I can offer two different solutions for your question: firstly, it is the "code-behind-style" (which you ask for, but I personally think that this is the wrong approach in WPF) and the more WPF-style (which is more complicated but preserves clean code and uses styles, triggers and converters).
Solution 1. Event Processing and Coloring Code Logic
First of all, the approach you choose will not work directly - the AutoGeneratingColumn event is designed to change the appearance of the entire column , and not for each element. Thus, it can be used, for example, to bind the correct style to the entire column based on its index score or related property.
Generally speaking, the first time an event is raised, your datagrid will not have any rows (and therefore no cells) at all. If you really need to catch an event, think about your DataGrid.LoadingRow event. And you canβt easily get the cells :)
So what do you do: handle the LoadRow event, get the string (it has the Item property that contains (surprisingly :)) your related item), get the related item, do all the necessary calculations, get the cell that needs to be changed, and finally , change the style of the target cell.
Here is the code (as an element I use a sample object with the int "Value" property, which I use for coloring).
Xaml
<DataGrid Name="mygrid" ItemsSource="{Binding Items}" AutoGenerateColumns="True" LoadingRow="DataGrid_OnLoadingRow"/>
.CS
private void DataGrid_OnLoadingRow(object sender, DataGridRowEventArgs e) { Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => AlterRow(e))); } private void AlterRow(DataGridRowEventArgs e) { var cell = GetCell(mygrid, e.Row, 1); if (cell == null) return; var item = e.Row.Item as SampleObject; if (item == null) return; var value = item.Value; if (value <= 1) cell.Background = Brushes.Red; else if (value <= 2) cell.Background = Brushes.Yellow; else cell.Background = Brushes.Green; } public static DataGridRow GetRow(DataGrid grid, int index) { var row = grid.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow; if (row == null) { // may be virtualized, bring into view and try again grid.ScrollIntoView(grid.Items[index]); row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index); } return row; } public static T GetVisualChild<T>(Visual parent) where T : Visual { T child = default(T); int numVisuals = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < numVisuals; i++) { var v = (Visual)VisualTreeHelper.GetChild(parent, i); child = v as T ?? GetVisualChild<T>(v); if (child != null) { break; } } return child; } public static DataGridCell GetCell(DataGrid host, DataGridRow row, int columnIndex) { if (row == null) return null; var presenter = GetVisualChild<DataGridCellsPresenter>(row); if (presenter == null) return null; // try to get the cell but it may possibly be virtualized var cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex); if (cell == null) { // now try to bring into view and retreive the cell host.ScrollIntoView(row, host.Columns[columnIndex]); cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex); } return cell; }
Solution 2. WPF Style
This solution uses only code to convert values ββto color (assuming that this coloring logic is more complicated than equality comparison), in which case you can use triggers and not mess up the converters).
What you do: set the DataGrid.CellStyle property with a style containing a data trigger that checks if the cell is in the right column (based on this DisplayIndex), and if it is, the background is applied via the converter.
Xaml
<DataGrid Name="mygrid" ItemsSource="{Binding Items}" AutoGenerateColumns="True"> <DataGrid.Resources> <local:ValueColorConverter x:Key="colorconverter"/> </DataGrid.Resources> <DataGrid.CellStyle> <Style TargetType="DataGridCell"> <Style.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Column.DisplayIndex}" Value="1"> <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text, Converter={StaticResource colorconverter}}"/> </DataTrigger> </Style.Triggers> </Style> </DataGrid.CellStyle> </DataGrid>
.cs
public class ValueColorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var str = value as string; if (str == null) return null; int intValue; if (!int.TryParse(str, out intValue)) return null; if (intValue <= 1) return Brushes.Red; else if (intValue <= 2) return Brushes.Yellow; else return Brushes.Green; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
UPD: If you need to color the entire data set, XAML is much simpler (no need to use triggers). Use the following CellStyle:
<DataGrid.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text, Converter={StaticResource colorconverter}}"/> </Style> </DataGrid.CellStyle>