9

我问是因为它似乎不起作用。

假设我们绑定到以下对象:

public class HurrDurr
{
  public string Hurr {get{return null;}}
  public string Durr {get{return null;}}
}

好吧,看起来如果我们对此使用MultiBinding会显示回退值,对吧?

<TextBlock>
    <TextBlock.Text>                                
        <MultiBinding StringFormat="{}{0} to the {1}"
                        FallbackValue="Not set!  It works as expected!)">
            <Binding Path="Hurr"/>
            <Binding Path="Durr"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

然而结果,其实是“到了”。即使强制绑定返回DependencyProperty.UnsetValue也不起作用:

<TextBlock xmnlns:base="clr-namespace:System.Windows;assembly=WindowsBase">
    <TextBlock.Text>                                
        <MultiBinding StringFormat="{}{0} to the {1}"
            FallbackValue="Not set!  It works as expected!)">
            <Binding Path="Hurr"
                FallbackValue="{x:Static base:DependencyProperty.UnsetValue}" />
            <Binding Path="Durr"
                FallbackValue="{x:Static base:DependencyProperty.UnsetValue}" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

对TargetNullValue进行了同样的尝试,这也是一个失败的过程。

所以看起来MultiBinding永远不会使用FallbackValue。这是真的,还是我错过了什么?


稍微搞砸了,我发现转换器可以返回我需要的 UnsetValue:

class MultiValueFailConverter : IMultiValueConverter
{
    public object Convert(
        object[] values, 
        Type targetType, 
        object parameter, 
        System.Globalization.CultureInfo culture)
    {
        if (values == null || 
            values.Length != 2 ||
            values.Any(x=>x == null))
            return System.Windows.DependencyProperty.UnsetValue;
        return values;
    }

    public object[] ConvertBack(
        object value, 
        Type[] targetTypes, 
        object parameter, 
        System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException("Too complex hurt brain.");
    }
}

然而,这似乎是一个肮脏肮脏的黑客。我认为这样的场景会在框架中得到考虑。但是,我在 Reflector 中找不到任何东西。

4

1 回答 1

8

这是一个老问题,但它可以使用一些解释。

来自FallbackValue 文档

在以下情况下,绑定成功返回值:

  1. 绑定源的路径解析成功。
  2. 值转换器(如果有)能够转换结果值。
  3. 结果值对绑定目标(target)属性有效。

如果 1 和 2 返回 DependencyProperty.UnsetValue,则目标属性设置为 FallbackValue 的值(如果可用)。如果没有 FallbackValue,则使用目标属性的默认值。

在提供的示例中,绑定成功解析为HurrDurr属性。Null 是字符串的有效值,这意味着绑定有效。

换句话说,当绑定无法返回值时使用 FallbackValue,并且在提供的示例中,绑定确实提供了有效值。

以以下每个基于原始示例的片段为例:

示例 1
Hurr 和 Durr 属性绑定正确;null 是一个有效值,并且永远不会看到 FallbackValue。

<TextBlock>
    <TextBlock.Text>
        <MultiBinding FallbackValue="Binding is valid. I will never be seen." StringFormat="{}{0} to the {1}">
            <Binding Path="Hurr" />
            <Binding Path="Durr" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

示例 2
Hurr 和 Durr 属性未正确绑定;将看到 FallbackValue。

<TextBlock>
    <TextBlock.Text>
        <MultiBinding FallbackValue="Binding paths are invalid. Look at me." StringFormat="{}{0} to the {1}">
            <Binding Path="xHurr" />
            <Binding Path="xDurr" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

示例 3
如果一个绑定路径无效,则将看到 FallbackValue。

<TextBlock>
    <TextBlock.Text>
        <MultiBinding FallbackValue="One binding path is invalid. Look at me." StringFormat="{}{0} to the {1}">
            <Binding Path="xHurr" />
            <Binding Path="Durr" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

示例 4
与前面的示例一样,绑定是正确的,因此不会使用 FallbackValue。此外,父项的每个子Binding属性的MultiBindingFallbackValue 应引用用于 MultiBinding 的目标属性的 FallbackValue,而不是子绑定。

<TextBlock xmlns:base="clr-namespace:System.Windows;assembly=WindowsBase">
    <TextBlock.Text>
        <MultiBinding FallbackValue="Binding is valid. I will never be seen." StringFormat="{}{0} to the {1}">
            <Binding FallbackValue="{x:Static base:DependencyProperty.UnsetValue}" Path="Hurr" />
            <Binding FallbackValue="{x:Static base:DependencyProperty.UnsetValue}" Path="Durr" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

示例 5
即使在Binding属性中没有提供路径,绑定仍然有效,因为绑定将使用它所绑定的任何对象。

<TextBlock xmlns:base="clr-namespace:System.Windows;assembly=WindowsBase">
    <TextBlock.Text>
        <MultiBinding FallbackValue="Binding is still valid. I will never be seen." StringFormat="{}{0} to the {1}">
            <Binding FallbackValue="{x:Static base:DependencyProperty.UnsetValue}" />
            <Binding FallbackValue="{x:Static base:DependencyProperty.UnsetValue}" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

示例 6
最后,如果将转换器添加到任何 Binding 属性以强制 UnsetValue,则将看到 MultiBinding FallbackValue:

转换器

internal class ForceUnsetValueConverter : IValueConverter
{
    #region Implementation of IValueConverter

    public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
    {
        return DependencyProperty.UnsetValue;
    }

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

    #endregion
}

XAML

<TextBlock>
    <TextBlock.Text>
        <MultiBinding FallbackValue="Binding is valid, but look at me. I'm an UnsetValue." StringFormat="{}{0} to the {1}">
            <Binding Converter="{StaticResource ForceUnset}" Path="Hurr" />
            <Binding Path="Durr" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>
于 2013-01-09T20:59:44.937 回答