正如@Erno de Weerd 所说,您可以为此使用自定义 ValueConvertert。我能想到的另一种方法是继承 TextBox 并覆盖 TextProperty 元数据以对该属性的更改做出反应。以下示例包含两种方法:
XAML:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfApp="clr-namespace:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<wpfApp:MainWindowViewModel/>
</Window.DataContext>
<Window.Resources>
<wpfApp:TextToColorConverter x:Key="TextToColorConverter"/>
</Window.Resources>
<StackPanel >
<TextBox Text="{Binding SomeString, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding SomeString, Mode=OneWay, Converter={StaticResource TextToColorConverter}}"
Margin="0,0,0,20"/>
<wpfApp:MyCustomTextBox Text="{Binding SomeString, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</Window>
MainWindowViewModel 只包含绑定的属性并实现了 INotifyPropertyChanged:
public class MainWindowViewModel : INotifyPropertyChanged
{
private string _someString;
public string SomeString
{
get => _someString;
set
{
if (value == _someString) return;
_someString = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
第一种方法,IValueConverter:
public class TextToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var str = (string)value;
if (str == null) return new SolidColorBrush(Colors.Black);
return str.StartsWith("<qs>") && str.EndsWith("<qe>") ? new SolidColorBrush(Colors.Red) :
str.StartsWith("<as>") && str.EndsWith("<ae>") ? new SolidColorBrush(Colors.Green) :
new SolidColorBrush(Colors.Black);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
第二个,我们继承自TextBox:
public class MyCustomTextBox : TextBox
{
static MyCustomTextBox()
{
TextProperty.OverrideMetadata(typeof(MyCustomTextBox), new FrameworkPropertyMetadata(OnTextChanged));
}
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (MyCustomTextBox)d;
var str = (string)e.NewValue;
SolidColorBrush foreGround;
if (str == null)
{
foreGround = new SolidColorBrush(Colors.Black);
}
else
{
foreGround = str.StartsWith("<qs>") && str.EndsWith("<qe>") ? new SolidColorBrush(Colors.Red) :
str.StartsWith("<as>") && str.EndsWith("<ae>") ? new SolidColorBrush(Colors.Green) :
new SolidColorBrush(Colors.Black);
}
control.Foreground = foreGround;
}
}
我个人更喜欢第二种方法,创建自己的自定义控件允许我在任意多个视图中使用该控件,而无需在我的 XAML 中始终包含转换器的实例,此外,如果您需要一些更多的自定义行为,然后您只需将该行为添加到您的自定义控件中,而不是编写许多其他转换器。