DataTrigger中的值不为空?

190

我知道我可以创建一个setter用于检查值是否为NULL并执行某些操作。例如:

<TextBlock>
  <TextBlock.Style>
    <Style>
      <Style.Triggers>
        <DataTrigger Binding="{Binding SomeField}" Value="{x:Null}">
          <Setter Property="TextBlock.Text" Value="It's NULL Baby!" />
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </TextBlock.Style>
</TextBlock>

我该如何检查“非”值,比如“NOT NULL”或“NOT = 3”?在XAML中是否可能实现?

结果:感谢您的回答... 我知道我可以使用值转换器(这意味着我必须编写代码,而不是像我希望的那样纯粹使用XAML)。然而,这确实回答了问题,即在纯XAML中不能实现。但是,所选的答案可能显示创建这种功能的最佳方法。做得好。

12个回答

192

这有点欺骗,但我只是设置了一个默认样式,然后使用数据触发器覆盖它,如果值为空...

  <Style> 
      <!-- Highlight for Reviewed (Default) -->
      <Setter Property="Control.Background" Value="PaleGreen" /> 
      <Style.Triggers>
        <!-- Highlight for Not Reviewed -->
        <DataTrigger Binding="{Binding Path=REVIEWEDBY}" Value="{x:Null}">
          <Setter Property="Control.Background" Value="LightIndianRed" />
        </DataTrigger>
      </Style.Triggers>
  </Style>

20
我认为这不是黑客行为,你需要多次这样做;而这是最干净的方法。 - akjoshi
3
可以使用 Default Setter,无需 Style.Setter 标签。 - Naser Asadi
1
太好了!我一直将默认值放在拥有样式的控件中,但就是想不通为什么它会覆盖我的样式 :-) 谢谢! - Riegardt Steyn
2
比使用转换器更好的答案...简单而干净。 - DasDas
3
如果默认样式/属性依赖于数据不为空,那么这可能会在输出窗口中导致绑定错误。 - ManIkWeet
显示剩余3条评论

167

您可以使用 IValueConverter 进行此操作:

<TextBlock>
    <TextBlock.Resources>
        <conv:IsNullConverter x:Key="isNullConverter"/>
    </TextBlock.Resources>
    <TextBlock.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding SomeField, Converter={StaticResource isNullConverter}}" Value="False">
                    <Setter Property="TextBlock.Text" Value="It's NOT NULL Baby!"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBlock.Style>
</TextBlock>

IsNullConverter在其他地方被定义(并且conv被设置为引用其命名空间):

public class IsNullConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (value == null);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
    }
}

一个更通用的解决方案是实现一个IValueConverter,该转换器检查与转换器参数的相等性,因此您可以针对任何内容进行检查,而不仅仅是null。


7
我会尽力进行翻译并使句子更加通顺易懂,但不会改变原意。需要翻译的内容是:“我想你可以让转换器更加通用,使用ConverterParameter传递一个值进行比较(以便支持与非空和非3的比较)。”。 - J c
这对我非常有效 - 使用多重触发器,使其更加强大。 - Bertie

41

我在使用DataTriggers时遇到了类似的限制,似乎只能检查相等性。最接近有用的方法是一种技术,可以进行除了相等性之外的其他类型比较。

这篇博客文章介绍了如何在DataTrigger中进行LT、GT等比较。

可以通过使用转换器将数据转换为特殊值来解决DataTrigger的这种限制,然后与其进行比较,正如Robert Macnee的答案所建议的那样。


11
有趣的是,DataTrigger 实际上有一个内部字段来控制它是测试相等还是不相等。不幸的是,你需要进行一定程度的反射才能到达所需的字段。问题是它可能会在下一个 .net 版本中出现故障。 - Caleb Vear

32

与null比较(正如Michael Noonan所说):

<Style>
    <Style.Triggers>
       <DataTrigger Binding="{Binding SomeProperty}" Value="{x:Null}">
           <Setter Property="Visibility" Value="Collapsed" />
        </DataTrigger>
     </Style.Triggers>
</Style>

与非空值进行比较(不使用转换器)相比:
<Style>
    <Setter Property="Visibility" Value="Collapsed" />
    <Style.Triggers>
       <DataTrigger Binding="{Binding SomeProperty}" Value="{x:Null}">
           <Setter Property="Visibility" Value="Visible" />
        </DataTrigger>
     </Style.Triggers>
</Style>

4
这绝对是最直接的答案。我喜欢它! - TimothyP
第二种情况不正是迈克尔·努南的答案所展示的吗? - ToolmakerSteve

