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

Posted

技术标签:

【中文标题】WPF 数据网格。无法突出显示自定义样式的单元格【英文标题】:WPF datagrid. Cannot highlight custom styled cell 【发布时间】:2017-09-05 14:53:59 【问题描述】:

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

Here's the picture

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

好吧,我可以为单元格样式添加一个额外的触发器,该触发器会在选择时更改 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();
        
    

【问题讨论】:

【参考方案1】:

“Kludge”与否,单元格的 Background 确实会“覆盖”行的背景,因此您应该在单元格样式中添加另一个触发器以考虑到这一点。例如,您可以使用包含红色和蓝色画笔的 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>

【讨论】:

正是我需要的。接受。【参考方案2】:

您可以使用 MultiDataTrigger 实现此目的。但为什么你认为这是一个“杂牌”?我认为它相当优雅。

mm8 代码的替代方法是简单地设置两个 MultiDataTrigger。第一种在 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>

【讨论】:

这行得通,赞成,但我接受了 mm8 的回答,因为他实现了不透明性。至于“kludge”,我看不到一种简单的方法可以将这种方法用于多个列。但这可能是另一个问题。

以上是关于WPF 数据网格。无法突出显示自定义样式的单元格的主要内容,如果未能解决你的问题,请参考以下文章

WPF 数据网格格式 - 并非所有样式都受到尊重

Grid布局(四)单元格自定义布局

Excel设置表格样式的显示效果使用excel如何改变表格样式

当在顶部添加新帖子时,UICollectionView 单元格自定义 FlowLayout 中断

如何用Apache POI读取Excel的单元格自定义名称的值

读取自定义Datagrid的每个单元格数据 - WPF C#