20

私はMVVMパターンに不慣れで、CodeBehindをいつ使用するかについて少し混乱しています。現在、1つのTextBoxと1つのDataGridを含む非常に単純なフォームがあります。私が欲しいのは、DataGridがTextBoxに基づいて選択されたアイテムを変更できるようにすることです。

私はこれをCodeBehindで実行しましたが、次のコードを使用すると正常に機能します。

private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
    for (int i = 0; i < dataGrid1.Items.Count; i++)
    {
        string cellContent = dtReferral.Rows[i][0].ToString();
        try
        {
            if (cellContent != null && cellContent.Substring(0, textBox1.Text.Length).Equals(textBox1.Text))
            {
                object item = dataGrid1.Items[i];
                dataGrid1.SelectedItem = item;
                dataGrid1.ScrollIntoView(item);
                //row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
                break;
            }
        }
        catch { }
    }
}

ここで、テキストボックスのテキストで始まるデータグリッド内のアイテムを強調表示し、ユーザーがボタンを押して選択したアイテムを編集できるようにします。

このロジックをCodeBehindファイルに含めても大丈夫ですか?それとも、ある種のバインディングを介してこれを行う必要がありますか?バインディング付きのビューモデルを介してこれを行う必要がある場合は、任意の方向をいただければ幸いです。ありがとうございました。

4

2 に答える 2

49

からのテキストでセルを強調表示するだけの場合は、TextBoxからの検索値を受け入れるAttatchedPropertyためのを作成し、スタイルのプロパティを設定するために使用できる一致を示すために別のを作成することができます。次に、を作成して、検索に一致する値を確認します。DataGridTextBoxAttatchedPropertyCellCellIMultiValueConverterCellText

AttachedPropertiesこのように、必要なのはとだけなので、他のプロジェクトで再利用できますConverter

をプロパティにバインドAttachedProperty SearchValueしますTextBox Text

 <DataGrid local:DataGridTextSearch.SearchValue="{Binding ElementName=SearchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}" 

次に、StyleforDataGridCellを作成しAttachedProperty IsTextMatchIMultiValueConverterセルのテキストがSearchValue

<Setter Property="local:DataGridTextSearch.IsTextMatch">
    <Setter.Value>
        <MultiBinding Converter="{StaticResource SearchValueConverter}">
            <Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
            <Binding RelativeSource="{RelativeSource Self}" Path="(local:DataGridTextSearch.SearchValue)" />
        </MultiBinding>
    </Setter.Value>
</Setter>

次に、Cells添付IsTextMatchプロパティを使用して、Trigger

<Style.Triggers>
    <Trigger Property="local:DataGridTextSearch.IsTextMatch" Value="True">
        <Setter Property="Background" Value="Orange" />
    </Trigger>
</Style.Triggers>

これが私のランビリングを示す実用的な例です:)

コード:

namespace WpfApplication17
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            for (int i = 0; i < 20; i++)
            {
                TestData.Add(new TestClass { MyProperty = GetRandomText(), MyProperty2 = GetRandomText(), MyProperty3 = GetRandomText() });
            }
        }

        private string GetRandomText()
        {
            return System.IO.Path.GetFileNameWithoutExtension(System.IO.Path.GetRandomFileName());
        }

        private ObservableCollection<TestClass> _testData = new ObservableCollection<TestClass>();
        public ObservableCollection<TestClass> TestData
        {
            get { return _testData; }
            set { _testData = value; }
        }
    }

    public class TestClass
    {
        public string MyProperty { get; set; }
        public string MyProperty2 { get; set; }
        public string MyProperty3 { get; set; }
    }

    public static class DataGridTextSearch
    {
        // Using a DependencyProperty as the backing store for SearchValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SearchValueProperty =
            DependencyProperty.RegisterAttached("SearchValue", typeof(string), typeof(DataGridTextSearch),
                new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Inherits));

        public static string GetSearchValue(DependencyObject obj)
        {
            return (string)obj.GetValue(SearchValueProperty);
        }

        public static void SetSearchValue(DependencyObject obj, string value)
        {
            obj.SetValue(SearchValueProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsTextMatch.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsTextMatchProperty =
            DependencyProperty.RegisterAttached("IsTextMatch", typeof(bool), typeof(DataGridTextSearch), new UIPropertyMetadata(false));

        public static bool GetIsTextMatch(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsTextMatchProperty);
        }

        public static void SetIsTextMatch(DependencyObject obj, bool value)
        {
            obj.SetValue(IsTextMatchProperty, value);
        }
    }

    public class SearchValueConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string cellText = values[0] == null ? string.Empty : values[0].ToString();
            string searchText = values[1] as string;

            if (!string.IsNullOrEmpty(searchText) && !string.IsNullOrEmpty(cellText))
            {
                return cellText.ToLower().StartsWith(searchText.ToLower());
            }
            return false;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
    }
}

