使用 MVVM 从 WPF 中的 TextBox 进行正确的 DataGrid 搜索
Posted
技术标签:
【中文标题】使用 MVVM 从 WPF 中的 TextBox 进行正确的 DataGrid 搜索【英文标题】:Proper DataGrid search from TextBox in WPF using MVVM 【发布时间】:2013-03-06 05:48:48 【问题描述】:我是 MVVM 模式的新手,对何时使用 Code Behind 有点困惑。我现在有一个非常简单的表单,其中包括一个 TextBox 和一个 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 中以文本框中的文本开头的项目,并允许用户按下按钮来编辑所选项目。
可以在代码隐藏文件中包含此逻辑吗?还是我需要通过某种绑定来做到这一点?如果我应该通过带有绑定的视图模型来做到这一点,任何方向都将不胜感激。谢谢。
【问题讨论】:
【参考方案1】:如果您只想用TextBox
中的文本突出显示单元格,您可以为DataGrid
创建一个AttatchedProperty
,以接受来自TextBox
的搜索值,并为@ 创建另一个AttatchedProperty
987654329@ 表示可用于设置Cell
样式中的属性的匹配项。然后我们创建一个IMultiValueConverter
来检查Cell
值是否与搜索Text
匹配。
这种方式可以在其他项目中重复使用,因为您只需要 AttachedProperties
和 Converter
将AttachedProperty
SearchValue
绑定到您的TextBox
Text
属性。
<DataGrid local:DataGridTextSearch.SearchValue="Binding ElementName=SearchBox, Path=Text, UpdateSourceTrigger=PropertyChanged"
然后为DataGridCell
创建一个Style
并为AttachedProperty
创建一个Setter 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
更改为在Row
上设置IsSelected
<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>
结果:
【讨论】:
哇,感谢您为此所做的所有工作。老实说,我要做的就是根据第一列中的文本选择整行。我可以为此调整您的代码吗? 我添加了一个编辑,显示如何修改以做你需要的,它很容易改变:) @sa_ddam213 感谢您的回答。这就是我喜欢这个网站的原因。我们有很多事情可以尝试。 @sa_ddam213 是否可以将搜索到的项目滚动到视图中 我不能在这里回答,但如果你是一个新问题,我可以告诉你如何:)【参考方案2】:我使用 MVVM 已经有一段时间了,我仍然更喜欢将其用作指导而不是严格的实践,部分原因是完全按照 MVVM 模式做所有事情并不总是可行的,如果您对它不太熟悉。我建议您只是玩弄它,直到您设法找到适合您的 MVVM 形式。 如果代码与 UI 相关,我不认为在 MVVM 的代码中包含代码是禁忌。 ScrollIntoView 不是可绑定属性,因此如果要绑定到它,则必须创建依赖项间接处理绑定的属性。至于设置所选项目,您可以通过以下方式完成:
查看:
<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>
视图模型:
private string _selected = "";
public string Selected
get return _selected;
set
if(_selected == value) return;
_selected = value;
base.OnPropertyChanged("Selected");
【讨论】:
以上是关于使用 MVVM 从 WPF 中的 TextBox 进行正确的 DataGrid 搜索的主要内容,如果未能解决你的问题,请参考以下文章
WPF MVVM - 如何绑定自定义控件->ToggleButton.IsChecked 到 View->TextBox.Text
MVVM DEVDataColumn中的TextBox与ComboBox的并存
WPF MVVM 架构 Step By Step(把actions从view model解耦)
WPF MVVM模式,有两个ListBox和一个TxtBox,选任一个ListBox的Item ,就显示在TextBox上。请帮帮高手。。