私はMVVMパターンに不慣れで、コードビハインドをいつ使用するかについて少し混乱しています。現在、1つのTextBoxと1つのDataGridを含む非常に単純なフォームがあります。私が望むのは、DataGridがTextBoxに基づいて選択されたアイテムを変更できるようにすることです。
私はこれをコードビハインドで行い、次のコードを使用して正常に動作します。
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 { }
}
}
ここで、テキストボックス内のテキストで始まるDatagrid内のアイテムを強調表示し、ユーザーがボタンを押して選択したアイテムを編集できるようにします。
このロジックを分離コードファイルに含めることはできますか?それとも、何らかのバインドによってこれを行う必要がありますか?バインディング付きのビューモデルを使用してこれを行う必要がある場合は、任意の方向でいただければ幸いです。ありがとうございました。
TextBox
からのテキストでセルを強調表示するだけの場合、AttatchedProperty
のDataGrid
を作成してTextBox
から検索値を受け入れ、AttatchedProperty
の別のCell
を作成して、プロパティで設定できる一致を示すことができます。 Cell
スタイル。次に、IMultiValueConverter
を作成して、Cell
の値が検索Text
と一致するかどうかを確認します。
このように、AttachedProperties
とConverter
だけが必要なので、他のプロジェクトで再利用できます
AttachedProperty
SearchValue
をTextBox
Text
プロパティにバインドします。
<DataGrid local:DataGridTextSearch.SearchValue="{Binding ElementName=SearchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
次に、Style
のDataGridCell
を作成し、AttachedProperty
を使用してIsTextMatch
のセッターを作成し、IMultiValueConverter
を使用して、セルのテキストが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>
結果:
私はしばらくの間MVVMを静かに使用してきましたが、MVVMパターンですべてを正確に実行することが常に実用的であるとは限らないため、厳密な実践よりもガイドラインとしてatを使用することを好みます。それに慣れる。
あなたにぴったりの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");
}
}