C# 当一个转换的值在未设置的值中时,使用convertback的多重绑定不起作用
我有以下多重绑定:C# 当一个转换的值在未设置的值中时,使用convertback的多重绑定不起作用,c#,wpf,binding,unset,C#,Wpf,Binding,Unset,我有以下多重绑定: <Grid.Visibility> <MultiBinding Converter="{StaticResource MyMultiValueConverter}" Mode="TwoWay"> <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="MyVisibilityDependencyProperty" Mode="TwoWay"/>
<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>
现在的场景是:我做smth。这会触发对ConvertBack方法的调用,这意味着我遇到了一个断点。之后,我在MyVisibilityDependencyProperty的OnPropertyChangedCallback中遇到了一个断点。在这里,我可以看到MyVisibilityDependencyProperty的新值是在ConvertBack方法中设置的值
现在我不明白这个问题。我将ConvertBack方法的实现更改为:
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { value, DependencyProperty.UnsetValue};
}
现在我遵循完全相同的场景。我做smth。这会触发对ConvertBack方法的调用,这意味着我遇到了一个断点。之后什么也没发生。不会调用OnPropertyChangedCallback,并且不会更新MyVisibilityDependencyProperty。为什么?
如果数组中的一个值是DependencyProperty.UnsetValue,则所有值的传播都将停止。不仅针对该值,还针对数组中的所有值。以下行为支持这一点:
return new[] { Binding.DoNothing, false };
这将导致调用MyBoolProperty的setter
return new[] { DependencyProperty.UnsetValue, false };
这不会调用MyBoolProperty的setter
我在文档中找不到任何解释的线索,在我看来,这是没有意义的 根据MSDN:
UnsetValue是一个sentinel值,用于WPF属性系统无法确定请求的DependencyProperty值的场景。使用UnsetValue而不是null,因为null可以是有效的属性值,也可以是有效的(经常使用的)DefaultValue
事实上,您不能将dependencProperty
设置为UnsetValue
,您只需与它进行比较即可设置为未设置的值没有效果,您可以自己尝试。尝试以下操作:
将源值转换为绑定目标的值。数据绑定引擎在将值从源绑定传播到绑定目标时调用此方法
///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 );
}
///param name=“values”>产品中源绑定的值数组。该值表示源绑定没有可供转换的值。
///绑定目标属性的类型。
///要使用的转换器参数。
///要在转换器中使用的区域性。
///
///转换后的值。
///如果该方法返回null,则使用有效的null值。
///返回值为。指示转换器未生成值,并且绑定将使用(如果可用),否则将使用默认值。
///返回值为。指示绑定不传输值或不使用或默认值。
///
公共对象转换回(对象[]值,类型targetType,对象参数,System.Globalization.CultureInfo-clture)
{
if(参数==null)
{返回null;}
返回String.Format(参数.ToString(),值);
}
我在文档中找不到任何解释的线索,在我看来,这是没有意义的
我不记得在文档中见过它,但您的观察是正确的:
如果IMultiValueConverter.ConvertBack
结果中的任何元素是未设置值
,则整个建议值集将被拒绝,即转换失败,并且没有子绑定更新其源值
相关代码可以在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;
}
内部覆盖对象ConvertedValue(对象值)
{
客观结果;
bool success=ConvertProposedValueImpl(值,输出结果);
{
结果=DependencyProperty.Unset值;
...
}
返回结果;
}
private bool ConvertedValueImpl(对象值,输出对象结果)
{
结果=GetValuesForChildBindings(值);
对象[]值=(对象[])结果;
int count=MutableBindingExpressions.count;
布尔成功=真;
//使用较小的计数
如果(值.长度<计数)
计数=值。长度;
对于(int i=0;i
至于它是否有意义,我认为是的。结果数组中的DoNothing
值表示应跳过相应的子绑定,即不应更新其源值。这实际上为部分更新提供了一种机制。如果您仔细想想,我们关心的唯一场景是:
正常行为提供(1),使用
DoNothing
可以满足(2)。使用未设置的值
来表示完全失败是有道理的。这也与单值转换器的含义一致:UnsetValue
表示转换失败。唯一的区别是ConvertBack
返回object[]
,因此不能直接返回UnsetValue
。但是,您可以返回一个只包含未设置值的数组:因为它的存在意味着整个结果都会被抛出,所以数组长度实际上不必与子绑定的数量匹配。我不久前遇到过类似的问题[]
对我来说,有效的方法是“延迟”分配DependencyProperty.UnsetValue
:由于MultiBinding
在某种程度上是绑定的“集合”,您可以按如下方式为每个涉及的1-1绑定分配IValueConverter
:
(1) XAML标记:引入转换
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;
}
<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>
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 };
}
}
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;
}
}