DataTrigger ที่ค่าไม่เป็นโมฆะ?


162

ฉันรู้ว่าฉันสามารถตั้งค่าที่ตรวจสอบเพื่อดูว่าค่าเป็นโมฆะและทำอะไร ตัวอย่าง:

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

แต่ฉันจะตรวจสอบค่า "ไม่" ... เหมือนใน "NOT NULL" หรือ "NOT = 3" ได้อย่างไร เป็นไปได้ใน XAML หรือไม่

ผลลัพธ์:ขอบคุณสำหรับคำตอบของคุณ ... ฉันรู้ว่าฉันสามารถใช้เครื่องมือแปลงค่า (ซึ่งหมายความว่าฉันจะต้องใส่รหัสและนั่นจะไม่ใช่ XAML ที่บริสุทธิ์อย่างที่ฉันหวังไว้) อย่างไรก็ตามนั่นจะตอบคำถามที่มีประสิทธิภาพ "ไม่" คุณไม่สามารถทำได้ใน XAML บริสุทธิ์ อย่างไรก็ตามคำตอบที่เลือกอาจแสดงวิธีที่ดีที่สุดในการสร้างฟังก์ชั่นประเภทนั้น หาดี

คำตอบ:


42

ฉันพบข้อ จำกัด ที่คล้ายกันกับ DataTriggers และดูเหมือนว่าคุณสามารถตรวจสอบความเท่าเทียมกันเท่านั้น สิ่งที่ใกล้เคียงที่สุดที่ฉันเคยเห็นซึ่งอาจช่วยให้คุณเป็นเทคนิคสำหรับการเปรียบเทียบประเภทอื่นนอกเหนือจากความเท่าเทียมกัน

โพสต์บล็อกนี้อธิบายวิธีทำการเปรียบเทียบเช่น LT, GT และอื่น ๆ ใน DataTrigger

ข้อ จำกัด ของ DataTrigger สามารถทำงานได้ในระดับหนึ่งโดยใช้ตัวแปลงเพื่อนวดข้อมูลเป็นค่าพิเศษที่คุณสามารถเปรียบเทียบกับได้ตามที่แนะนำในคำตอบของ Robert Macnee


10
น่าสนใจพอที่ DataTrigger มีเขตข้อมูลภายในซึ่งควบคุมว่าจะทดสอบความเท่าเทียมกันหรือไม่เท่ากัน น่าเสียดายที่คุณต้องทำการไตร่ตรองอย่างสมเหตุสมผลเพื่อไปยังฟิลด์ที่กำหนด ปัญหาคือมันอาจแตกใน. net รุ่นถัดไป
Caleb Vear

154

คุณสามารถใช้ 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>

โดยที่ IsNullConverter ถูกกำหนดไว้ที่อื่น (และ Conv ถูกตั้งค่าให้อ้างอิงเนมสเปซของมัน):

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

วิธีแก้ปัญหาทั่วไปที่มากกว่านั้นก็คือการใช้ IValueConverter ที่ตรวจสอบความเท่าเทียมกันกับ ConverterParameter ดังนั้นคุณจึงสามารถตรวจสอบอะไรก็ได้และไม่ใช่แค่ null


6
ฉันคิดว่าคุณสามารถทำให้ตัวแปลงเป็นแบบทั่วไปได้มากขึ้นและใช้ ConverterParameter เพื่อส่งผ่านค่าเพื่อเปรียบเทียบกับ (เพื่อสนับสนุนทั้งการเปรียบเทียบกับค่าที่ไม่เป็นโมฆะและไม่ใช่ 3)
J c

สิ่งนี้ใช้ได้กับฉัน - การใช้ทริกเกอร์หลายตัวทำให้มันดีและทรงพลัง
Bertie

149

นี่เป็นบิตของการโกง แต่ฉันเพิ่งตั้งค่ารูปแบบเริ่มต้นแล้วแทนที่ด้วยการใช้ DataTrigger หากค่าเป็นโมฆะ ...

  <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
นี่เป็นทางออกที่ดีที่สุดสำหรับสถานการณ์ของฉัน! ขอบคุณที่ให้คำตอบ!
Scott

14
ฉันไม่คิดว่านี่เป็นแฮ็คคุณต้องทำสิ่งนี้บ่อยครั้ง และนี่คือวิธีที่สะอาดที่สุดในการทำเช่นนี้
akjoshi

3
Setter เริ่มต้นสามารถใช้งานได้โดยไม่มีแท็ก Style.Setter
Naser Asadi

