使用MVVM从WPF中的TextBox搜索正确的DataGrid [英] Proper DataGrid search from TextBox in WPF using MVVM

查看:246
本文介绍了使用MVVM从WPF中的TextBox搜索正确的DataGrid的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是MVVM模式的新手,对于何时使用Code Behind有点困惑。我现在有一个非常简单的形式,包括一个TextBox和一个DataGrid。我想要的是能够使DataGrid根据TextBox更改其选定的项目。



我已经在Code Behind中完成了此操作,并且使用以下代码可以正常工作:

 code> 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中以文本框中的文本开头的Item,并允许用户按一个按钮来编辑所选项目。



在代码背后文件中有这个逻辑可以吗?或者我需要通过某种约束来做到这一点如果我应该通过查看模型绑定,任何方向将不胜感激。谢谢。

解决方案

如果您只想使用 TextBox 可以为 DataGrid AttatchedProperty 接受 TextBox 并为单元格创建另一个 AttatchedProperty 来指示您可以用于设置单元格样式中的属性。然后我们创建一个 IMultiValueConverter 来检查单元格值以匹配搜索 Text



这样,它可以在其他项目中重用,因为您只需要 AttachedProperties code>转换器



绑定 AttachedProperty SearchValue 到您的 TextBox 文本属性。

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

然后为 DataGridCell 创建一个样式并使用 IMultiValueConverter AttachedProperty IsTextMatch 创建Setter如果单元格文本与 SearchValue

 < Setter属性=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 code> IsTextMatch 属性使用触发器设置突出显示

 < Style.Triggers> 
< Trigger Property =local:DataGridTextSearch.IsTextMatchValue =True>
< Setter Property =BackgroundValue =Orange/>
< / Trigger>
< /Style.Triggers>



这是一个工作示例,显示了我的说法:)



代码:

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

私有字符串GetRandomText()
{
返回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;组; }
public string MyProperty2 {get;组; }
public string MyProperty3 {get;组; }
}

public static class DataGridTextSearch
{
//使用DependencyProperty作为SearchValue的后备库。这使得动画,样式,绑定等...
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);
}

//使用DependencyProperty作为IsTextMatch的后备存储。这使得动画,样式,绑定等...
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 ());
}
返回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 =MainWindowHeight =350Width =525Name =UI>

< StackPanel DataContext ={Binding ElementName = UI}>
< TextBox Name =SearchBox/>
< DataGrid x:Name =gridlocal: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.IsTextMatchValue =True>
< Setter Property =BackgroundValue =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>

然后更改触发器设置 IsSelected

 < Style.Triggers> 
< Trigger Property =local:DataGridTextSearch.IsTextMatchValue =True>
< Setter Property =IsSelectedValue =True/>
< / Trigger>
< /Style.Triggers>

应如下所示:

 < DataGrid x:Name =gridlocal: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.IsTextMatchValue =True>
< Setter Property =IsSelectedValue =True/>
< / Trigger>
< /Style.Triggers>
< / Style>
< /DataGrid.Resources>
< / DataGrid>

结果:




I am new to the MVVM pattern, and a little confused on when to use Code Behind. I have a very simple form right now, that includes one TextBox, and one DataGrid. What I would like is to be able to have the DataGrid change its selected item based on the TextBox.

I have done this in Code Behind and it works fine using the following code:

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 { }
    }
}

Now, I just want to highlight the Item in the Datagrid that starts with text in textbox, and allow the user to press a button to edit selected item.

Is it okay to have this logic in the Code Behind file? Or would I need to do this through some sort of binding? If I should do this through the View Model with Binding, any direction would be appreciated. Thank you.

解决方案

If you only want to highlight the cells with the text from the TextBox you could make an AttatchedProperty for the DataGrid to accept your search value from the TextBox and create another AttatchedProperty for the Cell to indicate a match that you can usee to set properties in the Cell style. Then we create a IMultiValueConverter to check the Cell value for a match to the search Text.

This way its reusable on other projects as you only need the AttachedProperties and Converter

Bind the AttachedProperty SearchValue to your TextBox Text property.

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

Then create a Style for DataGridCell and create a Setter for the AttachedProperty IsTextMatch using the IMultiValueConverter to return if the cells text matches the 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>

Then we can use the Cells attached IsTextMatch property to set a highlight using a Trigger

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

Here is a working example showing my rambilings :)

Code:

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>

Result:

Edit:

If you just want to select the row based on a single Column you can modify quite easily :).

Override the Style of DataGridRow instead of DataGridCell.

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

First pass in the property you want into the IMultiValueConverter this should be your DataContext

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

Then change the Trigger to set IsSelected on the Row

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

Should look like this:

 <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>

Result:

这篇关于使用MVVM从WPF中的TextBox搜索正确的DataGrid的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