c# - 在文本匹配 MVVM 上更改 TextBox BorderBrush 的颜色

标签 c# wpf mvvm triggers

所有,我创建了一个 DataGrid ,上面有一个搜索框。当用户键入并且文本位于 DataGrid 中时,匹配单元格的背景颜色为橙色。我已经做到了这一点,但现在(回顾)希望将搜索 TextBoxBorderBrush 更改为“红色”(如果文本不是 找到(否则默认)。该控件的 XAML 为

<UserControl x:Class="ResourceStudio.Views.ResourceControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels" 
             xmlns:dataAccess="clr-namespace:ResourceStudio.DataAccess" 
             xmlns:controls="clr-namespace:ResourceStudio.Controls"
             mc:Ignorable="d">
   <DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
      <TextBox DockPanel.Dock="Top" Name="searchBox" BorderBrush="#FF007ACC" BorderThickness="2">
         <TextBox.Resources>
            <Style TargetType="{x:Type TextBox}">
               <Style.Triggers>
                  <Trigger Property="dataAccess:DataGridTextSearch.IsTextMatch" Value="False">
                     <Setter Property="BorderBrush" Value="Red" />
                  </Trigger>
               </Style.Triggers>
            </Style>
         </TextBox.Resources>
      </TextBox>
      <Grid DockPanel.Dock="Top">
         <Border>
            <controls:ResourceDataGrid ItemsSource="{Binding Path=Resources}" 
                      dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox, 
                      Path=Text, UpdateSourceTrigger=PropertyChanged}">
               <controls:ResourceDataGrid.Columns>
                  <DataGridTextColumn Header="KeyIndex" Binding="{Binding KeyIndex}" IsReadOnly="True"/>
                  <DataGridTextColumn Header="FileName" Binding="{Binding FileName}" IsReadOnly="True"/>
                  <DataGridTextColumn Header="ResourceName" Binding="{Binding ResourceName}" IsReadOnly="False"/>
                  <controls:CollectionTextColumn Collection="ResourceStringList" Visibility="Collapsed"/>
               </controls:ResourceDataGrid.Columns>
               <controls:ResourceDataGrid.Resources>
                  <dataAccess:SearchValueConverter x:Key="searchValueConverter"/>
                  <Style TargetType="{x:Type DataGridCell}">
                     <Setter Property="dataAccess:DataGridTextSearch.IsTextMatch">
                        <Setter.Value>
                           <MultiBinding Converter="{StaticResource searchValueConverter}">
                              <Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
                              <Binding RelativeSource="{RelativeSource Self}" Path="(dataAccess:DataGridTextSearch.SearchValue)" />
                           </MultiBinding>
                        </Setter.Value>
                     </Setter>
                     <Style.Triggers>
                        <Trigger Property="dataAccess:DataGridTextSearch.IsTextMatch" Value="True">
                           <Setter Property="Background" Value="Orange" />
                        </Trigger>
                     </Style.Triggers>
                  </Style>
               </controls:ResourceDataGrid.Resources>
            </controls:ResourceDataGrid>
         </Border>
      </Grid>
   </DockPanel>
</UserControl>

我的 TextBox 的基本 Trigger 不执行任何操作。 如何使用与 DataGrid 相同的机制来更改 TextBox BorderBrush 的颜色?

感谢您的宝贵时间。


编辑。管理 DependencyPropertyIConverter 的类是

public static class DataGridTextSearch 
{
    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);
    }

    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, 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, CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}

最佳答案

好的,我找到了一种方法,通过为 DataGrid 创建一个新的 AttachedProperty IsAnyTextMatch

IMultiValueConverter 中,我们传入 DataGrid 并将新的 DataGrid IsAnyTextMatch 属性设置为 true(如果有)找到匹配项,如果您在 SearchBox 中键入,IsAnyTextMatch 将重置为 false

现在您可以在 TextBox 上创建一个 DataTrigger 并将其设置为 DataGrid IsAnyTextMatch 以设置 TextBox 边框颜色。

