【问题标题】:Proper DataGrid search from TextBox in WPF using MVVM使用 MVVM 从 WPF 中的 TextBox 进行正确的 DataGrid 搜索
【发布时间】: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 中以文本框中的文本开头的项目,并允许用户按下按钮来编辑所选项目。

可以在代码隐藏文件中包含此逻辑吗?还是我需要通过某种绑定来做到这一点?如果我应该通过带有绑定的视图模型来做到这一点,任何方向都将不胜感激。谢谢。

【问题讨论】:

    标签: c# wpf search mvvm datagrid


    【解决方案1】:

    如果您只想用TextBox 中的文本突出显示单元格,您可以为DataGrid 创建一个AttatchedProperty,以接受来自TextBox 的搜索值,并为@ 创建另一个AttatchedProperty 987654329@ 表示可用于设置Cell 样式中的属性的匹配项。然后我们创建一个IMultiValueConverter 来检查Cell 值是否与搜索Text 匹配。

    这种方式可以在其他项目中重复使用,因为您只需要 AttachedPropertiesConverter

    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");
          }
     }
    

    【讨论】:

      猜你喜欢
      • 2017-08-06
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 2010-12-24
      • 2013-08-03
      • 1970-01-01
      • 2018-05-16
      • 2021-07-17
      相关资源
      最近更新 更多