WPF数据表格行背景颜色的样式触发器被交替行背景刷覆盖

11
我有一个WPF DataGrid,它有一个AlternatingRowBackground画刷,用于配置交替着色的行。我想在鼠标悬停时突出显示当前行,但是样式触发器似乎输给了AlternatingRowBackground画刷。在不使用AlternatingRowBackground画刷绘制的行上,我可以在鼠标悬停时获得期望的行颜色。这是Windows.Resources中的样式:
<Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <Style TargetType="{x:Type DataGridRow}">
                <Style.Triggers>
                    <Trigger Property="IsMouseOver"
                             Value="True">
                        <Setter Property="Background"
                                Value="Red" />
                        <Setter Property="FontWeight"
                                Value="ExtraBold" />
                        <Setter Property="Height"
                                Value="20" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ResourceDictionary>
    </Window.Resources>

这里是DataGrid:

    <DataGrid Margin="25,15,25,0"
              VerticalAlignment="Top"
              ItemsSource="{Binding DocumentTypeList}"
              AutoGenerateColumns="False"
              Height="500"
              AlternationCount="2"
              FrozenColumnCount="2"
              AlternatingRowBackground="{DynamicResource AlternatingRow}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Abbreviation}"
                                Header="Abbreviation" />
            <DataGridTextColumn Binding="{Binding Title}"
                                Header="Title" />

            <DataGridTextColumn Binding="{Binding Fee}"
                                Header="Fee" />
            <DataGridTextColumn Binding="{Binding SpecialInstructions}"
                                Header="Special Instructions" />
        </DataGrid.Columns>
    </DataGrid>

有没有一种方法可以宣布绝对的赢家?问题是否涉及等级问题?在我看来,AlternatingRowBackground笔刷获胜,因为它直接关联到声明中最具体的部分。

更新:根据@Val的指导,以下是正确的语法:

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Skins/MainSkin.xaml" />
        </ResourceDictionary.MergedDictionaries>
        <Style TargetType="{x:Type DataGridRow}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver"
                         Value="True">
                    <Setter Property="Background"
                            Value="Red" />
                    <Setter Property="FontWeight"
                            Value="ExtraBold" />
                    <Setter Property="Height"
                            Value="20" />
                </Trigger>
            </Style.Triggers>
        </Style>
        <Style TargetType="{x:Type DataGrid}">
            <Setter Property="AlternatingRowBackground" Value="{DynamicResource AlternatingRow}"/>
        </Style>
    </ResourceDictionary>
</Window.Resources>

数据网格(不包括交替行背景刷):

<DataGrid Margin="25,15,25,0"
              VerticalAlignment="Top"
              ItemsSource="{Binding DocumentTypeList}"
              AutoGenerateColumns="False"
              Height="500"
              AlternationCount="2"
              FrozenColumnCount="2">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Abbreviation}"
                                Header="Abbreviation" />
            <DataGridTextColumn Binding="{Binding Title}"
                                Header="Title" />

            <DataGridTextColumn Binding="{Binding Fee}"
                                Header="Fee" />
            <DataGridTextColumn Binding="{Binding SpecialInstructions}"
                                Header="Special Instructions" />
        </DataGrid.Columns>
    </DataGrid>
2个回答

20

有两种方法可以实现这个目标,但都不是特别明显。由于DataGridRow把背景属性(在代码中)从父DataGrid传递给行中的本地值,正如您所指出的,它将优先于触发器设置的值。

第一种(也是最简单的)方法是不使用AlternatingRowBackground或RowBackground,而是使用触发器来交替设置背景颜色,就像Val建议的那样。他的示例不完整,不能直接使用。正确的样式和用法应该如下所示。请注意,您需要在DataGrid上设置AlternationCount,否则行将永远不会获得交替索引。

<DataGrid AlternationCount="2">
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="Background" Value="White"/>
            <Setter Property="FontWeight" Value="Normal"/>
            <Style.Triggers>
                <Trigger Property="AlternationIndex" Value="1">
                    <Setter Property="Background" Value="Wheat"/>
                    <Setter Property="FontWeight" Value="Bold"/>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="Khaki"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>
