DataTrigger où la valeur n'est pas null?
Je sais que je peux faire un setter qui vérifie si une valeur est NULL et faire 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 une valeur "non"... comme dans "NOT NULL", ou "NOT = 3"? Est-ce possible dans le code XAML?
Résultats: Merci pour vos réponses... Je savais que je pouvais faire un convertisseur de valeur (ce qui signifie que je devrais aller dans le code, et ce ne serait pas du XAML pur comme je l'espérais). Cependant, cela répond à la question que effectivement " non " vous ne pouvez pas le faire en XAML pur. La réponse sélectionnée, cependant, montre probablement la meilleure façon de créer ce genre de fonctionnalité. Bonne trouvaille.
12 réponses
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 vu qui pourrait vous aider est une technique pour faire d'autres types de comparaisons autres que l'égalité.
Cet article de blog décrit comment faire 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 masser les données en une valeur spéciale que vous pouvez ensuite comparez contre, comme suggéré dans la réponse de Robert Macnee.
Vous pouvez utiliser un IValueConverter pour ceci:
<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 serait d'implémenter un IValueConverter qui vérifie l'égalité avec le ConverterParameter, de sorte que vous pouvez vérifier n'importe quoi, et pas seulement null.
C'est un peu une triche mais je viens de définir un style par défaut, puis de le remplacer en utilisant 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>
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>
Comparer avec not null (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>
J'utilise ceci pour activer un bouton uniquement si un élément listview est sélectionné (c'est-à-dire non null):
<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>
Vous pouvez utiliser la classe DataTrigger
dans Microsoft.Expression.Interaction.dll qui viennent 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 déclencher contre GreaterThan
et LessThan
trop.
Pour utiliser ce code, vous devez référencer deux dll:
Système.Windows.Interactivité.dll
Microsoft.Expression.Interaction.dll
<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...définir mon stackpanel sur invisible lorsque mon comboitem n'est pas rempli, cela fonctionne plutôt bien!
Arrêter! Pas de convertisseur! Je ne veux pas "vendre" la bibliothèque de ce gars, mais je détestais le fait de faire converter 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 d'] :
Tout D'abord, dans la déclaration de windows / userControl:
<Windows....
xmlns:conv="clr-namespace:CalcBinding;assembly=CalcBinding"
>
Ensuite, dans le bloc 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 partie magique est la conv: Binding 'MYValue = = null' . En fait, vous pourrait définir n'importe quelle condition que vous vouliez [regardez le doc].
Notez que je ne suis pas un fan de tiers. mais cette bibliothèque est gratuite, et peu d'impact (il suffit d'ajouter 2 .dll pour le projet).
Ma solution est dans L'instance DataContext (ou ViewModel si vous utilisez MVVM). J'ajoute une propriété qui renvoie true si la condition Not Null que je veux est remplie.
Public ReadOnly Property IsSomeFieldNull() As Boolean
Get
Return If(SomeField is Null, True, False)
End Get
End Property
Et liez le DataTrigger à la propriété ci-dessus. Note: dans VB.NET assurez-vous d'utiliser l'opérateur If et non 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>
Convertisseur:
public class NullableToVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Collapsed : Visibility.Visible;
}
}
Liaison:
Visibility="{Binding PropertyToBind, Converter={StaticResource nullableToVisibilityConverter}}"
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}">
Si vous cherchez 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>