Как FallbackValue работает с MultiBinding? - PullRequest
9 голосов
/ 19 апреля 2010

Я спрашиваю, потому что это не похоже на работу.

Предположим, мы привязываемся к следующему объекту:

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 я ничего не могу найти.

1 Ответ

8 голосов
/ 10 января 2013

Это немного старый вопрос, но он может использовать некоторые объяснения.

Из документации FallbackValue :

Привязка возвращает значение успешно, если:

  1. Путь к источнику привязки разрешен успешно.
  2. Преобразователь значения, если таковой имеется, может преобразовать полученное значение.
  3. Полученное значение действительно для свойства target (target) привязки.

Если 1 и 2 возвращают DependencyProperty.UnsetValue, свойство target устанавливается в значение FallbackValue, если оно доступно. Если FallbackValue отсутствует, значением по умолчанию для целевого свойства является б.

В приведенном примере привязка успешно разрешается в свойствах Hurr и Durr. 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 не будет использоваться. Кроме того, FallbackValue для каждого из дочерних Binding свойств родительского элемента MultiBinding должен ссылаться на FallbackValue, который будет использоваться для целевого свойства MultiBinding, а не для дочерних привязок.

<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>
...