Home » WPFRSS

WPF DataGrid. Change single cell background.

Hi,

I need to change the background colour of a certain cell in a DataGrid that is bound to a DataTable, is this possible? I cannot find a list of cells or cell styles anywhere.

I know the column and row of its location in the DataTable. So, in pseudo code, it would be:

var cell = dgData.Cells[columnIndex,rowIndex];

cell.Background = new SolidBrush(Colours.AliceBlue);

Cheers,
Jose

 

13 Answers Found

 

Answer 1

I'm not sure you can access the cells  in the wpf  DataGrid from code  like this. We did something similar at work recently which set the background  colour of certain cells if the item the cell  was bound  to met certain criteria.

We did this by setting the DataGrid's CellStyle to set the background colour  of a cell using data binding with a custom binding converter like so:

<wpf:DataGrid.CellStyle>
<Style TargetType="{x:Type wpf:DataGridCell}">  
<Setter Property="Background"Value="{Binding SomeProperty, Converter={StaticResource cellBackgroundConverter}}"/>
</Style>
</wpf:DataGrid.CellStyle>

The custom binding converter returns a SolidColorBrush with the intended cell colour.

This may be a bit long-winded for what you want to do though....

 

Answer 2

Hi Dave,

Thanks for the pointer. It is exactly what I needed. I ended up writing a blog entry about this and I am leaving the link here for anyone else with the same problem:

http://codefornothing.wordpress.com/2009/01/25/the-wpf-datagrid-and-me/

 

Answer 3


 This may seem like a daft question, but is it possible to use something similar so that even if you don't know the column  name, you can affect the background  & display of any cell  in the datagrid?
 The reason is, I am trying to create a 'generic' WPF datagrid  which reacts to the data it is displaying, the colour  of numeric fields will reflect their value is a red, yellow, green for various hard-set values similar to the above code.
 A date field would want to be shown in shortdate format and it's background would need to change  based on how many years away from todays date it was. Other text fields would just have their justification and background changed based on a given condition (e.g. if the contained a specific substring).
 As I wouldn't know the name of the column and it's type at design time, I'd need to be able to react to the type at runtime which the above seems to do. For that reason, I couldn't 'hard-code' date converters as I wouldn't know which column they belonged to. This would allow the one view to cater for any number of queries on data under one common set of functions.

 On the face of it, it seems as if this should be possible, but so far I have had no success in finding any similar examples on the web despite many house of searching. The alternative is to have explicitly hard-coded views for each program and sub-choice I wish to make which seems like an awful lot of duplicated code.
 Can anyone offer any solutions? Or am I simply asking too much of the datagrids capabilities?
 

Answer 4

Hi. I have datagrid  with many columns. One column  is called "age". When data is loaded into the DataGrid, I want the text in a cell ("age" row) to be red if the value is greater than 25. I have been trying to do that in LoadingRow event but unsucessful so far. I know how to make entire row  into red when age>25 but I just need the age cell  in red, not entire row. Please advice...
 

Answer 5

Salve, Gaius!

take a look at this thread .
 

Answer 6

And please, do not double post your questions. You already asked your question in this thread.
 

Answer 7

As I now use this a lot, I thought I'd share what we did as I know how frustrating it is trying to locate this information.

Where, in this example, my project (namespace) is called DataGridColrs.

In the header part of the XAML I added:
       xmlns:local="clr-namespace:DataGridColrs"

Then in the window.resources area I add the lines:

            <local:BGConverter x:Key="myBGColor"/>
            <local:FGConverter x:Key="myFGColor"/>

and the code  to set a default cell  style thus:

            <Style x:Key="defCStyle" TargetType="{x:Type dg:DataGridCell}">
                <Setter Property="Foreground">
                    <Setter.Value>
                        <MultiBinding Converter="{StaticResource myFGColor}" >
                            <MultiBinding.Bindings>
                                <Binding RelativeSource="{RelativeSource Self}">
                                </Binding>
                                <Binding Path="Row"></Binding>
                            </MultiBinding.Bindings>
                        </MultiBinding>
                    </Setter.Value>
                </Setter>
                <Setter Property="Background">
                    <Setter.Value>
                        <MultiBinding Converter="{StaticResource myBGColor}" >
                            <MultiBinding.Bindings>
                                <Binding RelativeSource="{RelativeSource Self}">
                                </Binding>
                                <Binding Path="Row"></Binding>
                            </MultiBinding.Bindings>
                        </MultiBinding>
                    </Setter.Value>
                </Setter>
            </Style>