17

我正在使用这个来仅在选择了ListView项(即非空)时启用按钮:

<Style TargetType="{x:Type Button}">
    <Setter Property="IsEnabled" Value="True"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding ElementName=lvMyList, Path=SelectedItem}" Value="{x:Null}">
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

4
有时候最简单的解决方案就在明显的地方隐藏着。我相信,XAML代码是从上到下解释的。这样,如果在ListView中没有选择元素,按钮将首先启用,然后禁用。但请告诉我,当在ListView中选择一个项目后,样式是否会更新? - froeschli
当选择列表项时,按钮将启用。 - SteveCav

15
你可以使用附带于Expression Blend的Microsoft.Expression.Interactions.dll中的DataTrigger类。
代码示例:
<i:Interaction.Triggers>
    <i:DataTrigger Binding="{Binding YourProperty}" Value="{x:Null}" Comparison="NotEqual">
       <ie:ChangePropertyAction PropertyName="YourTargetPropertyName" Value="{Binding YourValue}"/>
    </i:DataTrigger
</i:Interaction.Triggers>

使用此方法,您也可以触发GreaterThanLessThan。为了使用此代码,您应该引用两个dll:

System.Windows.Interactivity.dll

Microsoft.Expression.Interactions.dll


6

停!不要转换器!我不想“销售”这个家伙的库,但每次我想在 XAML 中比较东西时都很讨厌做转换器。

所以使用这个库:https://github.com/Alex141/CalcBinding

你可以做到以下事情[以及更多]:

首先,在窗口/用户控件的声明中:

<Windows....
     xmlns:conv="clr-namespace:CalcBinding;assembly=CalcBinding"
>

那么,在文本块中

<TextBlock>
      <TextBlock.Style>
          <Style.Triggers>
          <DataTrigger Binding="{conv:Binding 'MyValue==null'}" Value="false">
             <Setter Property="Background" Value="#FF80C983"></Setter>
          </DataTrigger>
        </Style.Triggers>
      </TextBlock.Style>
    </TextBlock>

其中神奇的部分是conv:Binding 'MYValue==null'。实际上,你可以设置任何条件[请查看文档]。

请注意,我不喜欢第三方组件。但是这个库是免费的,并且影响小(只需要将2个.dll添加到项目中)。


6
<StackPanel.Style>
  <Style>
    <Setter Property="StackPanel.Visibility" Value="Visible"></Setter>
    <Style.Triggers>
      <DataTrigger  Binding="{Binding ElementName=ProfileSelectorComboBox, Path=SelectedItem.Tag}" Value="{x:Null}">
          <Setter Property="StackPanel.Visibility" Value="Collapsed"></Setter>
      </DataTrigger>
    </Style.Triggers>
  </Style>
</StackPanel.Style>

我只是使用了相反的逻辑... 当我的组合框项未填充时,将我的堆栈面板设置为不可见,这样就可以很好地工作了!


5

我的解决方案在DataContext实例(或使用MVVM的ViewModel)中。我添加了一个属性,如果满足我想要的非空条件,则返回true。

    Public ReadOnly Property IsSomeFieldNull() As Boolean
        Get
            Return If(SomeField is Null, True, False)
        End Get
    End Property

并将DataTrigger绑定到上述属性。 注意:在VB.NET中,请务必使用运算符If而不是IIf函数,后者无法与Null对象一起使用。 然后XAML代码如下:

    <DataTrigger Binding="{Binding IsSomeFieldNull}" Value="False">
      <Setter Property="TextBlock.Text" Value="It's NOT NULL Baby!" />
    </DataTrigger>

3
如果您正在寻找不使用IValueConverter的解决方案,您可以选择以下机制。
       <StackPanel>
            <TextBlock Text="Border = Red when null value" />
            <Border x:Name="border_objectForNullValueTrigger" HorizontalAlignment="Stretch" Height="20"> 
                <Border.Style>
                    <Style TargetType="Border">
                        <Setter Property="Background" Value="Black" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ObjectForNullValueTrigger}" Value="{x:Null}">
                                <Setter Property="Background" Value="Red" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>
            <TextBlock Text="Border = Green when not null value" />
            <Border HorizontalAlignment="Stretch" Height="20">
                <Border.Style>
                    <Style TargetType="Border">
                        <Setter Property="Background" Value="Green" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Background, ElementName=border_objectForNullValueTrigger}" Value="Red">
                                <Setter Property="Background" Value="Black" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>
            <Button Content="Invert Object state" Click="Button_Click_1"/>
        </StackPanel>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接