【问题标题】:WPF Property Target for Style Trigger样式触发器的 WPF 属性目标
【发布时间】:2014-10-08 15:00:42
【问题描述】:

我正在定义一个自定义 DataGridTextColumn,并在 DataGrid 上添加了“Tag”属性,如下所示

<local:DataGridTextColumn Binding="{Binding Path=Company}" 
                          Header="Company" 
                          Tag="String" 
                          IsReadOnly="True" />

我已经定义了一些资源 XAML 来控制网格的呈现,但是我遇到了一个问题。我想根据使用触发器的“Tag”属性的值在 DataGridColumnHeader 上呈现自定义 ContextMenu。但是,我找不到从样式中引用列“标签”值的方法。我已经尝试过 DataTriggers 和常规 Triggers。

<Style TargetType="{x:Type DataGridColumnHeader}">
<Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:DataGridTextColumn}, Path=Tag}" Value="String">
            <Setter Property="ContextMenu" Value="{StaticResource ColumnHeaderContextMenuString}" />
        </DataTrigger>
        <Trigger Property="Tag" Value="Int">
            <Setter Property="ContextMenu" Value="{StaticResource ColumnHeaderContextMenuInt}" />
        </Trigger>
        <Trigger Property="Tag" Value="DateTime">
            <Setter Property="ContextMenu" Value="{StaticResource ColumnHeaderContextMenuDateTime}" />
        </Trigger>
    </Style.Triggers>

