web-dev-qa-db-fra.com

DataTrigger où la valeur n'est PAS nulle?

Je sais que je peux faire un setter qui vérifie si une valeur est NULL et fait quelque chose. Exemple:

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

Mais comment puis-je vérifier la valeur "not" ... comme dans "NOT NULL" ou "NOT = 3"? Est-ce possible en XAML?

Résultats: Merci pour vos réponses ... Je savais que je pouvais faire un convertisseur de valeur (ce qui signifie que je devrais entrer dans le code, et ce ne serait pas du pur XAML comme je l'espérais). Toutefois, cela répond à la question selon laquelle "non" vous ne pouvez pas le faire en XAML pur. La réponse sélectionnée, cependant, indique probablement le meilleur moyen de créer ce type de fonctionnalité. Bonne trouvaille.

148
Timothy Khouri

J'ai rencontré une limitation similaire avec DataTriggers, et il semblerait que vous ne pouvez vérifier que l'égalité. La chose la plus proche que j'ai pu voir qui puisse vous aider est une technique permettant de faire d'autres types de comparaisons autres que l'égalité.

Cet article de blog explique comment effectuer des comparaisons telles que LT, GT, etc. dans un DataTrigger.

Cette limitation du DataTrigger peut être contournée dans une certaine mesure en utilisant un convertisseur pour transformer les données en une valeur spéciale que vous pouvez ensuite comparer, comme suggéré dans la réponse de Robert Macnee.

36
J c

Vous pouvez utiliser un IValueConverter pour cela:

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

Où IsNullConverter est défini ailleurs (et conv est défini pour référencer son espace de noms):

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

Une solution plus générale consisterait à implémenter un IValueConverter qui vérifie l’égalité avec ConverterParameter, afin que vous puissiez vérifier par tout, et pas seulement null.

140
Robert Macnee

C'est un peu une triche, mais je viens de définir un style par défaut, puis de le remplacer à l'aide d'un DataTrigger si la valeur est 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>
136
Michael Noonan

Comparez avec null (comme l'a dit Michael Noonan):

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

Comparez avec non nul (sans convertisseur):

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

Vous pouvez utiliser la classe DataTrigger dans Microsoft.Expression.Interactions.dll fournie avec Expression Blend.

Exemple de code:

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

En utilisant cette méthode, vous pouvez aussi déclencher contre GreaterThan et LessThan. Pour utiliser ce code, vous devez référencer deux dll:

System.Windows.Interactivity.dll

Microsoft.Expression.Interactions.dll

14
yossharel

J'utilise ceci pour activer un bouton uniquement si un élément listview est sélectionné (c'est-à-dire non nul):

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

Je viens d'utiliser la logique inverse ici ... régler mon stackpanel sur invisible quand mon comboitem n'est pas rempli, ça marche plutôt bien!

6
aromore

Arrêtez! Pas de convertisseur! Je ne veux pas "vendre" la bibliothèque de ce type, mais je détestais le fait de faire des convertisseurs à chaque fois que je voulais comparer des choses en XAML.

Donc, avec cette bibliothèque: https://github.com/Alex141/CalcBinding

vous pouvez le faire [et beaucoup plus]:

Tout d'abord, dans la déclaration de windows/userControl:

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

puis, dans le bloc de texte

<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 partie magique est la conv: Liaison 'MYValue == null' . En fait, vous pouvez définir la condition de votre choix [consultez la documentation].

notez que je ne suis pas un fan de tiers. mais cette librairie est gratuite et peu impactante (ajoutez juste 2 .dll au projet).

5
Simon

Ma solution se trouve dans l'instance DataContext (ou ViewModel si vous utilisez MVVM). J'ajoute une propriété qui renvoie la valeur true si la condition Non Null que je souhaite est remplie.

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

et lier le DataTrigger à la propriété ci-dessus. Remarque: dans VB.NET, veillez à utiliser l'opérateur If et NOT la fonction IIf, qui ne fonctionne pas avec les objets Null. Alors le XAML est:

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

Si vous recherchez une solution qui n'utilise pas IValueConverter, vous pouvez toujours utiliser le mécanisme ci-dessous.

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

Vous pouvez utiliser un convertisseur ou créer une nouvelle propriété dans votre ViewModel comme ceci:

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

et l'utiliser:

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

Convertisseur:

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

Contraignant:

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