DataTrigger di mana nilainya TIDAK nol?

163

Saya tahu bahwa saya bisa membuat setter yang memeriksa untuk melihat apakah suatu nilai NULL dan melakukan sesuatu. Contoh:

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

Tetapi bagaimana saya bisa mengecek nilai "tidak" ... seperti "TIDAK NULL", atau "TIDAK = 3"? Apakah itu mungkin di XAML?

Hasil: Terima kasih atas jawaban Anda ... Saya tahu saya bisa melakukan konverter nilai (yang berarti saya harus memasukkan kode, dan itu tidak akan menjadi XAML murni seperti yang saya harapkan). Namun, itu menjawab pertanyaan yang secara efektif "tidak" Anda tidak dapat melakukannya dalam XAML murni. Namun, jawaban yang dipilih mungkin menunjukkan cara terbaik untuk membuat fungsionalitas semacam itu. Bagus temukan.

Timothy Khouri
sumber

Jawaban:

42

Saya mengalami keterbatasan serupa dengan DataTriggers, dan tampaknya Anda hanya dapat memeriksa kesetaraan. Hal terdekat yang saya lihat yang mungkin membantu Anda adalah teknik untuk melakukan perbandingan jenis lain selain kesetaraan.

Posting blog ini menjelaskan cara melakukan perbandingan seperti LT, GT, dll di DataTrigger.

Keterbatasan DataTrigger ini dapat dikerjakan sampai batas tertentu dengan menggunakan Konverter untuk memijat data menjadi nilai khusus yang kemudian dapat Anda bandingkan, seperti yang disarankan dalam jawaban Robert Macnee.

J c
sumber
10
Yang cukup menarik, DataTrigger sebenarnya memiliki bidang internal yang mengontrol apakah ia menguji kesetaraan atau tidak. Sayangnya Anda harus melakukan sejumlah refleksi yang masuk akal untuk sampai ke bidang yang diperlukan. Masalahnya adalah bahwa hal itu mungkin rusak di versi .net.
Caleb Vear
155

Anda dapat menggunakan IValueConverter untuk ini:

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

Di mana IsNullConverter didefinisikan di tempat lain (dan conv diatur ke referensi namespace-nya):

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

Solusi yang lebih umum adalah dengan mengimplementasikan IValueConverter yang memeriksa kesetaraan dengan ConverterParameter, sehingga Anda dapat memeriksa apa pun, dan bukan hanya nol.

Robert Macnee
sumber
6
Saya kira Anda bisa membuat konverter sedikit lebih umum dan menggunakan ConverterParameter untuk memberikan nilai untuk dibandingkan (untuk mendukung keduanya dibandingkan dengan TIDAK nol dan TIDAK 3.
JC
Ini berhasil bagi saya - menggunakan Multiple Trigger, itu membuatnya bagus dan kuat.
Bertie
150

Ini sedikit curang tapi saya hanya mengatur gaya default dan kemudian mengesampingkannya menggunakan DataTrigger jika nilainya nol ...

  <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>
Jamaxack
sumber
1
Ini adalah solusi terbaik untuk skenario saya! Terima kasih telah memberikan jawaban ini!
Scott
14
Saya tidak berpikir ini adalah hack, Anda perlu melakukan ini banyak waktu; dan ini adalah cara paling bersih untuk melakukan ini.
akjoshi
3
Setter Default dapat digunakan tanpa tag Style.Setter.
Naser Asadi
1
Hanya tiketnya! Saya terus meletakkan default di kontrol yang memiliki Style, dan tidak tahu mengapa itu terus menimpa style saya :-) Terima kasih!
Riegardt Steyn
2
cara jawaban yang lebih baik kemudian menggunakan konverter ... sederhana dan bersih.
DasDas
27

Bandingkan dengan null (Seperti yang dikatakan Michael Noonan):

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

Bandingkan dengan yang bukan nol (tanpa konverter):

<Style>
    <Setter Property="Visibility" Value="Collapsed" />
    <Style.Triggers>
       <DataTrigger Binding="{Binding SomeProperty}" Value="{x:Null}">
           <Setter Property="Visibility" Value="Visible" />
        </DataTrigger>
     </Style.Triggers>
</Style>
JoanComasFdz
sumber
4
Sejauh ini, inilah jawaban yang paling mudah. Saya suka itu!
TimothyP
15

Saya menggunakan ini untuk hanya mengaktifkan tombol jika item listview dipilih (yaitu bukan 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>
SteveCav
sumber
4
Terkadang solusi paling sederhana disembunyikan dalam tampilan yang jelas. Saya percaya, kode XAML ditafsirkan dari atas ke bawah. Dengan begitu, tombol pertama-tama akan diaktifkan dan kemudian dinonaktifkan jika tidak ada elemen dalam tampilan daftar yang dipilih. Tapi tolong beri tahu saya, apakah gaya diperbarui setelah item dipilih dalam tampilan daftar?
froeschli
Tombol diaktifkan ketika item daftar dipilih, ya.
SteveCav
14

Anda bisa menggunakan DataTriggerkelas di Microsoft.Expression.Interactions.dll yang datang dengan Expression Blend .

Contoh kode:

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

Dengan menggunakan metode ini Anda dapat memicu GreaterThandan LessThanjuga. Untuk menggunakan kode ini, Anda harus mereferensikan dua dll:

System.Windows.Interactivity.dll

Microsoft.Expression.Interactions.dll

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

Saya hanya menggunakan logika invers di sini ... mengatur stackpanel saya menjadi tak terlihat ketika comboitem saya tidak terisi, ia bekerja dengan cukup baik!

aromore
sumber
6

Berhenti! Tidak ada konverter! Saya tidak ingin "menjual" perpustakaan orang ini, tetapi saya benci fakta melakukan konverter setiap kali saya ingin membandingkan barang di XAML.

Jadi dengan perpustakaan ini: https://github.com/Alex141/CalcBinding

Anda dapat melakukannya [dan banyak lagi]:

Pertama, Dalam deklarasi windows / userControl:

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

kemudian, di blok teks

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

Bagian ajaibnya adalah conv: Binding 'MYValue == null' . Bahkan, Anda dapat mengatur kondisi apa pun yang Anda inginkan [lihat dokumen].

perhatikan bahwa saya bukan penggemar pihak ketiga. tetapi pustaka ini gratis, dan sedikit dampak (tambahkan saja 2 .dll ke proyek).

Simon
sumber
5

Solusi saya adalah dalam contoh DataContext (atau ViewModel jika menggunakan MVVM). Saya menambahkan properti yang mengembalikan true jika kondisi Not Null yang saya inginkan terpenuhi.

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

dan ikat DataTrigger ke properti di atas. Catatan: Di VB.NET pastikan untuk menggunakan operator If dan NOT fungsi IIf, yang tidak berfungsi dengan objek Null. Maka XAML adalah:

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

Jika Anda mencari solusi yang tidak menggunakan IValueConverter, Anda selalu bisa menggunakan mekanisme di bawah ini

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

Konverter:

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

Mengikat:

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

Anda dapat menggunakan konverter atau membuat properti baru di ViewModel Anda seperti itu:

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

dan gunakan:

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