WPF 数据网格。无法突出显示自定义样式的单元格

WPF datagrid. Cannot highlight custom styled cell

我有一个数据网格,它是一个金融计算器,其中一些单元格在负值时变为红色。这是通过带有转换器的 DataTrigger 完成的。我还覆盖了系统高亮 selection 颜色。我现在的问题是,当我 select 一行时,红色单元格不会突出显示。

Here's the picture

据我了解,自定义单元格样式会覆盖 selection。我希望我的自定义红色单元格也用 0.5 不透明度蓝色条突出显示。我该如何解决这个问题?

好吧,我可以在单元格样式中添加一个额外的触发器,根据 selection 更改 BG 颜色并调整颜色以适合,但这有点麻烦。或者也许我可以在这里以某种方式实现不透明的叠加颜色?

<Trigger Property="IsSelected" Value="True">
    <Setter Property="Background" Value="LightBlue" />
</Trigger>

下面是完整代码。这是一个精简、重量轻但功能齐全的示例。

XAML

 <Window.Resources>
        <local:ValueToBoolConverter x:Key="ValueToBoolConverter"/>
    </Window.Resources>
    <Grid>
        <DataGrid ItemsSource="{Binding MainTable}"
                  AutoGenerateColumns="False"
                  CanUserAddRows="False">
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="Background" Value="Azure"/>
                    <Style.Resources>
                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Blue" Opacity="0.5" />
                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
                        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent" />
                    </Style.Resources>
                </Style>
            </DataGrid.RowStyle>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Income Day" Binding="{Binding IncomeDay}" />
                <DataGridTextColumn Header="Income Week" Binding="{Binding IncomeWeek}">
                    <DataGridTextColumn.CellStyle>
                        <Style TargetType="DataGridCell">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IncomeWeek, Converter={StaticResource ValueToBoolConverter}}" Value="true">
                                    <Setter Property="Background" Value="Salmon"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </DataGridTextColumn.CellStyle>
                </DataGridTextColumn>
                <DataGridTextColumn Header="Income Month" Binding="{Binding IncomeMonth}" />
                <DataGridTextColumn Header="Income Year" Binding="{Binding IncomeYear}" Width="*" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

C#

using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace Datagrid_Cell_Highlight
{
    public class TableData
    {
        public decimal IncomeDay { get; set; }
        public decimal IncomeWeek { get; set; }
        public decimal IncomeMonth { get; set; }
        public decimal IncomeYear { get; set; }
    }

    public class ViewModel
    {
        public ObservableCollection<TableData> MainTable { get; set; }
        public ViewModel()
        {
            MainTable = new ObservableCollection<TableData>
            {
                new TableData { IncomeDay = (decimal)1.11 },
                new TableData { IncomeDay = (decimal)2.22 },
                new TableData { IncomeDay = (decimal)-1.23 },
                new TableData { IncomeDay = (decimal)-2.34 }
            };
            foreach (var table in MainTable)
            {
                table.IncomeWeek = table.IncomeDay * 7;
                table.IncomeMonth = table.IncomeDay * 30;
                table.IncomeYear = table.IncomeDay * 365;
            }
        }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new ViewModel();
        }
    }

    public class ValueToBoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if ((value is decimal) && ((decimal)value < 0))
                return true;
            else return false;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

"Kludge" 与否,单元格的 Background 确实会 "override" 行的背景,因此您应该在考虑到这一点的单元格样式中添加另一个触发器。例如,您可以使用包含红色和蓝色画笔的 MultiDataTriggerDrawingBrush

<DataGridTextColumn Header="Income Week" Binding="{Binding IncomeWeek}">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IncomeWeek, Converter={StaticResource ValueToBoolConverter}}" Value="true">
                    <Setter Property="Background" Value="Salmon"/>
                </DataTrigger>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding IncomeWeek, Converter={StaticResource ValueToBoolConverter}}" Value="true" />
                        <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="True" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background">
                        <Setter.Value>
                            <DrawingBrush Viewport="0,0,1,1" TileMode="Tile">
                                <DrawingBrush.Drawing>
                                    <DrawingGroup>
                                        <GeometryDrawing>
                                            <GeometryDrawing.Geometry>
                                                <RectangleGeometry Rect="0,0,1,1" />
                                            </GeometryDrawing.Geometry>
                                            <GeometryDrawing.Brush>
                                                <SolidColorBrush Color="Salmon"/>
                                            </GeometryDrawing.Brush>
                                        </GeometryDrawing>
                                        <GeometryDrawing>
                                            <GeometryDrawing.Geometry>
                                                <RectangleGeometry Rect="0,0,1,1" />
                                            </GeometryDrawing.Geometry>
                                            <GeometryDrawing.Brush>
                                                <SolidColorBrush Color="Blue" Opacity="0.2"/>
                                            </GeometryDrawing.Brush>
                                        </GeometryDrawing>
                                    </DrawingGroup>
                                </DrawingBrush.Drawing>
                            </DrawingBrush>
                        </Setter.Value>
                    </Setter>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

您可以使用 MultiDataTrigger 实现此目的。但是你为什么认为这是一个"kludge"呢?我觉得比较优雅。

mm8 代码的替代方法是简单地设置两个 MultiDataTriggers。第一种在 IsSelected 为 false 时触发,第二种方式在 IsSelected 为 true 时触发。

<DataGridTextColumn.CellStyle>
    <Style TargetType="DataGridCell">            
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="False"/>
                    <Condition Binding="{Binding IncomeWeek, Converter={StaticResource ValueToBoolConverter}}" Value="True"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Background" Value="Salmon"/>
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True"/>
                    <Condition Binding="{Binding IncomeWeek, Converter={StaticResource ValueToBoolConverter}}" Value="True"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                    <Setter Property="BorderThickness" Value="0"/>
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>
</DataGridTextColumn.CellStyle>