这可能不是最迷人的方法,但它不需要您再次迭代 DataGrid 集合来设置 TextBox 背景。

这是基于我的答案的示例:Proper DataGrid search from TextBox in WPF using MVVM

代码:

namespace WpfApplication10
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

        }

        public IEnumerable<TestClass> TestData
        {
            get
            {
                yield return new TestClass { Column1 = "Stack", Column2 = "Overflow" };
                yield return new TestClass { Column1 = "Is", Column2 = "An" };
                yield return new TestClass { Column1 = "Awesome", Column2 = "Resource" };
            }
        }
    }


    public static class DataGridTextSearch
    {
        public static readonly DependencyProperty SearchValueProperty =
            DependencyProperty.RegisterAttached("SearchValue", typeof(string), typeof(DataGridTextSearch),
                new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(PropertyChangedCallback)));

        private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DataGrid)
            {
                // serach text has changed, reset tag to false
                (d as DataGrid).SetValue(IsAnyTextMatchProperty, false);
            }
        }

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

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


        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 static readonly DependencyProperty IsAnyTextMatchProperty =
         DependencyProperty.RegisterAttached("IsAnyTextMatch", typeof(bool),
           typeof(DataGridTextSearch), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));

        public static bool GetIsAnyTextMatch(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsAnyTextMatchProperty);
        }

        public static void SetIsAnyTextMatch(DependencyObject obj, bool value)
        {
            obj.SetValue(IsAnyTextMatchProperty, value);
        }
    }

    public class SearchValueConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            string cellText = values[0] == null ? String.Empty : values[0].ToString();
            string searchText = values[1] as String;
            var datagrid = values[2] as DataGrid;
            bool returnvalue = false;
            if (!string.IsNullOrEmpty(searchText) &&
                !string.IsNullOrEmpty(cellText))
            {
                returnvalue = cellText.ToLower().StartsWith(searchText.ToLower());
            }

            // we found a match so mark DataGrid tag to true for use on TextBox
            if (returnvalue)
            {
                datagrid.SetValue(DataGridTextSearch.IsAnyTextMatchProperty, true);
            }
            return returnvalue;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
}

Xaml:

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

    <StackPanel DataContext="{Binding ElementName=UI}">
        <TextBox Name="SearchBox" BorderThickness="3" >
            <TextBox.Style>
                <Style TargetType="TextBox">
                    <Setter Property="BorderBrush" Value="Blue" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding (local:DataGridTextSearch.IsAnyTextMatch), ElementName=dataGrid}" Value="false">
                            <Setter Property="BorderBrush" Value="Red" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBox.Style>
        </TextBox>
        <DataGrid x:Name="dataGrid" 
                  local:DataGridTextSearch.SearchValue="{Binding ElementName=SearchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}" 
                  local:DataGridTextSearch.IsAnyTextMatch="False"
                  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)" />
                                <Binding ElementName="dataGrid" />
                                <!-- pass in datarid-->
                            </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>

结果:

enter image description here enter image description here

关于c# - 在文本匹配 MVVM 上更改 TextBox BorderBrush 的颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17054641/

相关文章:

c# - DllImport 或 LoadLibrary 以获得最佳性能

c# - MVVM SelectedItem.Property OnChanged MVVM SelectedItem.Property OnChanged

WPF,在后台工作人员中调用服务器方法

WPF 数据网格组合框数据绑定(bind)

c# - 引用分配是原子的,那么为什么需要 Interlocked.Exchange(ref Object, Object) 呢?

javascript - 如何从 UWP c# 上的 appdata 中的 html 接收 scriptNotify

c# - asp .net 和 asp .net core 有什么区别?

javascript - knockout 不更新 View 中的值

wpf - 使用 MVVM 将父窗口的事件绑定(bind)到 UserControl 内部处理程序

c# - 将 ErrorTemplate 添加到 MahApp 控件而不覆盖其默认样式