[c#] Change DataGrid cell colour based on values

I have got a WPF datagrid and I want diffrent cell colours according to values. I have got below code on my xaml

Style TargetType="DataGridCell"

but instead of selecting a cell only is selecting all row? What am I missing?

This question is related to c# wpf xaml colors datagrid

The answer is


Based on the answer by 'Cassio Borghi'. With this method, there is no need to change the XAML at all.

        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);
        }

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

This may be of help to you. It isn't the stock WPF datagrid however.

I used DevExpress with a custom ColorFormatter behaviour. I couldn't find anything on the market that did this out of the box. This took me a few days to develop. My code attaached below, hopefully this helps someone out there.

Edit: I used POCO view models and MVVM however you could change this to not use POCO if you desire.

Example

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>

In my case convertor must return string value. I don't why, but it works.

*.xaml (common style file, which is included in another xaml files)

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

To do this in the Code Behind (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

If you need to do it with a set number of columns, H.B.'s way is best. But if you don't know how many columns you are dealing with until runtime, then the below code [read: hack] will work. I am not sure if there is a better solution with an unknown number of columns. It took me two days working at it off and on to get it, so I'm sticking with it regardless.

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>

Just put instead

<Style TargetType="{x:DataGridCell}" >

But beware that this will target ALL your cells (you're aiming at all the objects of type DataGridCell ) If you want to put a style according to the cell type, I'd recommend you to use a DataTemplateSelector

A good example can be found in Christian Mosers' DataGrid tutorial:

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

Have fun :)


Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to wpf

Error: the entity type requires a primary key Reportviewer tool missing in visual studio 2017 RC Pass command parameter to method in ViewModel in WPF? Calling async method on button click Setting DataContext in XAML in WPF How to resolve this System.IO.FileNotFoundException System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll? Binding an Image in WPF MVVM How to bind DataTable to Datagrid Setting cursor at the end of any text of a textbox

Examples related to xaml

Setting DataContext in XAML in WPF Change color of Button when Mouse is over Implement Validation for WPF TextBoxes Use StringFormat to add a string to a WPF XAML binding How to format number of decimal places in wpf using style/template? How to set DataGrid's row Background, based on a property value using data bindings WPF C# button style How to clear a textbox once a button is clicked in WPF? Add Items to Columns in a WPF ListView Binding ConverterParameter

Examples related to colors

is it possible to add colors to python output? How do I use hexadecimal color strings in Flutter? How do I change the font color in an html table? How do I print colored output with Python 3? Change bar plot colour in geom_bar with ggplot2 in r How can I color a UIImage in Swift? How to change text color and console color in code::blocks? Android lollipop change navigation bar color How to change status bar color to match app in Lollipop? [Android] How to change color of the back arrow in the new material theme?

Examples related to datagrid

How to bind DataTable to Datagrid WPF Datagrid Get Selected Cell Value Wpf DataGrid Add new row How to clear a data grid view Adding values to specific DataTable cells Accessing UI (Main) Thread safely in WPF Date formatting in WPF datagrid How to hide column of DataGridView when using custom DataSource? How can I disable editing cells in a WPF Datagrid? Datagrid binding in WPF