Xaml:

<Window x:Class="WpfApplication17.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication17"
        Title="MainWindow" Height="350" Width="525" Name="UI">

    <StackPanel DataContext="{Binding ElementName=UI}">
        <TextBox Name="SearchBox" />
        <DataGrid x:Name="grid" local:DataGridTextSearch.SearchValue="{Binding ElementName=SearchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}" 
                  ItemsSource="{Binding TestData}" >
            <DataGrid.Resources>
                <local:SearchValueConverter x:Key="SearchValueConverter" />
                <Style TargetType="{x:Type DataGridCell}">
                    <Setter Property="local:DataGridTextSearch.IsTextMatch">
                        <Setter.Value>
                            <MultiBinding Converter="{StaticResource SearchValueConverter}">
                                <Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
                                <Binding RelativeSource="{RelativeSource Self}" Path="(local:DataGridTextSearch.SearchValue)" />
                            </MultiBinding>
                        </Setter.Value>
                    </Setter>
                    <Style.Triggers>
                        <Trigger Property="local:DataGridTextSearch.IsTextMatch" Value="True">
                            <Setter Property="Background" Value="Orange" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.Resources>
        </DataGrid>
    </StackPanel>
</Window>

結果:

ここに画像の説明を入力してください ここに画像の説明を入力してください

編集:

単一の列に基づいて行を選択したいだけの場合は、非常に簡単に変更できます:)。

DataGridRowの代わりにのスタイルをオーバーライドしDataGridCellます。

  <Style TargetType="{x:Type DataGridRow}">

あなたが望むプロパティの最初のパスはIMultiValueConverterこれがあなたのものでなければなりませんDataContext

<MultiBinding Converter="{StaticResource SearchValueConverter}">
    <Binding RelativeSource="{RelativeSource Self}" Path="DataContext.MyProperty" />
    <Binding RelativeSource="{RelativeSource Self}" Path="(local:DataGridTextSearch.SearchValue)" />
</MultiBinding>

次に、Triggerをに設定IsSelectedするように変更しますRow

<Style.Triggers>
    <Trigger Property="local:DataGridTextSearch.IsTextMatch" Value="True">
        <Setter Property="IsSelected" Value="True" />
    </Trigger>
</Style.Triggers>

次のようになります。

 <DataGrid x:Name="grid" local:DataGridTextSearch.SearchValue="{Binding ElementName=SearchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}" 
              ItemsSource="{Binding TestData}" >
        <DataGrid.Resources>
            <local:SearchValueConverter x:Key="SearchValueConverter" />
            <Style TargetType="{x:Type DataGridRow}">
                <Setter Property="local:DataGridTextSearch.IsTextMatch">
                    <Setter.Value>
                        <MultiBinding Converter="{StaticResource SearchValueConverter}">
                            <Binding RelativeSource="{RelativeSource Self}" Path="DataContext.MyProperty" />
                            <Binding RelativeSource="{RelativeSource Self}" Path="(local:DataGridTextSearch.SearchValue)" />
                        </MultiBinding>
                    </Setter.Value>
                </Setter>
                <Style.Triggers>
                    <Trigger Property="local:DataGridTextSearch.IsTextMatch" Value="True">
                        <Setter Property="IsSelected" Value="True" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </DataGrid.Resources>
    </DataGrid>

結果:

ここに画像の説明を入力してください

于 2013-03-18T02:48:26.293 に答える
1

私はかなり前からMVVMを使用していますが、厳密な方法ではなくガイドラインとして使用することを好みます。これは、MVVMパターンですべてを正確に行うことが常に実用的であるとは限らないためです。そうでない場合は、さらにそうです。あまりにも精通している。
自分に合ったMVVMの形式が見つかるまで、それをいじってみることをお勧めします。
コードがUIに関連している場合、MVVMのコードビハインドにコードを含めることはタブーではないと思います。
ScrollIntoViewはBindableプロパティではないため、それにバインドする場合は、バインドを間接的に処理するための依存関係プロパティを作成する必要があります。選択したアイテムの設定については、次のような方法で行うことができます。

意見:

<TextBox Height="23" Text={Binding Path=Selected, UpdateSourceTrigger=PropertyChanged} HorizontalAlignment="Left" Margin="90,147,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
<DataGrid AutoGenerateColumns="True" 
          ItemsSource="{Binding Path=ItemList}" 
          SelectedItem="{Binding Path=Selected}" >
</DataGrid>

ViewModel:

 private string _selected = "";
 public string Selected
 {
      get{ return _selected; }
      set
      {
            if(_selected == value) return;
            _selected = value;
            base.OnPropertyChanged("Selected");
      }
 }
于 2013-03-18T02:01:54.780 に答える