根据值更改 DataGrid 单元格颜色

Posted

技术标签:

【中文标题】根据值更改 DataGrid 单元格颜色【英文标题】:Change DataGrid cell colour based on values 【发布时间】:2011-07-29 19:24:15 【问题描述】:

我有一个 WPF 数据网格,我想要根据值使用不同的单元格颜色。我的 xaml 上有以下代码

Style TargetType="DataGridCell"

但不是只选择一个单元格而是选择所有行?我错过了什么?

【问题讨论】:

您能否发布适用于您的场景的示例代码。这会有所帮助。顺便说一句,一种方法是将 datagridcell 的背景属性与该单元格的值绑定并使用转换器(从值转换为颜色)。 【参考方案1】:
 <DataGridTextColumn  Binding="Binding Name" Header="Name" Foreground="White">
     <DataGridTextColumn.CellStyle>
      <Style TargetType="x:Type DataGridCell">
         <Setter Property="Background" Value="Binding color" />
      </Style>
     </DataGridTextColumn.CellStyle>
 </DataGridTextColumn>

在 xaml.cs 文件中

SolidColorBrush color=new SolidColorBrush(Colors.Red);

【讨论】:

【参考方案2】:

如果您尝试设置DataGrid.CellStyle,DataContext 将是行,因此如果您想根据一个单元格更改颜色,那么在特定列中这样做可能是最简单的,特别是因为列可以有不同的内容,像文本块、组合框和复选框。这是将NameJohn 的所有单元格设置为浅绿色的示例:

<DataGridTextColumn Binding="Binding Name">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="x:Type TextBlock">
            <Style.Triggers>
                <Trigger Property="Text" Value="John">
                    <Setter Property="Background" Value="LightGreen"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>


您也可以使用ValueConverter 来更改颜色。

public class NameToBrushConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        string input = (string)value;
        switch (input)
        
            case "John":
                return Brushes.LightGreen;
            default:
                return DependencyProperty.UnsetValue;
        
    

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        throw new NotSupportedException();
    

用法:

<Window.Resources>
    <local:NameToBrushConverter x:Key="NameToBrushConverter"/>
</Window.Resources>
...
<DataGridTextColumn Binding="Binding Name">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="x:Type TextBlock">
            <Setter Property="Background" Value="Binding Name, Converter=StaticResource NameToBrushConverter"/>
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

另一种选择是将Background 直接绑定到返回相应颜色画笔的属性。您必须在颜色所依赖的属性的设置器中触发属性更改通知。

例如

public string Name

    get  return _name; 
    set
    
        if (_name != value)
        
            _name = value;
            OnPropertyChanged(nameof(Name));
            OnPropertyChanged(nameof(NameBrush));
        
    


public Brush NameBrush

    get
    
        switch (Name)
        
            case "John":
                return Brushes.LightGreen;
            default:
                break;
        

        return Brushes.Transparent;
    

【讨论】:

