当量。在XAML绑定中的Coalesce()?

时间:2021-11-13 11:44:25

In SQL I can do this:

在SQL中我可以这样做:

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

If Property1, 2 and 3 are all null, then I get 'All Null'

如果Property1,2和3都为null,那么我得到'All Null'

How do I do this in XAML? I tried the following, but no luck:

我如何在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>

The result should be 'Hello World' but instead it is 'All Null'

结果应该是'Hello World',而是'All Null'

I hope my question is clear.

我希望我的问题很清楚。

3 个解决方案

#1


7  

You'd have to build a custom IMultiValueConverter to do that and use a MultiBinding. PriorityBinding uses the first binding in the collection that produces a value successfully. In your case, the Property1 binding resolves immediately, so it's used. Since Property1 is null, the TargetNullValue is used.

您必须构建一个自定义IMultiValueConverter才能执行此操作并使用MultiBinding。 PriorityBinding使用集合中的第一个绑定成功生成值。在您的情况下,Property1绑定立即解析,因此使用它。由于Property1为null,因此使用TargetNullValue。

A converter like this:

像这样的转换器:

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();
    }
}

And MultiBinding like this:

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

#2


2  

Since you are binding to a String, null is a valid value for the PriorityBinding. I'm not sure what your Item class's property types are, but if you use Object, and set them to DependencyProperty.UnsetValue, you will get the behavior you are looking for.

由于绑定到String,因此null是PriorityBinding的有效值。我不确定您的Item类的属性类型是什么,但如果您使用Object,并将它们设置为DependencyProperty.UnsetValue,您将获得您正在寻找的行为。

The PriorityBinding documentation's remarks section describes how it works in more detail.

PriorityBinding文档的备注部分更详细地描述了它的工作原理。

#3


0  

The PriorityBinding is only looking for DependencyProperty.UnsetValue to advance to the next Binding. Since Property1 exists it is set and the PriorityBinding is taking the value of it.

PriorityBinding仅查找DependencyProperty.UnsetValue以进入下一个Binding。由于Property1存在,因此设置它并且PriorityBinding将获取它的值。

For a pure XAML solution, this Style will do the job:

对于纯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>

Although, it's a bit convoluted way of doing it, and IMHO, doesn't belong in the UI but in the ViewModel.

虽然,这有点令人费解,但恕我直言,不属于UI,而是属于ViewModel。

#1


7  

You'd have to build a custom IMultiValueConverter to do that and use a MultiBinding. PriorityBinding uses the first binding in the collection that produces a value successfully. In your case, the Property1 binding resolves immediately, so it's used. Since Property1 is null, the TargetNullValue is used.

您必须构建一个自定义IMultiValueConverter才能执行此操作并使用MultiBinding。 PriorityBinding使用集合中的第一个绑定成功生成值。在您的情况下,Property1绑定立即解析,因此使用它。由于Property1为null,因此使用TargetNullValue。

A converter like this:

像这样的转换器:

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();
    }
}

And MultiBinding like this:

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

#2


2  

Since you are binding to a String, null is a valid value for the PriorityBinding. I'm not sure what your Item class's property types are, but if you use Object, and set them to DependencyProperty.UnsetValue, you will get the behavior you are looking for.

由于绑定到String,因此null是PriorityBinding的有效值。我不确定您的Item类的属性类型是什么,但如果您使用Object,并将它们设置为DependencyProperty.UnsetValue,您将获得您正在寻找的行为。

The PriorityBinding documentation's remarks section describes how it works in more detail.

PriorityBinding文档的备注部分更详细地描述了它的工作原理。

#3


0  

The PriorityBinding is only looking for DependencyProperty.UnsetValue to advance to the next Binding. Since Property1 exists it is set and the PriorityBinding is taking the value of it.

PriorityBinding仅查找DependencyProperty.UnsetValue以进入下一个Binding。由于Property1存在,因此设置它并且PriorityBinding将获取它的值。

For a pure XAML solution, this Style will do the job:

对于纯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>

Although, it's a bit convoluted way of doing it, and IMHO, doesn't belong in the UI but in the ViewModel.

虽然,这有点令人费解,但恕我直言,不属于UI,而是属于ViewModel。