DataTrigger nơi giá trị KHÔNG phải là null?


162

Tôi biết rằng tôi có thể tạo một setter kiểm tra xem giá trị có phải là NULL không và làm gì đó. Thí dụ:

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

Nhưng làm cách nào tôi có thể kiểm tra giá trị "không" ... như trong "KHÔNG NULL" hoặc "KHÔNG = 3"? Điều đó có thể có trong XAML không?

Kết quả: Cảm ơn câu trả lời của bạn ... Tôi biết tôi có thể thực hiện một trình chuyển đổi giá trị (có nghĩa là tôi sẽ phải nhập mã và đó không phải là XAML thuần túy như tôi mong muốn). Tuy nhiên, điều đó trả lời cho câu hỏi "không" một cách hiệu quả mà bạn không thể làm điều đó trong XAML thuần túy. Câu trả lời được chọn, tuy nhiên, có lẽ là cách tốt nhất để tạo ra loại chức năng đó. Tìm tốt

Câu trả lời:


42

Tôi gặp phải một giới hạn tương tự với DataTriggers và dường như bạn chỉ có thể kiểm tra sự bằng nhau. Điều gần nhất tôi từng thấy có thể giúp bạn là một kỹ thuật để thực hiện các loại so sánh khác ngoài bình đẳng.

Bài đăng trên blog này mô tả cách thực hiện các so sánh, chẳng hạn như LT, GT, v.v. trong DataTrigger.

Hạn chế này của DataTrigger có thể được khắc phục ở một mức độ nào đó bằng cách sử dụng Trình chuyển đổi để xoa bóp dữ liệu thành một giá trị đặc biệt mà sau đó bạn có thể so sánh với, như được đề xuất trong câu trả lời của Robert Macnee.


10
Điều thú vị là DataTrigger thực sự có một trường bên trong để kiểm soát xem nó có kiểm tra sự bằng nhau hay không bằng nhau. Thật không may, bạn phải thực hiện một số lượng phản ánh hợp lý để đến trường bắt buộc. Vấn đề là nó có thể bị hỏng trong phiên bản tiếp theo của .net.
Caleb Vear

154

Bạn có thể sử dụng IValueConverter cho việc này:

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

Trong đó IsNullConverter được định nghĩa ở nơi khác (và đối tượng được đặt để tham chiếu không gian tên của nó):

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

Một giải pháp tổng quát hơn sẽ là triển khai IValueConverter để kiểm tra sự bằng nhau với ConverterParameter, do đó bạn có thể kiểm tra mọi thứ và không chỉ null.


6
Tôi cho rằng bạn có thể làm cho trình chuyển đổi chung chung hơn một chút và sử dụng ConverterParameter để chuyển vào một giá trị để so sánh (để hỗ trợ cả so sánh với KHÔNG null và KHÔNG 3.
J c

Điều này có tác dụng đối với tôi - sử dụng Đa kích hoạt, nó làm cho nó hay và mạnh mẽ.
Bertie

149

Đây là một chút gian lận nhưng tôi chỉ đặt một kiểu mặc định và sau đó ghi đè nó bằng DataTrigger nếu giá trị là 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
Đây là giải pháp tốt nhất cho kịch bản của tôi! Cảm ơn đã cung cấp câu trả lời này!
Scott

14
Tôi không nghĩ rằng đây là một hack, bạn cần phải làm điều này rất nhiều thời gian; và đây là cách sạch nhất để làm điều này.
akjoshi

3
Setter mặc định có thể được sử dụng mà không có thẻ Style.Setter.
Naser Asadi

1
Chỉ cần vé! Tôi tiếp tục đặt mặc định trong điều khiển sở hữu Kiểu và không thể hiểu tại sao nó lại ghi đè lên kiểu của tôi :-) Cảm ơn bạn!
Heliac

2
cách tốt hơn để trả lời sau đó sử dụng một công cụ chuyển đổi ... đơn giản và sạch sẽ.
DasDas

27

So sánh với null (Như Michael Noonan đã nói):

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

So sánh với không null (không có bộ chuyển đổi):

<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
Đây là câu trả lời thẳng về phía trước nhất. Tôi thích nó!
TimothyP

15

Tôi đang sử dụng điều này để chỉ kích hoạt một nút nếu một mục listview được chọn (nghĩa là không 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
Đôi khi giải pháp đơn giản nhất được ẩn trong chế độ xem rõ ràng. Tôi tin rằng, mã XAML được diễn giải từ trên xuống dưới. Bằng cách đó, nút đầu tiên sẽ được bật và sau đó bị vô hiệu hóa nếu không có phần tử nào trong listview được chọn. Nhưng xin vui lòng cho tôi biết, phong cách có được cập nhật sau khi một mục được chọn trong listview không?
froeschli

Nút được bật khi một mục danh sách được chọn, có.
SteveCav

14

Bạn có thể sử dụng DataTriggerlớp trong Microsoft.Expression.Interilities.dll đi kèm với Expression Blend .

Mẫu mã:

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

Sử dụng phương pháp này bạn có thể kích hoạt GreaterThanLessThanquá. Để sử dụng mã này, bạn nên tham khảo hai dll:

System.Windows.Interactivity.dll

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

Tôi chỉ sử dụng logic nghịch đảo ở đây ... đặt stackpanel của mình thành vô hình khi combo của tôi không được điền, nó hoạt động khá tốt!


6

Dừng lại! Không có công cụ chuyển đổi! Tôi không muốn "bán" thư viện của anh chàng này, nhưng tôi ghét thực tế là làm công cụ chuyển đổi mỗi khi tôi muốn so sánh các công cụ trong XAML.

Vì vậy, với thư viện này: https://github.com/Alex141/CalcBinding

bạn có thể làm điều đó [và nhiều hơn nữa]:

Đầu tiên, trong phần khai báo của windows / userControl:

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

sau đó, trong 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>

Phần ma thuật là phần kết: Binding 'MYValue == null' . Trong thực tế, bạn có thể đặt bất kỳ điều kiện nào bạn muốn [nhìn vào tài liệu].

lưu ý rằng tôi không phải là một fan hâm mộ của bên thứ ba. nhưng thư viện này là miễn phí và ít ảnh hưởng (chỉ cần thêm 2 đậm vào dự án).


5

Giải pháp của tôi là trong trường hợp DataContext (hoặc ViewModel nếu sử dụng MVVM). Tôi thêm một thuộc tính trả về true nếu điều kiện Not Null tôi muốn được đáp ứng.

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

và liên kết DataTrigger với thuộc tính trên. Lưu ý: Trong VB.NET, hãy chắc chắn sử dụng toán tử If và KHÔNG là hàm IIf, không hoạt động với các đối tượng Null. XAML là:

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

3

Nếu bạn đang tìm kiếm một giải pháp không sử dụng IValueConverter, bạn luôn có thể đi theo cơ chế dưới đây

       <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

Chuyển đổi:

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

Ràng buộc:

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

2

Bạn có thể sử dụng trình chuyển đổi hoặc tạo thuộc tính mới trong ViewModel của mình như thế:

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

và sử dụng nó:

<DataTrigger Binding="{Binding SomeField}" Value="{Binding CanDoIt}">
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.