DataTrigger in cui il valore NON è null?


163

So che posso creare un setter che controlla se un valore è NULL e fa qualcosa. Esempio:

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

Ma come posso verificare un valore "non" ... come in "NOT NULL" o "NOT = 3"? È possibile in XAML?

Risultati: Grazie per le tue risposte ... Sapevo di poter fare un convertitore di valore (il che significa che avrei dovuto inserire il codice e che non sarebbe stato XAML puro come speravo). Tuttavia, questo risponde alla domanda che effettivamente "no" non è possibile farlo in XAML puro. La risposta selezionata, tuttavia, mostra probabilmente il modo migliore per creare quel tipo di funzionalità. Buona scoperta.

Risposte:


42

Mi sono imbattuto in una limitazione simile con DataTriggers e sembrerebbe che tu possa solo verificare la parità. La cosa più vicina che ho visto che potrebbe aiutarti è una tecnica per fare altri tipi di confronti diversi dall'uguaglianza.

Questo post sul blog descrive come eseguire confronti come LT, GT, ecc. In un DataTrigger.

Questa limitazione di DataTrigger può essere aggirata in una certa misura usando un convertitore per massaggiare i dati in un valore speciale che è quindi possibile confrontare, come suggerito nella risposta di Robert Macnee.


10
È interessante notare che DataTrigger ha effettivamente un campo interno che controlla se verifica l'uguaglianza o meno. Sfortunatamente devi fare una ragionevole quantità di riflessione per arrivare al campo richiesto. Il problema è che potrebbe interrompersi nella prossima versione di .net.
Caleb Vear,

155

Per questo puoi usare un 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>

Dove IsNullConverter è definito altrove (e conv è impostato per fare riferimento al suo spazio dei nomi):

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 soluzione più generale sarebbe quella di implementare un IValueConverter che controlla l'uguaglianza con ConverterParameter, in modo da poter verificare qualsiasi cosa, e non solo null.


6
Suppongo che potresti rendere il convertitore un po 'più generico e utilizzare ConverterParameter per passare un valore da confrontare (al fine di supportare sia il confronto con NOT null sia NOT 3.
J c

Questo ha funzionato a meraviglia per me - utilizzando un trigger multiplo, lo rende bello e potente.
Bertie,

150

Questo è un po 'un trucco, ma ho appena impostato uno stile predefinito e quindi lo ho annullato usando un DataTrigger se il valore è 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>

1
Questa è stata la migliore soluzione per il mio scenario! Grazie per aver fornito questa risposta!
Scott,

14
Non penso che questo sia un trucco, devi farlo molto tempo; e questo è il modo più pulito per farlo.
Akjoshi,

3
Setter predefinito può essere utilizzato senza tag Style.Setter.
Naser Asadi,

1
Solo il biglietto! Continuavo a mettere il valore predefinito nel controllo proprietario dello stile e non riuscivo a capire perché continuasse a prevalere sui miei stili :-) Grazie!
Riegardt Steyn,

2
risposta migliore quindi usando un convertitore ... semplice e pulito.
DasDas,

27

Confronta con null (Come diceva Michael Noonan):

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

Confronta con not null (senza convertitore):

<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
Questa è di gran lunga la risposta più diretta. Mi piace!
Timoteo,

15

Sto usando questo per abilitare un pulsante solo se è selezionato un elemento listview (cioè 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>

4
A volte la soluzione più semplice è nascosta in bella vista. Credo che il codice XAML sia interpretato dall'alto verso il basso. In questo modo, il pulsante verrà prima abilitato e quindi disabilitato se non viene selezionato alcun elemento nella visualizzazione elenco. Ma per favore dimmi, lo stile viene aggiornato una volta selezionato un elemento nella visualizzazione elenco?
froeschli,

Il pulsante è abilitato quando è selezionata una voce di elenco, sì.
SteveCav,

14

È possibile utilizzare la DataTriggerclasse in Microsoft.Expression.Interactions.dll fornita con Expression Blend .

Esempio di codice:

<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 questo metodo è possibile attivare contro GreaterThane LessThananche. Per utilizzare questo codice è necessario fare riferimento a due dll:

System.Windows.Interactivity.dll

Microsoft.Expression.Interactions.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>

Ho appena usato la logica inversa qui ... impostando il mio stackpanel su invisibile quando il mio comboitem non è popolato, funziona abbastanza bene!


6

Fermare! Nessun convertitore! Non voglio "vendere" la libreria di questo ragazzo, ma odiavo il fatto di fare il convertitore ogni volta che volevo confrontare cose in XAML.

Quindi con questa libreria: https://github.com/Alex141/CalcBinding

puoi farlo [e molto altro]:

Innanzitutto, nella dichiarazione di windows / userControl:

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

quindi, nel blocco di testo

<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 magica è la conv: Binding 'MYValue == null' . In effetti, potresti impostare qualsiasi condizione tu voglia [guarda il documento].

nota che non sono un fan di terze parti. ma questa libreria è gratuita e di scarso impatto (basta aggiungere 2 dll al progetto).


5

La mia soluzione è nell'istanza DataContext (o ViewModel se si utilizza MVVM). Aggiungo una proprietà che restituisce true se viene soddisfatta la condizione Not Null che desidero.

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

e associare DataTrigger alla proprietà sopra. Nota: in VB.NET assicurarsi di utilizzare l'operatore If e NOT la funzione IIf, che non funziona con oggetti Null. Quindi XAML è:

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

3

Se stai cercando una soluzione che non utilizza IValueConverter, puoi sempre andare con il meccanismo seguente

       <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

Converter:

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

Rilegatura:

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

2

Puoi usare un convertitore o creare una nuova proprietà nel tuo ViewModel in questo modo:

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

e usalo:

<DataTrigger Binding="{Binding SomeField}" Value="{Binding CanDoIt}">
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.