将 DataTrigger 值绑定到此 DataTemplate 实例

Posted

技术标签:

【中文标题】将 DataTrigger 值绑定到此 DataTemplate 实例【英文标题】:Binding a DataTrigger value to this instance of DataTemplate 【发布时间】:2021-11-30 22:05:52 【问题描述】:

我有一个ListView,其项目由ItemTemplate 表示,如下所示:

<ListView dependencyObjects:InterestingItem.Interesting="Binding InterestingItem"
          ItemsSource="Binding Quotations" >
    <ListView.ItemTemplate>
        <DataTemplate>
            <Border>
                <Grid>
                    <StackPanel x:Name="NotImportant">
                    </StackPanel>

                    <Grid x:Name="HiddenGrid"
                          Background="Red"
                          Visibility="Hidden" >
                        <Grid.Style>
                            <Style TargetType="Grid">
                                <Style.Triggers>
                                    <Grid.Triggers>
                                        <DataTrigger Binding="Binding Path=DataContext.InterestingItem, 
                                                               RelativeSource=RelativeSource AncestorType=x:Type ListView " 
                                                               Value="*this instance here*!">
                                            <Setter Property="Visibility" Value="Visible" />
                                        </DataTrigger>
                                    </Grid.Triggers>
                                </Style.Triggers>
                            </Style>
                        </Grid.Style>
                    </Grid>
                </Grid>
            </Border>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

ListView 有一个附加属性InterestingItem,它是ListView 中的一项。

我无法连接的是当InterestingItem 与其中一项相同时,第二个Grid 应该变得可见。

我不希望更改并绑定到列表中的实际对象 - 而是让ListView 控制要更改的项目。

我需要的DataTrigger中的Value是什么?

【问题讨论】:

【参考方案1】:

我需要的 DataTrigger 中的值是什么?

恐怕 XAML 不支持 C# 中的 this 关键字。

您可以使用MultiBindingIMultiValueConverter 实现来确定项目是否相等:

<Grid x:Name="HiddenGrid" Background="Red">
    <Grid.Style>
        <Style TargetType="Grid">
            <Setter Property="Visibility" Value="Hidden" />
            <Style.Triggers>
                <DataTrigger Value="True">
                    <DataTrigger.Binding>
                        <MultiBinding>
                            <MultiBinding.Converter>
                                <local:MultiConverter />
                            </MultiBinding.Converter>
                            <Binding Path="Binding Path=DataContext.InterestingItem, 
                                        RelativeSource=RelativeSource AncestorType=x:Type ListView " />
                            <Binding Path="Binding" />
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Visibility" Value="Visible" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

转换器:

public class MultiConverter : IMultiValueConverter

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) =>
        values != null && values.Length == 2 && values[0] == values[1];

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
        throw new NotSupportedException();

请注意,如果您希望能够使用 Style 设置器覆盖该值,则不能将 GridVisibility 属性设置为本地值。

 <Grid x:Name="HiddenGrid" Background="Red" Visibility="Hidden">

【讨论】:

【参考方案2】:

您的 XAML 中存在多个问题,并且在概念上会阻止它工作。

要绑定附加属性,您必须使用正确的带括号的语法。

Path="Binding (local:InterestingItem.Interesting), RelativeSource=RelativeSource AncestorType=x:Type ListView"

请参阅Binding path syntax 文档以供参考。

Triggers 属性只支持EventTriggers,请参阅FrameworkElement.Triggers

注意,在一个元素上建立的触发器集合只支持EventTrigger,不支持属性触发器(Trigger)。如果您需要属性触发器,则必须将它们放在样式或模板中,然后直接通过 Style 属性或通过隐式样式引用间接将该样式或模板分配给元素。

您不能绑定DataTriggerValue 属性,因为它不是依赖属性。

您当然可以更改绑定类型以公开指示它是否为特殊对象的属性,并使用 DataTrigger 在 XAML 中绑定该属性,类似于此(其中 IsSpecial 是新的 bool属性)。

<Grid x:Name="HiddenGrid"
      Background="Red">
   <TextBlock Text="Hidden Grid"/>
   <Grid.Style>
      <Style TargetType="x:Type Grid">
         <Setter Property="Visibility" Value="Hidden"/>
         <Style.Triggers>
            <DataTrigger Binding="Binding IsSpecial" Value="True">
               <Setter Property="Visibility" Value="Visible" />
            </DataTrigger>
         </Style.Triggers>
      </Style>
   </Grid.Style>
</Grid>

如果您想坚持当前的方法,您可以创建一个自定义IMultiValueConverter,以启用绑定多个属性。它将检查所有绑定值是否相等,否则返回Visibility.VisibleVisibility.Hidden。此示例使用 Linq 来检查这一点并支持绑定任意数量的值,但还有许多其他选项。

public class EqualityToVisibilityConverter : IMultiValueConverter

   public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
   
      if (values is null || values.Length < 2)
         return Binding.DoNothing;

      return values.Distinct().Count() == 1 ? Visibility.Visible : Visibility.Hidden;
   

   public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
   
      throw new InvalidOperationException();
   

接下来,在ListView 的资源或范围内的任何其他资源字典中实例化转换器,并将GridVisibility 属性绑定到当前项(仅&lt;Binding/&gt;)和附加属性local:InterestingItem.InterestingMultiBinding 使用转换器将它们转换为 Visibility

<ListView local:InterestingItem.Interesting="Binding InterestingItem"
          ItemsSource="Binding Quotations">
   <ListView.Resources>
      <local:EqualityToVisibilityConverter x:Key="EqualityToVisibilityConverter"/>
   </ListView.Resources>
   <ListView.ItemTemplate>
      <DataTemplate>
         <Border>
            <Grid>
               <StackPanel x:Name="NotImportant">
                  <TextBlock Text="Not Important"/>
               </StackPanel>
               <Grid x:Name="HiddenGrid"
                     Background="Red">
                  <Grid.Visibility>
                     <MultiBinding Converter="StaticResource EqualityToVisibilityConverter">
                        <Binding/>
                        <Binding Path="(local:InterestingItem.Interesting)"
                                 RelativeSource="RelativeSource AncestorType=x:Type ListView"/>
                     </MultiBinding>
                  </Grid.Visibility>
                  <TextBlock Text="Hidden Grid"/>
               </Grid>
            </Grid>
         </Border>
      </DataTemplate>
   </ListView.ItemTemplate>
</ListView>

这里还有两点需要注意。我添加了两个虚拟TextBlocks,否则结果将不可见,因为面板是空的。用您的内容替换它们。此外,StackPanelGrid 在父 Grid 中都重叠,我不知道这是不是故意的,但您可以通过添加行或列并将元素移动到那里来更改它。

【讨论】:

以上是关于将 DataTrigger 值绑定到此 DataTemplate 实例的主要内容,如果未能解决你的问题,请参考以下文章

DataTrigger.ExistActions 未触发绑定值“null”

将 DataTrigger `Value` 绑定到 `V Model`

DataGrid RowStyle - DataTrigger 中的绑定值

将 DataTrigger 绑定到复选框的 IsChecked 属性

wpf datatrigger绑定到方法

绑定属性上的 DataTrigger