How to set datagrid cell background during AutoGeneratingColumn event depending on its value?

I'm still struggling with manipulating cell backgrounds, so I'm asking a new question.

User "HB" wrote that I can set the cell style during an AutoGeneratingColumn event - Change the color of a DataGrid cell based on values . The problem is that I'm not sure how to do this.

What I want: Set different background colors for each cell depending on its value. If the value is null , I also want it to not be clickable (as far as I understand).

What am i trying to do:

 private void mydatagrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { foreach (Cell cell in e.Column) { if (cell.Value < 1) { cell.Background = Color.Black; cell.isFocusable = false; } else { cell.Background = Color.Pink; } } } 

This is just pseudo code. Is this possible during auto-generation of a column, and if so, how can I change my code to be valid?

I read about value converters, but I want to know if this is possible programmatically, without writing XAML.

Please understand that I'm still new to C # / WPF / DataGrid.

Part of solution 1:

I used the answer that I accepted. Just put it in

 <Window.Resources> <local:ValueColorConverter x:Key="colorConverter"/> <Style x:Key="DataGridCellStyle1" TargetType="{x:Type DataGridCell}"> <Setter Property="Padding" Value="5"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type DataGridCell}"> <Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True"> <Border.Background> <MultiBinding Converter="{StaticResource colorConverter}"> <Binding RelativeSource="{RelativeSource AncestorType=DataGridCell}" Path="Content.Text"/> <Binding RelativeSource="{RelativeSource AncestorType=DataGridCell}" Path="IsSelected"/> </MultiBinding> </Border.Background> <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> 

And made a MultiBinding converter for it so that I can also set the background color for the selected cells.

Problem:

Now I need to solve the problem of setting the focus of empty cells. Any clues?

  <Style.Triggers> <Trigger Property="HasContent" Value="False"> <Setter Property="Focusable" Value="False"/> </Trigger> </Style.Triggers> 

This does not work. I had empty lines in empty cells, but they are filled with "zero", so it should work, right? Or what am I doing wrong: |

Part of the solution:

This way, the code above will not work until the cell value is β€œTextBox”, so I decided to find another way to handle this, which can be found in my answer here: https://stackoverflow.com/a/316618/

Thanks for trying to help me :)

+8
c # background wpf datagrid autogeneratecolumn
May 20 '13 at 8:44
source share
3 answers

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> 
+10
May 20 '13 at 10:27
source share

What I had in mind is that you can set the CellStyle property of a column, you cannot directly manipulate cells, since they are not available in this case. The style may contain your conditional logic in the form of DataTriggers (a converter is required, since you have less than equal) and Setters .

Also, if the logic is not column specific, you can set the style globally on the grid . The point of using the event will be to manipulate the properties of the column, which you cannot access otherwise.

+1
May 20 '13 at 10:22
source share

I'm not sure if this property (Cell.Style) is available in your WPF Datagrid. There is probably some alternative in your case. He worked for WinForms datagrid.

  cell.Style.BackColor = System.Drawing.Color.Black; 
-2
May 20 '13 at 9:47
source share



All Articles