我正在研究WPF应用程序并且正在努力处理数据触发器。我想将触发条件的值绑定到我的某个对象:
<DataTrigger Binding="{Binding Foo}"
Value="{Binding ElementName=AnotherElement, Path=Bar}">..
但是,我不被允许,因为似乎不可能对Value属性使用绑定。是吗?我能以某种方式实现吗?我收到以下错误:
无法在“DataTrigger”类型的“Value”属性上设置“绑定”。 '绑定'只能在DependencyObject的DependencyProperty上设置。
答案 0 :(得分:37)
不,这是不可能的。正如错误消息所述,只有依赖项属性可以是WPF绑定的目标,而DataTrigger.Value不是依赖项属性。所以你需要指定一个实际值。
解决方法是使用MultiBinding,其子Bindings是您要比较的两个绑定,IMultiValueConverter如果两个输入相等则返回true,如果它们不相等则返回false。然后,DataTrigger可以使用MultiBinding,值为True。
答案 1 :(得分:6)
这里是IMultiValueConverter
转换器的示例。
<!-- 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}">..