Wpf 值不为null的DataTrigger?

Wpf 值不为null的DataTrigger?,wpf,xaml,binding,visibility,datatrigger,Wpf,Xaml,Binding,Visibility,Datatrigger,我知道我可以做一个setter,检查一个值是否为NULL,然后做一些事情。例如: <TextBlock> <TextBlock.Style> <Style> <Style.Triggers> <DataTrigger Binding="{Binding SomeField}" Value="{x:Null}"> <Setter Property="TextBlock.Te

我知道我可以做一个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”值。。。如“NOT NULL”或“NOT=3”?这在XAML中可能吗


结果:感谢您的回答。。。我知道我可以做一个值转换器(这意味着我必须使用代码,而这并不是我所希望的纯XAML)。然而,这确实回答了一个问题,即在纯XAML中不能有效地做到“不”。然而,选择的答案可能显示了创建此类功能的最佳方式。很好的发现。

我在DataTriggers上遇到了类似的限制,似乎您只能检查是否相等。我所见过的最有可能帮助你的东西是一种做其他类型比较的技巧,而不是平等

描述如何在DataTrigger中进行比较,如LT、GT等


如Robert Macnee的回答所示,通过使用转换器将数据转换成一个特殊值,然后与之进行比较,可以在一定程度上解决DataTrigger的这一限制。

您可以使用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>

一个更通用的解决方案是实现一个检查与ConverterParameter是否相等的IValueConverter,这样您就可以检查任何内容,而不仅仅是空值。

这有点欺骗,但我只是设置了一个默认样式,然后在值为空时使用DataTrigger对其进行重写

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

我使用此选项仅在选择listview项(即非空)时启用按钮:


我的解决方案位于DataContext实例中(如果使用MVVM,则为ViewModel)。我添加了一个属性,如果满足我想要的NOTNULL条件,该属性将返回true

    Public ReadOnly Property IsSomeFieldNull() As Boolean
        Get
            Return If(SomeField is Null, True, False)
        End Get
    End Property
并将DataTrigger绑定到上述属性。 注意:在VB.NET中,请确保使用运算符If而不是IIf函数,该函数不适用于空对象。 那么XAML是:

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

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


与非空比较(不带转换器):


转换器:

public class NullableToVisibilityConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value == null ? Visibility.Collapsed : Visibility.Visible;
    }
}
绑定:

Visibility="{Binding PropertyToBind, Converter={StaticResource nullableToVisibilityConverter}}"

您可以在Microsoft.Expression.Interactions.dll中使用Expression Blend附带的
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>



我只是在这里使用了相反的逻辑…当我的comboitem未填充时,将stackpanel设置为不可见,效果非常好

住手!没有转换器!我不想“出售”这个家伙的库,但我讨厌每次我想在XAML中比较东西时都使用converter

因此,对于这个库:

你可以做到这一点[还有更多]:

首先,在windows/userControl的声明中:

<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添加到项目中即可)。

您可以使用转换器或在ViewModel中创建新属性,如下所示:

public bool CanDoIt
{
    get
    {
        return !string.IsNullOrEmpty(SomeField);
    }
}
并使用它:

<DataTrigger Binding="{Binding SomeField}" Value="{Binding CanDoIt}">

如果您正在寻找不使用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>


我想您可以让转换器更通用一些,并使用ConverterParameter传入一个值进行比较(为了同时支持比较非空和非3。这对我来说是一件好事——使用多重触发器,它使它变得漂亮和强大。有趣的是,DataTrigger实际上有一个内部字段,它控制着它是否测试相等。不幸的是,你必须进行合理的反射才能到达e必填字段。问题是它可能会在下一版本的.net中中断。这是我的方案的最佳解决方案!感谢您提供此答案!我不认为这是一个黑客行为,您需要花费大量时间来完成此操作;这是最干净的方法。默认Setter可以在没有样式的情况下使用。Setter标记。way更好的答案是使用converter…简单且干净。如果默认样式/属性依赖于数据,则输出窗口中可能会出现绑定错误。有时,最简单的解决方案隐藏在clear view中。我相信,XAML代码是从上到下解释的。这样,如果li中没有元素,按钮将首先启用,然后禁用选择了stview。但是请告诉我,一旦在listview中选择了一个项目,样式是否会更新?当选择了一个列表项目时,按钮将启用,是的。这是迄今为止最直接的答案。我喜欢它!
<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>
public bool CanDoIt
{
    get
    {
        return !string.IsNullOrEmpty(SomeField);
    }
}
<DataTrigger Binding="{Binding SomeField}" Value="{Binding CanDoIt}">
       <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>