I'm still fighting with manipulation of cell backgrounds so I'm asking a new question.
A user "H.B." wrote that I can actually set the cell style during the AutoGeneratingColumn event - Change DataGrid cell colour based on values. The problem is that I'm not sure how to do it.
What I want:
Set different background colours for each cell depending on its value. If the value is null
I also want it not to be clickable (focusable I guess).
What I have / I'm 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 the pseudocode. Is something like this is possible during column auto-generation and if so, how can I edit my code so it will be valid?
I read about value convertors but I want to know if it's somehow possible programmatically, without writing XAML.
Please understand that I'm still a beginner to C#/WPF/DataGrid.
Solution part1:
I used the answer I accepted. Just put it into
<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 for it a MultiBinding
convertor so I can also set the background color for selected cells.
Problem:
Now I only have to solve the problem of setting focus of empty cells. Any hints?
<Style.Triggers>
<Trigger Property="HasContent" Value="False">
<Setter Property="Focusable" Value="False"/>
</Trigger>
</Style.Triggers>
This doesn't work. I had empty strings in the empty cells, but they are filled with ´null´s so it should work, right? Or what am I doing wrong :| ?
Solution part 2:
So the code above won't work as long as the cell value is a ´TextBox´ so I decided to find another way to deal with it which can be found in my answer here: https://stackoverflow.com/a/16673602/2296407
Thanks for trying to help me :)
I am not sure whether this property (Cell.Style) is available in your WPF Datagrid. Probably some alternative exists in your case. It has worked for WinForms datagrid.
What i meant is that you can set the
CellStyle
property of the column, you can not manipulate cells directly as they are not available in this event. The style can contain your conditional logic in the form ofDataTriggers
(will need a converter as you have "less-than" and not equals) andSetters
.Also if the logic is not specific to the columns you can set the style globally on the grid itself. The point of using the event would be to manipulate the column properties which you can not access otherwise.
I can propose two different solutions for your question: the first is "code-behind-style" (which you are asking for but personally I think it is not right approach in WPF) and more WPF-style (which more tricky but keeps code-behind clean and utilizes styles, triggers and converters)
Solution 1. Event handling and code-behind logic for coloring
First of all, the approach you've chosen will not work directly - the AutoGeneratingColumn event is meant to be used for altering the entire column appearance, not on the cell-by-cell basis. So it can be used for, say, attaching the correct style to entire column basing on it's display index or bound property.
Generally speaking, for the first time the event is raised your datagrid will not have any rows (and consequently - cells) at all. If you really need to catch the event - consider your DataGrid.LoadingRow event instead. And you will not be able to get the cells that easy :)
So, what you do: handle the LoadingRow event, get the row (it has the Item property which holds (surprisingly :)) your bound item), get the bound item, make all needed calculations, get the cell you need to alter and finally alter the style of the target cell.
Here is the code (as item I use a sample object with the int "Value" property that I use for coloring).
XAML
.CS
Solution 2. WPF-style
This solution uses code-behind only for value-to-color convertions (assuming that that logic of coloring is more complex than equality comparison - in that case you can use triggers and do not mess with converters).
What you do: set DataGrid.CellStyle property with style that contains a data trigger, which checks if the cell is within a desired column (basing on it's DisplayIndex) and if it is - applies background through a converter.
XAML
.CS
UPD: If you need to color entire datagrid, XAML is much easier (no need to use triggers). Use the following CellStyle: