使用绑定DataTrigger条件的Value属性

时间:2010-02-10 21:16:59

标签: .net wpf data-binding triggers

我正在研究WPF应用程序并且正在努力处理数据触发器。我想将触发条件的值绑定到我的某个对象:

<DataTrigger Binding="{Binding Foo}" 
             Value="{Binding ElementName=AnotherElement, Path=Bar}">..

但是,我不被允许,因为似乎不可能对Value属性使用绑定。是吗?我能以某种方式实现吗?我收到以下错误:

  

无法在“DataTrigger”类型的“Value”属性上设置“绑定”。 '绑定'只能在DependencyObject的DependencyProperty上设置。

4 个答案:

答案 0 :(得分:37)

不,这是不可能的。正如错误消息所述,只有依赖项属性可以是WPF绑定的目标,而DataTrigger.Value不是依赖项属性。所以你需要指定一个实际值。

解决方法是使用MultiBinding,其子Bindings是您要比较的两个绑定,IMultiValueConverter如果两个输入相等则返回true,如果它们不相等则返回false。然后,DataTrigger可以使用MultiBinding,值为True。

答案 1 :(得分:6)

这里是IMultiValueConverter转换器的示例。

在此XAML中,有三个复选框。前两个绑定到Foo和Bar属性(均为布尔值)。第三个使用IMultiValueConverter的多重绑定。当Foo和Bar具有相同的值时进行检查。

<!-- It's expected that the DataContext of this StackPanel has boolean Bar and Foo properties.. -->
<StackPanel Orientation="Vertical">
    <StackPanel.Resources>
        <!-- local contains the MultiValueEqualityConverter class implementation -->
        <local:MultiValueEqualityConverter x:Key="multiValueEqualityConverter"/>
    </StackPanel.Resources>

    <CheckBox IsChecked="{Binding Foo}">Foo</CheckBox>
    <CheckBox IsChecked="{Binding Bar}">Bar</CheckBox>

    <CheckBox IsEnabled="False" Content="Are the same">
        <CheckBox.Style>
            <Style TargetType="CheckBox">
                <Style.Setters>
                    <Setter Property="IsChecked" Value="False"/>
                </Style.Setters>
                <Style.Triggers>
                    <DataTrigger Value="True">
                        <DataTrigger.Binding>
                            <MultiBinding Converter="{StaticResource multiValueEqualityConverter}">
                                <Binding RelativeSource="{RelativeSource self}" Path="DataContext.Foo" Mode="OneWay" />
                                <Binding RelativeSource="{RelativeSource self}" Path="DataContext.Bar" Mode="OneWay"/>
                            </MultiBinding>
                        </DataTrigger.Binding>
                        <Setter Property="IsChecked" Value="True" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </CheckBox.Style>
    </CheckBox>
</StackPanel>

用于单向绑定的简单IMultiValueConverter实现:

public class MultiValueEqualityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values?.All(o => o?.Equals(values[0]) == true) == true || values?.All(o => o == null) == true;
    }

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

答案 2 :(得分:1)

我使用MVVM。由于我已经多次返回此答案,所以值得一提的是,每次我得到的结果都是相同的:

  

为每个项目创建一个模型,而不是对其进行比较。

例如,我通常在ItemsControl.DataTemplate中有一堆行。我尝试通过与动态IsEnabled进行比较来使用DataTrigger来设置Value={Binding}(或其他方式)。

就在那时,我的代码破败不堪,然后我去了SO,然后到了这里。

然后我几乎肯定会在ViewModel中维护一个行模型的列表,这些模型处理它们自己的IsEnabled并相应地通知UI。

我将它们用于ItemsControl.Source,然后想知道为什么我不只是这样做。

答案 3 :(得分:0)

DataTrigger的Value属性不是可以绑定的DependencyProperty。因此,我们RegisterAttached的依赖项属性可以在每次设置附加的依赖项属性值时绑定并设置DataTrigger的Value属性的值。

这里是一个示例DataTriggerAssists

public class DataTriggerAssists
{
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.RegisterAttached(
            "Value",
            typeof(object),
            typeof(DataTriggerAssists),
            new FrameworkPropertyMetadata(null, OnValueChanged));

    public static object GetValue(DependencyObject d)
    {
        return d.GetValue(ValueProperty);
    }

    public static void SetValue(DependencyObject d, object value)
    {
        d.SetValue(ValueProperty, value);
    }

    public static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
    {
        if (!(d is DataTrigger trigger))
            return;

        trigger.Value = args.NewValue;
    }
}

使用as类的名称空间声明一个名为DataTriggerAssists的前缀。

然后您可以像这样使用

<DataTrigger Binding="{Binding Foo}" 
             as:DataTriggerAssists.Value="{Binding ElementName=AnotherElement, Path=Bar}">..