【问题讨论】:

    标签: c# .net wpf xaml wpfdatagrid


    【解决方案1】:

    不要在设计时强制样式决策,通过更改 Tag 属性在运行时应用样式。为什么?

    如果您可以在设计时更改标签,则可以让列标题遵循特定的样式。

    目前尚不清楚为什么需要 Rube Goldberg 方法来设置设计时样式。

    【讨论】:

    • Mine 是一个自定义 DataGrid 类,可应用于许多 DataGrid。以上是在应用于整个应用程序的主题中设置的更大样式的一部分。我认为这是 XAML 方式。您有什么建议可以带来更好的解决方案吗?
    • @BigBadOwl 我知道有必要根据不同的情况进行更改。但是风格是继承的。如果页面 X 需要样式 Y,它应该 override 页面上的样式(甚至网格级别到数据网格的实际实例)并且当数据网格接受它时,它将按照 pages我>需要。 HTH
    【解决方案2】:

    首先,您必须从样式化的DataGridColumnHeader 元素到基础列。从那里,您可以深入了解Tag。试试这个:

    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Column.Tag}" 
                 Value="String">
        <Setter Property="ContextMenu"
                Value="{StaticResource ColumnHeaderContextMenuString}" />
    </DataTrigger>
    

    但是,如果您要使用标题样式,为什么不简单地为每个基础数据类型设置一个样式,并相应地设置每一列的HeaderStyle?如果每个标题样式仅适用于单一数据类型,则不需要触发器。

    【讨论】:

    • 谢谢迈克。恐怕这对我不起作用。我正在尝试使样式通用,我可以将其应用于多个 DataGrid,而无需单独设置每个样式。
    • 奇数。绑定错误是什么?我假设您的网格基于标准 WPF 网格,所以它应该具有 Column 属性,是吗?
    • 是的,它扩展了 DataGrid。
    【解决方案3】:

    DataGridColumnHeader 基类型中没有 Tag 属性。 使用:&lt;Style TargetType="{x:Type local:DataGridTextColumn}"&gt; 和简单的触发器

    【讨论】:

      【解决方案4】:

      好吧!您的工作一切顺利,但需要一点概念来解决问题:

      核心概念:(可选读物)DataGridTextColumn的Header属性处理其中的两种数据,一种是Type:string,一种是Type:DataGridColumnHeader。与许多其他框架属性相比,字符串类型值在编译时不会转换为其他类型。所以设置值 Header="Company" 保留在 sting 数据类型中,设置 ContextMenu 属性意义不大。

      有很多解决方案/方法可以解决此问题,但我发布的答案与您的方法相近……。

      解决方案: 设置样式,但设置 header 属性如下:

       <DataGridTextColumn x:Name="CompanyColumn" Width="*" Binding="{Binding Company}">
           <DataGridTextColumn.Header>
               <DataGridColumnHeader Content="Company" Tag="String"/>
           </DataGridTextColumn.Header>
       </DataGridTextColumn>
      

      为了支持其他访问者,我发送了完整的代码以了解这种方法。

      <Window x:Class="AnswerNo1.SolutionA" 
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:System="clr-namespace:System;assembly=mscorlib"
          Title="SolutionA" Height="250" Width="400">
      <Window.Resources>
          <ContextMenu x:Key="ColumnHeaderContextMenuString">
              <MenuItem Header="_Sentence case."/>
              <MenuItem Header="_lowercase"/>
              <MenuItem Header="_UPPERCASE"/>
              <MenuItem Header="_Capitalize Each Word"/>
              <MenuItem Header="_tOGGLE cASE"/>
          </ContextMenu>
          <ContextMenu x:Key="ColumnHeaderContextMenuInt">
              <MenuItem Header="Show _SUM"/>
              <MenuItem Header="Show _Mean"/>
              <MenuItem Header="Show Standard Deviation"/>
              <MenuItem Header="Subtract All Form ..."/>
              <MenuItem Header="Toggle Sign"/>
          </ContextMenu>
          <ContextMenu x:Key="ColumnHeaderContextMenuDateTime">
              <MenuItem Header="Show Time Graph"/>
              <MenuItem Header="Show Minimum Data"/>
              <MenuItem Header="Show Maximum Data"/>
              <MenuItem Header="Show Mode Day"/>
              <MenuItem Header="Sort by day name"/>
          </ContextMenu>
          <Style TargetType="{x:Type DataGridColumnHeader}">
              <Style.Triggers>
                  <Trigger Property="Tag" Value="String">
                      <Setter Property="ContextMenu" Value="{StaticResource ColumnHeaderContextMenuString}" />
                  </Trigger>
                  <Trigger Property="Tag" Value="Int">
                      <Setter Property="ContextMenu" Value="{StaticResource ColumnHeaderContextMenuInt}" />
                  </Trigger>
                  <Trigger Property="Tag" Value="DateTime">
                      <Setter Property="ContextMenu" Value="{StaticResource ColumnHeaderContextMenuDateTime}" />
                  </Trigger>
              </Style.Triggers>
          </Style>
      </Window.Resources>
      <Grid>
          <Grid.RowDefinitions>
              <RowDefinition/>
              <RowDefinition Height="Auto"/>
          </Grid.RowDefinitions>
          <DataGrid x:Name="YourDataGrid" AutoGenerateColumns="False" Margin="3">
              <DataGrid.Columns>
                  <DataGridTextColumn x:Name="CompanyColumn" Width="*" Binding="{Binding Company}">
                      <DataGridTextColumn.Header>
                          <DataGridColumnHeader Content="Company" Tag="String"/>
                      </DataGridTextColumn.Header>
                  </DataGridTextColumn>
                  <DataGridTextColumn x:Name="ReputationColumn" Width="*" Binding="{Binding Reputation}">
                      <DataGridTextColumn.Header>
                          <DataGridColumnHeader Content="Reputation" Tag="Int"/>
                      </DataGridTextColumn.Header>
                  </DataGridTextColumn>
                  <DataGridTextColumn x:Name="SetupDateColumn" Width="*" Binding="{Binding SetupDate}">
                      <DataGridTextColumn.Header>
                          <DataGridColumnHeader Content="Setup Date" Tag="DateTime"/>
                      </DataGridTextColumn.Header>
                  </DataGridTextColumn>
              </DataGrid.Columns>
          </DataGrid>
          <Grid Grid.Row="1">
              <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="auto"/>
                  <ColumnDefinition/>
              </Grid.ColumnDefinitions>
              <Label Content="Tag for 1st Column: "/>
              <ComboBox Grid.Column="1" SelectedItem="{Binding Header.Tag, ElementName=CompanyColumn}" >
                  <System:String>String</System:String>
                  <System:String>Int</System:String>
                  <System:String>DateTime</System:String>
              </ComboBox>
          </Grid>
      </Grid>
      

      【讨论】:

      • 请只发布与问题相关的任何内容,不要发布额外的阅读材料。
      • @Mohammad 感谢您的提示!
      【解决方案5】:

      我最终不得不为此编写一个非 XAML 解决方案。这是获得具有内容感知上下文菜单的可重用 DataGrid 的唯一方法。每次添加网格时,其他解决方案都需要大量配置(而且我无法让它们工作)。

      【讨论】:

        猜你喜欢
        • 2010-10-15
        • 1970-01-01
        • 2013-02-16
        • 1970-01-01
        • 1970-01-01
        • 2012-06-02
        • 2011-01-27
        • 2012-04-23
        相关资源
        最近更新 更多