</DataGrid>
第二种选择是使用VisualStateManager。这可以让你更好地控制不同的可视状态,但它会更冗长。幸运的是,使用Blend复制默认控件模板非常容易。大部分内容都不变,除了MouseOver状态中的Storyboard,并且我在selectiveScrollingGrid上设置了背景色。抱歉换行了,但像我说的,它有点冗长。
<DataGrid AlternationCount="2" AlternatingRowBackground="Wheat">
  <DataGrid.RowStyle>
    <Style TargetType="DataGridRow">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="DataGridRow">
            <Border x:Name="DGR_Border" 
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    SnapsToDevicePixels="True">
              <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                  <VisualState x:Name="Normal"/>
                  <VisualState x:Name="Normal_AlternatingRow"/>
                  <VisualState x:Name="Unfocused_Editing"/>
                  <VisualState x:Name="Normal_Editing"/>
                  <VisualState x:Name="Unfocused_Selected"/>
                  <VisualState x:Name="Normal_Selected"/>
                  <VisualState x:Name="MouseOver_Unfocused_Editing"/>
                  <VisualState x:Name="MouseOver_Editing"/>
                  <VisualState x:Name="MouseOver_Unfocused_Selected"/>
                  <VisualState x:Name="MouseOver_Selected"/>
                  <VisualState x:Name="MouseOver">
                    <Storyboard Storyboard.TargetName="Highlight">
                      <ColorAnimation Duration="0" Storyboard.TargetProperty="Color" To="Khaki"/>
                    </Storyboard>
                  </VisualState>
                </VisualStateGroup>
              </VisualStateManager.VisualStateGroups>
              <SelectiveScrollingGrid x:Name="selectiveScrollingGrid">
                <SelectiveScrollingGrid.Background>
                  <SolidColorBrush x:Name="Highlight" Color="Transparent"/>
                </SelectiveScrollingGrid.Background>
                <SelectiveScrollingGrid.ColumnDefinitions>
                  <ColumnDefinition Width="Auto"/>
                  <ColumnDefinition Width="*"/>
                </SelectiveScrollingGrid.ColumnDefinitions>
                <SelectiveScrollingGrid.RowDefinitions>
                  <RowDefinition Height="*"/>
                  <RowDefinition Height="Auto"/>
                </SelectiveScrollingGrid.RowDefinitions>
                <DataGridCellsPresenter Grid.Column="1" ItemsPanel="{TemplateBinding ItemsPanel}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                <DataGridDetailsPresenter Grid.Column="1" Grid.Row="1" SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}, Converter={x:Static DataGrid.RowDetailsScrollingConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Visibility="{TemplateBinding DetailsVisibility}"/>
                <DataGridRowHeader Grid.RowSpan="2" SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Row}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
              </SelectiveScrollingGrid>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </DataGrid.RowStyle>
</DataGrid>

谢谢Josh。我真的很喜欢你描述的第一个选项。但愿我能够分割被接受的答案。 - Mike L
LOL并不重要,但是被接受的答案至少应该能编译通过吧? :) - Josh
1
哈哈!可能是这样...但是我觉得从一个只有16声望的人那里夺走答案,对你这个有17.3k声望的人来说有点残忍了... :) - Mike L
哈哈,继续吧。毕竟更好的答案应该是被接受的答案。 - Val

5

在我过去处理这种情况时,我通常会使用触发器外部的setter来解决,例如:

<Style TargetType="{x:Type DataGridRow}">
    <Style.Triggers>
        <Trigger Property="IsMouseOver"
                 Value="True">
             <Setter Property="Background"
                     Value="Red" />
             <Setter Property="FontWeight"
                     Value="ExtraBold" />
             <Setter Property="Height"
                     Value="20" />
        </Trigger>
    </Style.Triggers>
    <Setter Property="AlternatingRowBackground"
            Value="{DynamicResource AlternatingRow}"/>
</Style>

然后删除DataGrid本身的属性绑定。虽然我通常使用数据触发器来完成此操作,而不是使用动态资源绑定。但仍然值得一试。


你肯定是朝着正确的方向前进。我按照你的建议添加了Setter属性...不是针对{x:Type DataGridRow},而是作为{x:Type DataGrid}的单独样式。这就解决了问题。 - Mike L
谢谢!不确定为什么在DataGrid样式中定义AlternatingRowBackground而不是直接在DataGrid.AlternatingRowBackground中定义会使触发器起作用,但我很高兴它能够工作! - xofz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接