嗨 HB,谢谢它或多或少是我想要的,单元格改变但想根据值改变,必须查看值转换器并连接你发送给我的这个代码示例,但我认为这是正确的方向,你有我所说的任何例子吗?谢谢你 我现在可以根据单元格的值获得浅绿色,但想使用值转换器来实现,我不想定义 value="john" 希望被触发并根据条件设置颜色我将以编程方式设置(cs.file c#),希望我能说清楚。非常感谢你帮助我 关于 SO 的大量问题说明了如何使用值转换器,您真的可以进行一些搜索。编辑了我的答案以显示等效值转换器。 我已经做到了,我确实已经实现了一个 claa,但它不能正常工作,这就是为什么问你,** namespace GridCellColor public class MyValueConverter : IValueConverter #region IValueConverter Members object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) if (Convert.ToInt32(value) &gt; 0) return 10; else if (Convert.ToInt32(value) == 0) return 0; else return -1; 但不能正常工作为什么我问你是否有任何例子谢谢为您的回复 该类将您的输入整数转换为另一个整数,这应该如何为背景着色?您需要一个返回 Brush 的转换器。【参考方案3】:

基于“Cassio Borghi”的回答。使用这种方法,根本不需要更改 XAML。

        DataGridTextColumn colNameStatus2 = new DataGridTextColumn();
        colNameStatus2.Header = "Status";
        colNameStatus2.MinWidth = 100;
        colNameStatus2.Binding = new Binding("Status");
        grdComputer_Servives.Columns.Add(colNameStatus2);

        Style style = new Style(typeof(TextBlock));
        Trigger running = new Trigger()  Property = TextBlock.TextProperty, Value = "Running" ;
        Trigger stopped = new Trigger()  Property = TextBlock.TextProperty, Value = "Stopped" ;

        stopped.Setters.Add(new Setter()  Property = TextBlock.BackgroundProperty, Value = Brushes.Blue );
        running.Setters.Add(new Setter()  Property = TextBlock.BackgroundProperty, Value = Brushes.Green );

        style.Triggers.Add(running);
        style.Triggers.Add(stopped);

        colNameStatus2.ElementStyle = style;

        foreach (var Service in computerResult)
        
            var RowName = Service;  
            grdComputer_Servives.Items.Add(RowName);
        

【讨论】:

【参考方案4】:

这可能对您有所帮助。然而,它不是普通的 WPF 数据网格。

我使用带有自定义 ColorFormatter 行为的 DevExpress。我在市场上找不到任何开箱即用的产品。这花了我几天的时间来开发。我的代码附在下面,希望这对那里的人有所帮助。

编辑:我使用了 POCO 视图模型和 MVVM,但是您可以根据需要将其更改为不使用 POCO。

Viewmodel.cs

namespace ViewModel

    [POCOViewModel]
    public class Table2DViewModel
    
        public ITable2DView Table2DView  get; set; 

        public DataTable ItemsTable  get; set; 


        public Table2DViewModel()
        
        

        public Table2DViewModel(MainViewModel mainViewModel, ITable2DView table2DView) : base(mainViewModel)
        
            Table2DView = table2DView;   
            CreateTable();
        

        private void CreateTable()
        
            var dt = new DataTable();
            var xAxisStrings = new string[]"X1","X2","X3";
            var yAxisStrings = new string[]"Y1","Y2","Y3";

            //TODO determine your min, max number for your colours
            var minValue = 0;
            var maxValue = 100;
            Table2DView.SetColorFormatter(minValue,maxValue, null);

            //Add the columns
            dt.Columns.Add(" ", typeof(string));
            foreach (var x in xAxisStrings) dt.Columns.Add(x, typeof(double));

            //Add all the values
            double z = 0;
            for (var y = 0; y < yAxisStrings.Length; y++)
            
                var dr = dt.NewRow();
                dr[" "] = yAxisStrings[y];
                for (var x = 0; x < xAxisStrings.Length; x++)
                
                    //TODO put your actual values here!
                    dr[xAxisStrings[x]] = z++; //Add a random values
                
                dt.Rows.Add(dr);
            
            ItemsTable = dt;
        


        public static Table2DViewModel Create(MainViewModel mainViewModel, ITable2DView table2DView)
        
            var factory = ViewModelSource.Factory((MainViewModel mainVm, ITable2DView view) => new Table2DViewModel(mainVm, view));
            return factory(mainViewModel, table2DView);
        
    


IView.cs

namespace Interfaces
    
        public interface ITable2DView
        
            void SetColorFormatter(float minValue, float maxValue, ColorScaleFormat colorScaleFormat);
        
    

View.xaml.cs

namespace View

    public partial class Table2DView : ITable2DView
    
        public Table2DView()
        
            InitializeComponent();
        

        static ColorScaleFormat defaultColorScaleFormat = new ColorScaleFormat
        
            ColorMin = (Color)ColorConverter.ConvertFromString("#FFF8696B"),
            ColorMiddle = (Color)ColorConverter.ConvertFromString("#FFFFEB84"),
            ColorMax = (Color)ColorConverter.ConvertFromString("#FF63BE7B")
        ;

        public void SetColorFormatter(float minValue, float maxValue, ColorScaleFormat colorScaleFormat = null)
        
            if (colorScaleFormat == null) colorScaleFormat = defaultColorScaleFormat;
            ConditionBehavior.MinValue = minValue;
            ConditionBehavior.MaxValue = maxValue;
            ConditionBehavior.ColorScaleFormat = colorScaleFormat;
        
    

DynamicConditionBehavior.cs

namespace Behaviors

    public class DynamicConditionBehavior : Behavior<GridControl>
    
        GridControl Grid => AssociatedObject;

        protected override void OnAttached()
        
            base.OnAttached();
            Grid.ItemsSourceChanged += OnItemsSourceChanged;
        

        protected override void OnDetaching()
        
            Grid.ItemsSourceChanged -= OnItemsSourceChanged;
            base.OnDetaching();
        

        public ColorScaleFormat ColorScaleFormat  get; set;
        public float MinValue  get; set; 
        public float MaxValue  get; set; 

        private void OnItemsSourceChanged(object sender, EventArgs e)
        
            var view = Grid.View as TableView;

            if (view == null) return;

            view.FormatConditions.Clear();

            foreach (var col in Grid.Columns)
            
                view.FormatConditions.Add(new ColorScaleFormatCondition
                
                    MinValue = MinValue,
                    MaxValue = MaxValue,
                    FieldName = col.FieldName,
                    Format = ColorScaleFormat,
                );
            

        
    

View.xaml

<UserControl x:Class="View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" 
             xmlns:ViewModels="clr-namespace:ViewModel"
             xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
             xmlns:behaviors="clr-namespace:Behaviors"
             xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking"
             DataContext="dxmvvm:ViewModelSource Type=x:Type ViewModels:ViewModel"
             mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="800">

    <UserControl.Resources>
        <Style TargetType="x:Type dxg:GridColumn">
            <Setter Property="Width" Value="50"/>
            <Setter Property="HorizontalHeaderContentAlignment" Value="Center"/>
        </Style>

        <Style TargetType="x:Type dxg:HeaderItemsControl">
            <Setter Property="FontWeight" Value="DemiBold"/>
        </Style>
    </UserControl.Resources>

        <!--<dxmvvm:Interaction.Behaviors>
            <dxmvvm:EventToCommand EventName="" Command="Binding OnLoadedCommand"/>
        </dxmvvm:Interaction.Behaviors>-->
        <dxg:GridControl ItemsSource="Binding ItemsTable"
                     AutoGenerateColumns="AddNew"
                     EnableSmartColumnsGeneration="True">

        <dxmvvm:Interaction.Behaviors >
            <behaviors:DynamicConditionBehavior x:Name="ConditionBehavior" />
            </dxmvvm:Interaction.Behaviors>
            <dxg:GridControl.View>
                <dxg:TableView ShowGroupPanel="False"
                           AllowPerPixelScrolling="True"/>
            </dxg:GridControl.View>
        </dxg:GridControl>
  </UserControl>

【讨论】:

【参考方案5】:

在我的情况下转换器必须返回字符串值。我不知道为什么,但它有效。

*.xaml(通用样式文件,包含在另一个xaml文件中)

<Style TargetType="DataGridCell">
        <Setter Property="Background" Value="Binding RelativeSource=RelativeSource Self, Converter=StaticResource ValueToBrushConverter" />
</Style>

*.cs

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    Color color = VSColorTheme.GetThemedColor(EnvironmentColors.ToolWindowBackgroundColorKey);
    return "#" + color.Name;

【讨论】:

【参考方案6】:

如果您需要使用一定数量的列来执行此操作,那么 H.B. 的方式是最好的。但是,如果您在运行时之前不知道要处理多少列,那么下面的代码 [re​​ad: hack] 将起作用。我不确定是否有更好的解决方案,列数未知。我断断续续地花了两天时间才得到它,所以无论如何我都会坚持下去。

C#

public class ValueToBrushConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        int input;
        try
        
            DataGridCell dgc = (DataGridCell)value;
            System.Data.DataRowView rowView = (System.Data.DataRowView)dgc.DataContext;
            input = (int)rowView.Row.ItemArray[dgc.Column.DisplayIndex];
        
        catch (InvalidCastException e)
        
            return DependencyProperty.UnsetValue;
        
        switch (input)
        
            case 1: return Brushes.Red;
            case 2: return Brushes.White;
            case 3: return Brushes.Blue;
            default: return DependencyProperty.UnsetValue;
        
    

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        throw new NotSupportedException();
    

XAML

<UserControl.Resources>
    <conv:ValueToBrushConverter x:Key="ValueToBrushConverter"/>
    <Style x:Key="CellStyle" TargetType="DataGridCell">
        <Setter Property="Background" Value="Binding RelativeSource=RelativeSource Self, Converter=StaticResource ValueToBrushConverter" />
    </Style>
</UserControl.Resources>
<DataGrid x:Name="dataGrid" CellStyle="StaticResource CellStyle">
</DataGrid>

【讨论】:

Brushes.Red 没有帮助,但 "#" + color.Name 是。想法肯定是你的。谢谢【参考方案7】:
        // Example: Adding a converter to a column (C#)
        Style styleReading = new Style(typeof(TextBlock));
        Setter s = new Setter();
        s.Property = TextBlock.ForegroundProperty;
        Binding b = new Binding();
        b.RelativeSource = RelativeSource.Self;
        b.Path = new PropertyPath(TextBlock.TextProperty);
        b.Converter = new ReadingForegroundSetter();
        s.Value = b;
        styleReading.Setters.Add(s);
        col.ElementStyle = styleReading;

【讨论】:

我希望它在运行时完成。我正在将数据网格与窗口加载上的数据表绑定。那么怎么做呢? 考虑改进您的答案。 Code-only answers may fall under 'Very Low Quality' ...and are candidates for deletion....We've always touted that we aren't a code factory. We are the people who teach others to fish. Code-only answers only feed a person for a day【参考方案8】:

在后面的代码 (VB.NET) 中执行此操作

Dim txtCol As New DataGridTextColumn

Dim style As New Style(GetType(TextBlock))
Dim tri As New Trigger With .Property = TextBlock.TextProperty, .Value = "John"
tri.Setters.Add(New Setter With .Property = TextBlock.BackgroundProperty, .Value = Brushes.Green)
style.Triggers.Add(tri)

xtCol.ElementStyle = style

【讨论】:

【参考方案9】:

换个方式

<Style TargetType="x:DataGridCell" >

但请注意,这将针对您的所有单元格(您针对的是 DataGridCell 类型的所有对象) 如果您想根据单元格类型设置样式,我建议您使用DataTemplateSelector

可以在 Christian Mosers 的 DataGrid 教程中找到一个很好的示例:

http://www.wpftutorial.net/DataGrid.html#rowDetails

玩得开心:)

【讨论】:

嗨大马士革,感谢您的回复,我有 DatagridCell 的 TargetType,您是对的,因为它影响了我的整个行。我希望只影响一个单元格,具体取决于该单元格的值。我该怎么做? 其实这取决于你的情况。你看到我给你的链接上的例子了吗?关于如何根据对象类型(在示例中:男孩或女孩)选择样式有一个非常清楚的示例。你的问题是否类似? 不,它不相似,因为我希望选择一个单元格而不是整个行,因为它是在示例中播种的。

以上是关于根据值更改 DataGrid 单元格颜色的主要内容,如果未能解决你的问题,请参考以下文章

WPF使用转换器更改datagrid单元格背景颜色

根据存储在其他单元格中的 RGB 值动态更改单元格的背景颜色

根据值更改单元格颜色

数据表:根据值更改单元格颜色

C#WPF根据数据长度编辑datagrid单元格颜色

HTML 和 CSS - 根据值更改单元格的文本颜色