WPF相对源更新源触发器=属性更改不起作用

bzzcjhmw  于 2022-12-27  发布在  其他
关注(0)|答案(1)|浏览(271)

我使用的是DataTrigger

<Window x:Class="_11_5_Style_demo4_DataTrigger.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:local="clr-namespace:_11_5_Style_demo4_DataTrigger"
        mc:Ignorable="d"
        Title="MainWindow" Height="130" Width="300">
    <Window.Resources>
        <local:L2BConverter x:Key="cvtr"/>
        
        <!--TextBox DataTrigger-->
        <Style TargetType="TextBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding 
                    RelativeSource={x:Static RelativeSource.Self}, 
                    Path=Text.Length, 
                    Converter={StaticResource cvtr},
                    UpdateSourceTrigger=PropertyChanged}"
                             Value="false">
                    <DataTrigger.Setters>
                        <Setter Property="BorderBrush" Value="Red"/>
                        <Setter Property="BorderThickness" Value="1"/>
                    </DataTrigger.Setters>
                </DataTrigger>
            </Style.Triggers>
        </Style>
        
    </Window.Resources>
    
    <StackPanel>
        <TextBox Margin="5"/>
        <TextBox Margin="5,0"/>
        <TextBox Margin="5"/>
    </StackPanel>
</Window>

我预计TextBox在输入超过6个字符时会有红色边框,而UpdateSourceTrigger=PropertyChangedTextBox中超过6个字符时就不起作用了。它只在失去焦点时更新。
下面是Converter

public class L2BConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int textLength = (int)value;
        return textLength < 6 ? true : false;
    }

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

我搜索了一下,但是没有发现相关的问题。谁能解释一下为什么这个不起作用,我用的不对吗?

cuxqih21

cuxqih211#

您的触发器工作正常,但您对其工作结果的期望不正确。触发器正确设置了边框画笔,但问题是当TextBox具有焦点时,边框的颜色不是从TextBox获取的。BorderBrush画笔,而是从TextBox模板常量中获取的。而且你不能用触发器来改变它。您需要更改TextBox本身的模板或应用其他方法来解决问题。
您可以确保触发器正常工作,例如,通过更改帧粗细:

<Style TargetType="TextBox">
    <Style.Triggers>
        <DataTrigger Binding="{Binding
                                RelativeSource={x:Static RelativeSource.Self},
                                Path=Text.Length,
                                Converter={StaticResource cvtr}}"
                        Value="false">
            <DataTrigger.Setters>
                <Setter Property="BorderBrush" Value="Red"/>
                <Setter Property="BorderThickness" Value="10"/>
            </DataTrigger.Setters>
        </DataTrigger>
    </Style.Triggers>
</Style>

另一种实现这种验证的方法是使用ValidationRule。但是它只能在你没有的绑定中使用。你可以使用一点“巫毒魔法”来实现这一点:

public class LengthValidate : ValidationRule
{
    public LengthValidate() :base(ValidationStep.UpdatedValue, true) { }
    public int LengthLimit { get; set; }
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        int limit = LengthLimit;
        if(value is BindingExpression expression)
        {
            value = expression.GetSourceValue();
        }
        if (value is not string text)
        {
            text= value?.ToString()?? string.Empty;
        }
        return text.Length <= limit
            ? ValidationResult.ValidResult
            : new ValidationResult(false, $"String length exceeds limit={limit}.");
    }
}

使用the BindingExpressionHelper class中的GetSourceValue方法。
使用此规则设置样式:

<Style TargetType="TextBox">
    <Setter Property="Tag">
        <Setter.Value>
            <Binding Path="Text" RelativeSource="{RelativeSource Self}">
                <Binding.ValidationRules>
                    <local:LengthValidate LengthLimit="6"/>
                </Binding.ValidationRules>
            </Binding>
        </Setter.Value>
    </Setter>
</Style>

相关问题