为什么OneWayToSource绑定会覆盖数据触发器?

本文关键字:数据 触发器 覆盖 OneWayToSource 绑定 为什么 | 更新日期: 2023-09-27 18:01:30

我有一个具有多个控件的WPF表单,并且我希望当且仅当这些控件上的各种条件为真时启用按钮('Assign')。一些条件包括测试文本框是否为空。

我最初通过将文本框的内容绑定到属性并在XAML中绑定按钮的IsEnabled属性来实现这一点:

<TextBox Name="NewName" Text="{Binding NewName}" />
(etc)
<Button Name="Assign" ... IsEnabled="{Binding Path=AssignEnabled}" />

与c# ViewModel中相应的方法:

public bool AssignEnabled
{
    get
    {
        return !string.IsNullOrWhiteSpace(this.NewName) && ... (etc)
    }
    set
    {
        ...
        this.NotifyPropertyChanged("AssignEnabled");
        ...
    }
}

问题是,这会导致按钮在焦点从相应的文本框中丢失时更新,而不是在文本更改时更新。我本可以在XAML中的每个文本框上使用TextChanged属性来调用代码,但这似乎过于复杂了。

为了解决这个问题,我删除了绑定并切换到DataTriggers,像这样:

<Button Name="Assign" ... >
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="IsEnabled" Value="True"/>
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding IsChecked, ElementName=NewNameOption}" Value="true" />
                        <Condition Binding="{Binding Text, ElementName=NewName}" Value="{x:Static sys:String.Empty}" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="IsEnabled" Value="False"/>
                </MultiDataTrigger>
                ...
                (more conditions here)
                ...
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

这工作得很好。唯一的缺点是,我以前编写的测试按钮的IsEnabled状态的单元测试不再可用(因为他们使用的ViewModel的AssignEnabled属性不再绑定到按钮)。

为了允许这些单元测试工作,我需要AssignEnabled属性来反映按钮的IsEnabled状态。我希望能够通过添加OneWayToSource绑定来解决这个问题,像这样:

<Button Name="Assign" ... IsEnabled="{Binding AssignEnabled, Mode=OneWayToSource}">

,属性改为:

public bool AssignEnabled { get; set; }

然而,似乎这个绑定,即使设置为OneWayToSource,覆盖了数据触发器,因为按钮的启用/禁用不再工作。

我知道还有其他选择,例如使用转换器或实现ICommand,但我宁愿保持简单,如果可能的话,并修复上述方法(或至少理解为什么它不起作用)。我怎样才能访问按钮的IsEnabled属性而不违反ViewModel范式或阻止DataTriggers工作?

为什么OneWayToSource绑定会覆盖数据触发器?

您可以保留第一个解决方案并为绑定设置UpdateSourceTrigger=PropertyChanged。这样,绑定将在文本变化时立即改变,而不仅仅是在焦点丢失时。顺便说一下,这个解决方案为您提供了更大的灵活性,因为您可以对字段执行更复杂的测试(例如测试电子邮件地址格式)。