Триггер стиля WPF для цвета фона DataGridRow, превосходящего кисть AlternatingRowBackground

У меня есть WPF DataGrid с кистью AlternatingRowBackground. Он настроен на окрашивание каждой второй строки. Я хотел бы сделать что-то при наведении курсора мыши, чтобы выделить текущую строку. Однако Style Trigger, кажется, проигрывает кисти 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 (без кисти AlternatingRowBackground):

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

person Mike L    schedule 01.09.2010    source источник


Ответы (2)


Что работало для меня в прошлом с такими вещами, так это использовать установщик вне триггеров, например:

<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. Хотя я обычно делаю это с триггерами данных, а не с динамическими привязками ресурсов. Но все же, возможно, стоит попробовать

person Val    schedule 01.09.2010
comment
вы определенно меня идете в правильном направлении. Я добавил свойство Setter, как вы предложили... не в {x:Type DataGridRow}, а как отдельный стиль для {x:Type DataGrid}. Это делает свое дело. - person Mike L; 01.09.2010
comment
Спасибо! Не уверен, почему определение AlternatingRowBackground в стиле DataGrid, а не в DataGrid.AlternatingRowBackground напрямую позволяет триггеру работать, но я рад, что это так! - person xofz; 13.10.2010

Есть два способа сделать это, ни один из них не особенно очевиден. Поскольку DataGridRow передает (в коде) свойство фона из родительского DataGrid в локальное значение в строке, как вы заметили, оно будет иметь приоритет над значением, установленным вашим триггером.

Первый (и самый простой) способ — не использовать AlternatingRowBackground или RowBackground, а вместо этого использовать триггеры для изменения цвета фона, как предложил Вал. Однако его пример не является полным и не будет работать как есть. Правильный стиль и использование будут следующими. Обратите внимание, что вам нужно установить AlternationCount для DataGrid, иначе строки никогда не получат чередующиеся индексы.

<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, и я установил фон для selectedScrollingGrid.

Извините за обертку, но, как я уже сказал, это немного более подробно.

<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>
person Josh    schedule 01.09.2010
comment
Спасибо, Джош. Мне очень нравится первый описанный вами вариант. Хотел бы я разделить принятый ответ. - person Mike L; 01.09.2010
comment
LOL на самом деле не имеет значения, но разве принятый ответ не должен хотя бы компилироваться? :) - person Josh; 01.09.2010
comment
Ха-ха! Наверное, да... но было бы жестоко отнять ответ у человека с репутацией 16 против ваших 17,3 тыс.... :) - person Mike L; 01.09.2010
comment
Ха-ха, давай. В конце концов, лучший ответ должен быть принятым ответом. - person Val; 07.09.2010