DataTrigger donde el valor NO es null?


Sé que puedo hacer un setter que comprueba si un valor es NULO y hacer algo. Ejemplo:

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

Pero cómo puedo comprobar si hay un valor "not"... como en "NOT NULL", o"NOT = 3"? ¿Es eso posible en XAML?

Resultados: Gracias por sus respuestas... Sabía que podía hacer un convertidor de valor (lo que significa que tendría que ir en código, y que no sería puro XAML como esperaba). Sin embargo, eso responde a la pregunta de que efectivamente "no" no puedes hacerlo en XAML puro. La respuesta seleccionada, sin embargo, muestra probablemente la mejor manera de crear ese tipo de funcionalidad. Buen hallazgo.

Author: abatishchev, 2008-12-10

12 answers

Me encontré con una limitación similar con DataTriggers, y parece que solo se puede comprobar la igualdad. Lo más cercano que he visto que podría ayudarte es una técnica para hacer otros tipos de comparaciones además de la igualdad.

Esta entrada de blog describe cómo hacer comparaciones como LT, GT, etc. en un DataTrigger.

Esta limitación del DataTrigger se puede solucionar hasta cierto punto mediante el uso de un convertidor para masajear los datos en un valor especial que luego puede comparar contra, como se sugiere en la respuesta de Robert Macnee.

 34
Author: J c,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-10 17:00:52

Puedes usar un IValueConverter para esto:

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

Donde IsNullConverter se define en otro lugar (y conv se establece para hacer referencia a su espacio de nombres):

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.");
    }
}

Una solución más general sería implementar un IValueConverter que verifique la igualdad con el parámetro Converter, para que pueda verificar cualquier cosa, y no solo null.

 133
Author: Robert Macnee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-06 21:48:48

Esto es un poco tramposo, pero acabo de establecer un estilo predeterminado y luego lo anulo usando un DataTrigger si el valor es null...

  <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>
 124
Author: Jamaxack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-27 11:54:08

Compárese con null (Como dijo Michael Noonan):

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

Comparar con not null (sin convertidor):

<Style>
    <Setter Property="Visibility" Value="Collapsed" />
    <Style.Triggers>
       <DataTrigger Binding="{Binding SomeProperty}" Value="{x:Null}">
           <Setter Property="Visibility" Value="Visible" />
        </DataTrigger>
     </Style.Triggers>
</Style>
 21
Author: JoanComasFdz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-09 14:21:30

Estoy usando esto para habilitar solo un botón si se selecciona un elemento listview (es decir, no nulo):

<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>
 14
Author: SteveCav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-02 01:08:01

Puede usar la clase DataTrigger en Microsoft.Expresion.Interacción.dll que vienen con Expresión Blend.

Ejemplo de código:

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

Usando este método puedes disparar contra GreaterThan y LessThan también. Para usar este código, debe hacer referencia a dos dll:

Sistema.Windows.Interactividad.dll

Microsoft.Expresion.Interacción.dll

 13
Author: yossharel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-23 10:52:49
<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>

Acabo de usar la lógica inversa aquí...configurar mi stackpanel a invisible cuando mi comboitem no está poblada, funciona bastante bien!

 6
Author: aromore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-30 20:47:22

Parar! ¡Sin convertidor! No quiero "vender" la biblioteca de este tipo, pero odiaba el hecho de hacer convertidor cada vez que quería comparar cosas en XAML.

Así que con esta biblioteca: https://github.com/Alex141/CalcBinding

Puedes hacer eso [y mucho más]:

Primero, en la declaración de windows / UserControl :

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

Luego, en el textblock

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

La parte mágica es el conv:Binding 'MyValue==null'. De hecho, usted podría establecer cualquier condición que desee [mire el documento].

Tenga en cuenta que no soy un fan de terceros. pero esta biblioteca es gratuita, y poco impacto (solo agregue 2 .dll al proyecto).

 5
Author: Simon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-09 13:57:53

Mi solución está en la instancia de DataContext (o ViewModel si se usa MVVM). Agrego una propiedad que devuelve true si se cumple la condición Not Null que quiero.

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

Y enlaza el DataTrigger a la propiedad anterior. Nota: En VB.NET asegúrese de usar el operador If y NO la función IIf, que no funciona con objetos Null. Entonces el XAML es:

    <DataTrigger Binding="{Binding IsSomeFieldNull}" Value="False">
      <Setter Property="TextBlock.Text" Value="It's NOT NULL Baby!" />
    </DataTrigger>
 3
Author: APaglia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-10 09:01:10

Convertidor:

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

Enlace:

Visibility="{Binding PropertyToBind, Converter={StaticResource nullableToVisibilityConverter}}"
 2
Author: abatishchev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-10 12:42:15

Puedes usar un convertidor o crear una nueva propiedad en tu ViewModel así:

public bool CanDoIt
{
    get
    {
        return !string.IsNullOrEmpty(SomeField);
    }
}

Y úsalo:

<DataTrigger Binding="{Binding SomeField}" Value="{Binding CanDoIt}">
 2
Author: Butsaty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-26 10:49:29

Si está buscando una solución que no use IValueConverter, siempre puede ir con el mecanismo siguiente

       <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>
 2
Author: Chaitanya Kadamati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-10 10:33:30