In my code for the datagrid, I add the line to set the cellstyle to the above

        <dg:DataGrid Margin="12,12,23,60"
                     CellStyle="{StaticResource defCStyle}"
                     Name="dgrid1" IsReadOnly="True">
        </dg:DataGrid>


..Then in the code I create the foreground and background  converters
within the namespace but outside of the window class thus:
(in this case, I am reacting to the physical stock level).


    public class BGConverter : IMultiValueConverter
    {
        #region Implementation of BGConverter

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            SolidColorBrush mybrush = new SolidColorBrush();
            Decimal cell_value;

            if (values[1] is DataRow)
            {
                var  cell = (DataGridCell)values[0];
                var row  = (DataRow)values[1];
                var columnName = cell.Column.SortMemberPath;
                Type type1 = row[columnName].GetType();

                if (columnName == "physical_stock")
                {
                    cell_value = (Decimal)row[columnName];  // phys. stock is a Decimal column

                    if (cell_value <= 0)
                        mybrush = new SolidColorBrush(Colors.Red);
                    else if (cell_value <= 8)
                        mybrush = new SolidColorBrush(Colors.Yellow);
                    else if (cell_value < 20)
                        mybrush = new SolidColorBrush(Colors.Green);
                    else
                        mybrush = new SolidColorBrush(Colors.White);
                }
                else
                {
                    mybrush = new SolidColorBrush(Colors.AliceBlue);
                }
                return mybrush;

            }
            return SystemColors.AppWorkspaceColor;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }

        #endregion
    }

    // ----------------------------------------

    public class FGConverter : IMultiValueConverter
    {
        #region Implementation of FGConverter

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            SolidColorBrush mybrush = new SolidColorBrush();
            Decimal cell_value;

            if (values[1] is DataRow)
            {
                var cell = (DataGridCell)values[0];
                var row = (DataRow)values[1];
                var columnName = cell.Column.SortMemberPath;
                Type type1 = row[columnName].GetType();

                if (columnName == "physical_stock")
                {
                    cell_value = (Decimal)row[columnName];

                    if (cell_value <= 0)
                        mybrush = new SolidColorBrush(Colors.White);
                    else if (cell_value <= 8)
                        mybrush = new SolidColorBrush(Colors.Black);
                    else if (cell_value < 20)
                        mybrush = new SolidColorBrush(Colors.White);
                    else
                        mybrush = new SolidColorBrush(Colors.Black);
                }
                else
                {
                    mybrush = new SolidColorBrush(Colors.Navy);
                }
                return mybrush;
            }
            return Colors.Black;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }

        #endregion
    }


..Hope this helps.

-Terian
 

Answer 8

tanks .is ok
 

Answer 9

I've been playing around with this example, but values[1] in both IMultiValueConverters is always {DependencyProperty.UnsetValue}. Any ideas?
 

Answer 10

Can't say I've ever had that, it's as if the datarow doesn't exist. If you stop the debugger, does values[] have anything in it? As you can see from the converter code, values[0] should be the cell  and values[1] should be the row.

 

 

Answer 11

What do you mean "if you stop the debugger"?

Values[0] is set correctly by the way.

 

Answer 12

Sorry, meant to say, if you put a breakpoint in the multiconverter, which you must have done to know Values[0] is set . :-)

I'm at a loss to figure out why the row  value is not set in values, the only other thing end to have in my datagrid  definition is

EnableRowVirtualization="True"
AutoGenerateColumns="False"

As I build my datagrid based on a dynamic datatable. Now if for some reason, on a autogenerated datagrid, it is trying to call the converter before any rows exist, I could understand that error.

Does values[] have 2 elements or 1?   the only thing I can think of is to put in a specific check for the number of elements and drop out of the converter accordingly. I'm thinking maybe it is a question of not having any rows to work on so the attempt to get the row is failing.

 

 

Answer 13

My grid also has these properties set:

EnableRowVirtualization="True"
AutoGenerateColumns="False"

values[] length =2. Index 0 is the cell, index 1 is {DependencyProperty.UnsetValue}

This is my resource for the DataGridCellStyle:

<Stylex:Key="defCStyle"TargetType="{x:Type DataGridCell}"><SetterProperty="Background"><Setter.Value><MultiBindingConverter="{StaticResource myBGColor}"><MultiBinding.Bindings><BindingRelativeSource="{RelativeSource Self}"></Binding><BindingPath="Row"Mode="OneWay"/></MultiBinding.Bindings></MultiBinding></Setter.Value></Setter></Style>
 
 
 

<< Previous      Next >>


Microsoft   |   Windows   |   Visual Studio   |   Follow us on Twitter