Эквивалент. объединить () в привязке XAML? - PullRequest
6 голосов
/ 04 августа 2011

В SQL я могу сделать это:

Select Coalesce(Property1, Property2, Property3, 'All Null') as Value
From MyTable 

Если значения Property1, 2 и 3 равны нулю, тогда я получаю 'All Null'

Как мне это сделать в XAML? Я попробовал следующее, но не повезло:

<Window.Resources>
    <local:Item x:Key="MyData" 
                Property1="{x:Null}"
                Property2="{x:Null}"
                Property3="Hello World" />
</Window.Resources>

<TextBlock DataContext="{StaticResource MyData}">
    <TextBlock.Text>
        <PriorityBinding TargetNullValue="All Null">
            <Binding Path="Property1" />
            <Binding Path="Property2" />
            <Binding Path="Property3" />
        </PriorityBinding>
    </TextBlock.Text>
</TextBlock>

Результат должен быть «Hello World», но вместо этого «All Null»

Надеюсь, мой вопрос понятен.

Ответы [ 3 ]

9 голосов
/ 04 августа 2011

Для этого вам нужно создать пользовательский IMultiValueConverter и использовать MultiBinding. PriorityBinding использует первую привязку в коллекции, которая успешно создает значение.В вашем случае привязка Property1 разрешается немедленно, поэтому она используется.Поскольку Property1 имеет значение null, используется TargetNullValue.

Преобразователь, подобный этому:

public class CoalesceConverter : System.Windows.Data.IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, 
            object parameter, System.Globalization.CultureInfo culture)
    {
        if (values == null)
            return null;
        foreach (var item in values)
            if (item != null)
                return item;
        return null;
    }

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

, и MultiBinding, подобный этому:

<Window.Resources>
    <local:Item x:Key="MyData" 
                Property1="{x:Null}"
                Property2="{x:Null}"
                Property3="Hello World" />
    <local:CoalesceConverter x:Key="MyConverter" />
</Window.Resources>

<TextBlock DataContext="{StaticResource MyData}">
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource MyConverter}">
            <Binding Path="Property1" />
            <Binding Path="Property2" />
            <Binding Path="Property3" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>
3 голосов
/ 05 августа 2011

Поскольку вы связываетесь с String, для PriorityBinding допустимым является значение NULL. Я не уверен, каковы типы свойств вашего класса Item, но если вы используете Object и устанавливаете их в DependencyProperty.UnsetValue, вы получите поведение, которое вы ищете.

В разделе замечаний к документации PriorityBinding более подробно описано, как это работает.

0 голосов
/ 05 августа 2011

PriorityBinding ищет только DependencyProperty.UnsetValue для перехода к следующему Binding.Поскольку Property1 существует, он установлен, и PriorityBinding принимает его значение.

Для чистого решения XAML этот Style выполнит свою работу:

   <TextBlock>
        <TextBlock.Style>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="Text"
                        Value="{Binding Property1}" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Property1}"
                                 Value="{x:Null}">
                        <Setter Property="Text"
                                Value="{Binding Property2}" />
                    </DataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Property1}"
                                       Value="{x:Null}" />
                            <Condition Binding="{Binding Property2}"
                                       Value="{x:Null}" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Text"
                                Value="{Binding Property3}" />
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Property1}"
                                       Value="{x:Null}" />
                            <Condition Binding="{Binding Property2}"
                                       Value="{x:Null}" />
                            <Condition Binding="{Binding Property3}"
                                       Value="{x:Null}" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Text"
                                Value="All Null" />
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>

Хотя это немного запутанный способ сделать это, и ИМХО, не в пользовательском интерфейсе, а в ViewModel.

...