我有以下Multibinding:
<Grid.Visibility>
<MultiBinding Converter="{StaticResource MyMultiValueConverter}" Mode="TwoWay">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="MyVisibilityDependencyProperty" Mode="TwoWay"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="MyBoolProperty" Mode="TwoWay"/>
</MultiBinding>
</Grid.Visibility>
MyVisibilityDependencyProperty是一个依赖项属性。 MyBoolProperty是一个普通的属性。 MyMultiValueConverter的实现是重要的事情:
public class MyMultiValueConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//Not interesting
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { value, Binding.DoNothing};
}
}
现在的情景:我确实这么做了。触发ConvertBack-Method的调用,这意味着我在那里遇到了一个断点。之后我在MyVisibilityDependencyProperty的OnPropertyChangedCallback中找到了一个断点。在那里我可以看到MyVisibilityDependencyProperty的新值是ConvertBack-Method中设置的值。
现在我不明白的问题。我将ConvertBack-Method的实现更改为:
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { value, DependencyProperty.UnsetValue};
}
现在我遵循完全相同的情况。我做的很好。触发ConvertBack-Method的调用,这意味着我在那里遇到了一个断点。之后没有任何反应。未调用OnPropertyChangedCallback,并且不更新MyVisibilityDependencyProperty。为什么呢?
似乎如果数组中的一个值是DependencyProperty.UnsetValue,则停止所有值的传播。不仅是该值,还包括数组中的所有值。这受以下行为支持:
return new[] { Binding.DoNothing, false };
这导致调用MyBoolProperty的setter。
return new[] { DependencyProperty.UnsetValue, false };
这不会调用MyBoolProperty的setter。
我在文档中找不到任何解释的暗示,在我看来这没有意义。
答案 0 :(得分:8)
我在文档中找不到任何解释提示,但在我看来这没有任何意义。
我不记得曾在文档中看过它,但您的观察是正确的:
如果IMultiValueConverter.ConvertBack
的结果中的任何元素为UnsetValue
,则整套建议值将被拒绝,即转化失败,并且没有任何子绑定更新其源值。
相关代码可在MultiBindingExpression
课程中找到。以下是摘录摘录。
internal override object ConvertProposedValue(object value)
{
object result;
bool success = ConvertProposedValueImpl(value, out result);
{
result = DependencyProperty.UnsetValue;
...
}
return result;
}
private bool ConvertProposedValueImpl(object value, out object result)
{
result = GetValuesForChildBindings(value);
object[] values = (object[])result;
int count = MutableBindingExpressions.Count;
bool success = true;
// use the smaller count
if (values.Length < count)
count = values.Length;
for (int i = 0; i < count; ++i)
{
value = values[i];
...
if (value == DependencyProperty.UnsetValue)
success = false; // if any element is UnsetValue, conversion fails
values[i] = value;
}
result = values;
return success;
}
至于它是否有意义,我认为确实如此。结果数组中的值DoNothing
表示应跳过相应的子绑定,即不应更新其源值。实际上,这提供了部分更新的机制。如果您考虑一下,我们关心的唯一场景是:
正常行为提供(1),DoNothing
的使用可以满足(2)。使用UnsetValue
表示完全失败是有道理的。这也与单值转换器的含义一致:UnsetValue
表示转换失败。唯一的区别是ConvertBack
会返回object[]
,因此您无法直接返回UnsetValue
。但是,您可以返回一个仅包含 UnsetValue
的数组:由于它的存在意味着整个结果被抛出,因此数组长度实际上不必与子绑定的数量相匹配。
答案 1 :(得分:2)
前段时间我有一个类似的问题[Demultiplexing using IMultiValueConverter]
对我有用的是“延迟”DependencyProperty.UnsetValue
的分配:由于MultiBinding
有点是Bindings的“集合”,因此您可以为每个参与者分配IValueConverter
1 -1绑定如下:
(1)XAML-Markup:为所涉及的1:1绑定引入转换器
<Grid.Visibility>
<MultiBinding Converter="{StaticResource MyMultiValueConverter}" Mode="TwoWay">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="MyVisibilityDependencyProperty" Mode="TwoWay" />
<Binding Converter="UnsetValueConverter" RelativeSource="{RelativeSource TemplatedParent}" Path="MyBoolProperty" Mode="TwoWay"/>
</MultiBinding>
</Grid.Visibility>
(注意第二个绑定中引入的Converter="UnsetValueConverter"
)
(2)实现MyMultiValueConverter:创建所提供元素的副本
public class MyMultiValueConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//Not interesting
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { value, value };
}
}
(3)实现in(1)引入的UnsetValueConverter
public class UnsetValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
这样处理会延迟到更新值发布之前
是的,这不是你问题的答案,但Mike S.在解释它方面做得很好,并尝试提供通用的解决方案
答案 2 :(得分:1)
根据MSDN:
UnsetValue是一个标记值,用于场景,其中WPF属性系统无法确定请求的DependencyProperty值。使用UnsetValue而不是null,因为null可以是有效的属性值,也可以是有效的(经常使用的)DefaultValue。
事实上,您无法将DependencyProperty
设置为UnsetValue
,您可以将其与之进行比较。 设置为UnsetValue没有效果,您可以自己试试。
答案 3 :(得分:-3)
试试这个:
将源值转换为绑定目标的值。数据绑定引擎在将值从源绑定传播到绑定目标时调用此方法。
///param name="values"> The array of values taht the source bindings in the<see cref="T:System.Windows.Data.MultiBinding"/>produces.The value <see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the source binding has no value to provide for conversion.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>
/// A converted value.
/// If the method returns null, the valid null value is used.
/// A return value of <see cref="T:System.Windows.DependencyProperty"/>.<see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the converter did not produce a value, and that the binding will use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue"/> if it is available, or else will use the default value.
/// A return value of <see cref="T:System.Windows.Data.Binding"/>.<see cref="F:System.Windows.Data.Binding.DoNothing"/> indicates that the binding does not transfer the value or use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue"/> or the default value.
/// </returns>
public object ConvertBack( object[] values, Type targetType, object parameter, System.Globalization.CultureInfo clture )
{
if( parameter == null )
{ return null;}
return String.Format( parameter.ToString(), values );
}