How to style a WPF DataGridCell dynamically

10.5k views Asked by At

I have a DataGrid with the itemsSource defined as follow:

dg.ItemsSource = new ObservableCollection<myRow>

...

public class myRow : Collection<myDataGridCell> { ... }

...

public interface ImyDataGridCell
{
    Brush Background { get; set; }
    Brush Foreground { get; set; }
}

and then I have classes for each type of column/cell:

public class myTextBoxColumn : DataGridTextColumn {...}
public class myTextBoxCell : TextBox, ImyDataGridCell {...}

then I set each column's CellStyle like this:

in each column's constructor:

string source = String.Format(CultureInfo.InvariantCulture, "[{0}].", dataGrid.Columns.Count);
// I set the "source" string to the column's index in the dataGrid's Columns list between [] to get an index in my binding below.

CellStyle = new Style(typeof(DataGridCell));
CellStyle.Setters.Add(new Setter(DataGridCell.BackgroundProperty, new Binding(source + "Background")));

this allows me to bind the actual DataGridCell's Background property to the Background property of my cell's representation, and thus to modify a cell's background anytime I want easily.

now my main issue is that this way of doing things slows the dataGrid like hell... I have around 15 properties I bind for each cell, and when I show 100 cols x 20 rows it takes more than a second to show the dataGrid and then about a second to refresh it when I scroll horizontally (my screen can only allow for 20 cols at a time, and I have Virtualization enabled for the dataGrid).

If I get rid of the styling, the response time is still more than I'd like, but I could do with it.

So is there a better way to do this?

I also tried doing this style in Xaml, but It did not seem to cope well with column's virtualization, i.e.: I would set a cell's background green, then scroll a whole page right, and the cell that ends up in the same position as the cell I had painted green gets the green color event if it should be red: the value is not updated untill I move the current row to the row containing the cell... plus, it did not seem to improve performance at all...

thanks for sharing if you have any kind of though/tip/previous experience on the matter, I'm willing to try about everything that could make this damn dataGrid load faster...

Edit: General effect I want to achieve:

  • a dataGrid with dynamics columns (the number and type of columns are only known at runtime
  • at any time, I can change whatever style property of a single cell: Font (family, size, style, weight, decoration if applied), foreground, background, textAlignment if any etc...

this is just what I have to achieve. know I found that with column virtualization on, you cannot manipulate the REAL dataGridCells, as they might not be shown yet (virtualized), and then you loose the property value's change. So I went for this "hack": I bind every single property in the actual dataGridCell's style to the "logical" one, and I modify the logical one. But this is slooooow.

hope I managed to explain myself a little better.

1

There are 1 answers

4
PeterI On

Any chance of seeing your slow Xaml? I would have thought that doing this with a datatrigger wouldn't be too awful (also which version of the data grid are you using as the .net 4.0 and the WPF Toolkit versions are different)

I've done stuff like this to recolor for selected items and it didn't seem too slow (this isn't the right solution but I'd like a little more detail before I say any more):

        <Style TargetType="DataGrid">
        <Setter Property="CellStyle">
            <Setter.Value>
                <Style TargetType="DataGridCell">
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Background" Value="{StaticResource SelectedBackgroundBrush}" />
                            <Setter Property="BorderBrush" Value="{x:Null}" />
                            <Setter Property="Foreground" Value="White" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Setter.Value>
        </Setter>
    </Style>