1
แค่ตั๋ว! ฉันใส่ค่าเริ่มต้นในการควบคุมที่เป็นเจ้าของสไตล์และไม่สามารถหาสาเหตุที่ทำให้รูปแบบของฉันแทนที่ :-) ขอบคุณ!
Riegardt Steyn

2
วิธีที่ดีกว่าตอบแล้วใช้ตัวแปลง ... ง่ายและสะอาด
DasDas

27

เปรียบเทียบกับ null (ดังที่ Michael Noonan พูด):

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

เปรียบเทียบกับไม่ใช่ null (ไม่มีตัวแปลง):

<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
นี่คือคำตอบที่ตรงไปตรงมามากที่สุด ฉันชอบมัน!
TimothyP

15

ฉันใช้ตัวเลือกนี้เพื่อเปิดใช้งานปุ่มเฉพาะเมื่อมีการเลือกรายการมุมมอง (เช่นไม่ใช่โมฆะ):

<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
บางครั้งวิธีแก้ปัญหาที่ง่ายที่สุดถูกซ่อนอยู่ในมุมมองที่ชัดเจน ฉันเชื่อว่ารหัส XAML ถูกตีความจากบนลงล่าง ด้วยวิธีนี้ปุ่มจะเปิดใช้งานก่อนจากนั้นปิดใช้งานหากไม่มีองค์ประกอบใน listview ถูกเลือก แต่โปรดบอกฉันว่าสไตล์มีการปรับปรุงเมื่อรายการถูกเลือกใน listview หรือไม่
froeschli

ปุ่มถูกเปิดใช้งานเมื่อมีการเลือกรายการรายการใช่
SteveCav

14

คุณสามารถใช้DataTriggerเรียนในMicrosoft.Expression.Interactions.dllที่มาพร้อมกับExpression Blend

ตัวอย่างโค้ด:

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

การใช้วิธีนี้คุณสามารถกระตุ้นGreaterThanและต่อต้านได้LessThanเช่นกัน ในการใช้รหัสนี้คุณควรอ้างอิงของ 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>

ฉันเพิ่งใช้ตรรกะผกผันที่นี่ ... การตั้งค่าสแต็คพาเนลของฉันเป็นล่องหนเมื่อคอมโบของฉันไม่ได้บรรจุมันทำงานได้ดี!


6

หยุด! ไม่มีตัวแปลง! ฉันไม่ต้องการที่จะ "ขาย" ห้องสมุดของผู้ชายคนนี้ แต่ฉันเกลียดความจริงที่ว่าตัวแปลงทุกครั้งที่ฉันต้องการเปรียบเทียบเนื้อหาใน XAML

ดังนั้นด้วยไลบรารีนี้: https://github.com/Alex141/CalcBinding

คุณสามารถทำได้ [และอีกมากมาย]:

ครั้งแรกในการประกาศของ windows / userControl:

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

จากนั้นในเท็กซ์บล็อค

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

ส่วนมายากลเป็นแปลง: ผูกพัน 'MYValue == null' ในความเป็นจริงคุณสามารถกำหนดเงื่อนไขใด ๆ ที่คุณต้องการ [ดูเอกสาร]

โปรดทราบว่าฉันไม่ใช่แฟนของบุคคลที่สาม แต่ไลบรารี่นี้ไม่มีค่าใช้จ่ายและมีผลกระทบน้อย (เพียงเพิ่ม 2. dll ลงในโครงการ)


5

โซลูชันของฉันอยู่ในอินสแตนซ์ DataContext (หรือ ViewModel ถ้าใช้ MVVM) ฉันเพิ่มคุณสมบัติที่คืนค่าจริงหากเงื่อนไขไม่เป็นโมฆะที่ต้องการ

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

และผูก DataTrigger กับคุณสมบัติข้างต้น หมายเหตุ: ใน VB.NET ต้องแน่ใจว่าใช้โอเปอเรเตอร์หากไม่ใช่ฟังก์ชัน IIf ซึ่งไม่สามารถใช้กับวัตถุ Null ได้ จากนั้น XAML คือ:

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

3

หากคุณกำลังมองหาโซลูชันที่ไม่ได้ใช้ IValueConverter คุณสามารถไปที่กลไกด้านล่างได้ตลอดเวลา

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

ผูกพัน:

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

2

คุณสามารถใช้ตัวแปลงหรือสร้างคุณสมบัติใหม่ใน ViewModel ของคุณเช่นนั้น:

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

และใช้มัน:

<DataTrigger Binding="{Binding SomeField}" Value="{Binding CanDoIt}">
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.