【问题标题】:Binding a DataTrigger value to this instance of DataTemplate将 DataTrigger 值绑定到此 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是什么?

【问题讨论】:

    标签: wpf xaml listview data-binding datatrigger


    【解决方案1】:

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

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

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

    <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 设置器覆盖该值,则不能将 Grid 的 Visibility 属性设置为本地值。

     <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 属性或通过隐式样式引用间接将该样式或模板分配给元素。

      • 您不能绑定DataTrigger 的Value 属性,因为它不是依赖属性。

      您当然可以更改绑定类型以公开指示它是否为特殊对象的属性,并使用 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.Visible 或Visibility.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 的资源或范围内的任何其他资源字典中实例化转换器,并将Grid 的Visibility 属性绑定到当前项(仅&lt;Binding/&gt;)和附加属性local:InterestingItem.Interesting 和 MultiBinding 使用转换器将它们转换为 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,否则结果将不可见,因为面板是空的。用您的内容替换它们。此外,StackPanel 和 Grid 在父 Grid 中都重叠,我不知道这是不是故意的,但您可以通过添加行或列并将元素移动到那里来更改它。

      【讨论】:

        猜你喜欢
        • 2014-05-28
        • 1970-01-01
        • 2018-07-29
        • 2012-01-09
        • 2014-08-26
        • 2018-09-30
        • 1970-01-01
        • 2013-06-04
        • 1970-01-01
        相关资源
        最近更新 更多