.net 对 DataTrigger 条件的 Value 属性使用绑定
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2240421/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using binding for the Value property of DataTrigger condition
提问by stiank81
I'm working on a WPF application and struggling with a data trigger. I'd like to bind the value of the trigger condition to some object I have:
我正在开发一个 WPF 应用程序,并且正在为数据触发器苦苦挣扎。我想将触发条件的值绑定到我拥有的某个对象:
<DataTrigger Binding="{Binding Foo}"
Value="{Binding ElementName=AnotherElement, Path=Bar}">..
However, I'm not allowed as it doesn't seem to be possible to use bindings for the Value property. Is it? Can I achieve this somehow? I get the following error:
但是,我不被允许,因为似乎不可能对 Value 属性使用绑定。是吗?我能以某种方式实现这一目标吗?我收到以下错误:
A 'Binding' cannot be set on the 'Value' property of type 'DataTrigger'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
无法在“DataTrigger”类型的“Value”属性上设置“Binding”。只能在 DependencyObject 的 DependencyProperty 上设置“绑定”。
回答by itowlson
No, it is not possible. As the error message says, only dependency properties can be targets of WPF bindings, and DataTrigger.Value is not a dependency property. So you will need to assign an actual value.
不,这是不可能的。正如错误消息所说,只有依赖属性才能成为 WPF 绑定的目标,而 DataTrigger.Value 不是依赖属性。因此,您需要分配一个实际值。
The workaround is to use a MultiBinding whose child Bindings are the two bindings you want to compare, with an IMultiValueConverter which returns true if the two inputs are equal and false if they are unequal. The DataTrigger can then use that MultiBinding, and a Value of True.
解决方法是使用 MultiBinding,其子 Bindings 是您要比较的两个绑定,并使用 IMultiValueConverter,如果两个输入相等,则返回 true,如果它们不相等,则返回 false。然后,DataTrigger 可以使用该 MultiBinding 和 True 值。
回答by chviLadislav
Here is an example with the IMultiValueConverterconverter.
这是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>
Simple IMultiValueConverterimplementation for one way binding:
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();
}
}
回答by Ben
I use MVVM. Since I've returned to this answer quite a few times, it's worth mentioning that each time I end up with the same result:
我使用 MVVM。由于我已经多次返回这个答案,值得一提的是,每次我都得到相同的结果:
Make a model for each item rather than comparing it.
为每个项目建立一个模型,而不是比较它。
For example, I typically have a stack of rows in an ItemsControl.DataTemplate. I try to set IsEnabled(or something) using a DataTriggerby comparing to a dynamic Value={Binding}.
例如,我通常在ItemsControl.DataTemplate. 我尝试设置IsEnabled(或东西)使用DataTrigger通过比较动态Value={Binding}。
Right about then, my code belly flops, and I head to SO, and end up here.
就在那时,我的代码失败了,我前往 SO,最后到了这里。
Almost without fail, I then decide to maintain a list of row models in the ViewModel, which handle their own IsEnabledand notify the UI accordingly.
几乎没有失败,然后我决定在 ViewModel 中维护一个行模型列表,它们处理自己的IsEnabled并相应地通知 UI。
I use them for the ItemsControl.Source, then wonder why I didn't just do that to begin with.
我将它们用于ItemsControl.Source,然后想知道为什么我一开始不这样做。
回答by RareChicken
The Value property of the DataTrigger is not a DependencyPropertythat can be bind. Therefore, we RegisterAttacheda dependency property that can bind and set the value of DataTrigger's Value property each time the attached dependency property value is set.
DataTrigger 的 Value 属性不是DependencyProperty可以绑定的。因此,我们RegisterAttached有一个依赖属性,可以在每次设置附加的依赖属性值时绑定和设置 DataTrigger 的 Value 属性的值。
Here is an example DataTriggerAssistsclass
这是一个示例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)
trigger.Value = args.NewValue;
}
}
Declare a prefix named aswith the namespace of the DataTriggerAssistsclass.
声明一个以类as的命名空间命名的前缀DataTriggerAssists。
Then you can use like this.
然后就可以这样使用了。
<DataTrigger Binding="{Binding Foo}"
as:DataTriggerAssists.Value="{Binding ElementName=AnotherElement, Path=Bar}">..

