你能暂时 disable/override 控制 WPF 中的模板触发器吗?

Can you temporarily disable/override Control Template Triggers in WPF?

如果我在其中输入无效文本,我正在设置 TextBoxBorderBrush:

if (!Regex.IsMatch(txtAddName.Text, @"[^A-Za-z0-9|()& ]"))
{
    txtAddName.BorderBrush = regularBrush;
}
else
{
    txtAddName.BorderBrush = errorBrush;
}

然而,我设置的 BorderBrushControl Template Triggers 覆盖:

<ControlTemplate.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
        <Setter TargetName="Border" Property="BorderBrush" Value="#505F69"/>
    </Trigger>
    <Trigger Property="IsFocused" Value="True">
        <Setter TargetName="Border" Property="BorderBrush" Value="#505F69"/>
    </Trigger>
</ControlTemplate.Triggers>

所以我需要以某种方式禁用它们,直到我失去 TextBox 的焦点或文本有效。我考虑过用它制作一个 Multitrigger 并设置第二个条件,但我无法想象这个条件应该是什么样子。有没有一种简单的方法可以做到这一点?还没有找到任何有用的东西。

有没有这样的可能:

在代码设置中 bool:

bool isTextInvalid;
if (!Regex.IsMatch(txtAddName.Text, @"[^A-Za-z0-9|()& ]"))
{
    txtAddName.BorderBrush = regularBrush;
    isTextInvalid = false;
}
else
{
    txtAddName.BorderBrush = errorBrush;
    isTextInvalid = true;
}

然后在 XAML 中访问这个 bool ?

<ControlTemplate.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="isTextInvalid" Value="False"/>   <-- The bool from code
                <Condition Property="IsFocused" Value="True"/>
            </MultiTrigger.Conditions>
            <MultiTrigger.Setters>
                <Setter TargetName="Border" Property="BorderBrush" Value="#505F69"/>
            </MultiTrigger.Setters>
        </MultiTrigger>
    </ControlTemplate.Triggers>

您可以使用 Tag 属性 来存储 isTextInvalid 的当前值:

txtAddName.BorderBrush = regularBrush;
txtAddName.Tag = false;

XAML:

<MultiTrigger xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <MultiTrigger.Conditions>
        <Condition Property="Tag">
            <Condition.Value>
                <sys:Boolean>false</sys:Boolean>
            </Condition.Value>
        </Condition>
        <Condition Property="IsFocused" Value="True"/>
    </MultiTrigger.Conditions>
    <MultiTrigger.Setters>
        <Setter TargetName="Border" Property="BorderBrush" Value="#505F69"/>
    </MultiTrigger.Setters>
</MultiTrigger>

如果您的 TextBox 的文本有效性优先于其他触发器,您可以使用 ValueConverter、带触发器(无 ControlTemplate 触发器)且无代码隐藏的 Style 来完成这一切。

这是一个工作示例:

MainWindow.xaml:

<Window.Resources>
    <local:MyRegexValueConverter x:Key="MyRegexConverter"/>
</Window.Resources>
<Grid>
    <TextBox x:Name="txtAddName" Width="300" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center">
        <TextBox.Style>
            <Style TargetType="{x:Type TextBox}">
                <Setter Property="SnapsToDevicePixels" Value="True" />
                <Setter Property="OverridesDefaultStyle" Value="True" />
                <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
                <Setter Property="FocusVisualStyle" Value="{x:Null}" />
                <Setter Property="MinWidth" Value="120" />
                <Setter Property="MinHeight" Value="20" />
                <Setter Property="AllowDrop" Value="true" />
                <Setter Property="BorderBrush" Value="LightGray"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TextBox}">
                            <Border Name="Border" CornerRadius="2" Padding="2" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}">
                                <ScrollViewer Margin="0" x:Name="PART_ContentHost" />
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderBrush" Value="#505F69"/>
                    </Trigger>
                    <Trigger Property="IsFocused" Value="True">
                        <Setter Property="BorderBrush" Value="#505F69"/>
                    </Trigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=Text,Converter={StaticResource MyRegexConverter}}" Value="True"
                        <Setter Property="BorderBrush" Value="#FF0000"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>
</Grid>

MainWindow.xaml.cs:

public MainWindow()
{
    InitializeComponent();
    this.DataContext = this;
}

MyRegexValueConverter.cs:

public class MyRegexValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var textValue = System.Convert.ToString(value);

        // Returns true if text is invalid, otherwise false
        return Regex.IsMatch(textValue, @"[^A-Za-z0-9|()& ]");
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

使用 IsMouseOver 或 IsFocused 的示例输出:

带有无效文本的示例输出:

我在一个新的 WPF 项目中对此进行了测试,它可以正常工作。希望你觉得它有用。