C# – DataGrid Cell.Style binding

cdata-bindingdatagridperformancewpf

I have a performance issue with the WPF DataGrid (.net 4.0)

first, some details:

  • I have a datagrid with an Observable collection as ItemsSource.
  • this observableCollection itself contains collections of objects, each collection hence being a row, each object being a cell ("logical" cell of course, not actual dataGridCell)

the reason why I do this is because I only know at runtime how many columns I will have in my dataGrid.

  • then I bind each DataGridCell's value to the value of the object in the "logical" table (= the collection of collections)

now the trouble I have is that I also have to be able to change whatever cell's Properties (like Background, Foreground, FontFamily, etc…) at any time while the app is running.

The solution I came up with is one involving setting the columns' cellStyles with bindings that bind to the "logical" cells' properties

here Is a sample code (no Xaml in my app):

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Width = 1200;
        Height = 780;
        Top = 60;
        Left = 200;

        DataGrid dg = new DataGrid();
        Content = dg;

        ObservableCollection<Row> Source = new ObservableCollection<Row>();
        dg.ItemsSource = Source;

        dg.SelectionMode = DataGridSelectionMode.Extended;
        dg.IsSynchronizedWithCurrentItem = true;

        dg.CanUserSortColumns = false;
        dg.CanUserReorderColumns = true;
        dg.CanUserResizeColumns = true;
        dg.CanUserResizeRows = true;
        dg.CanUserAddRows = false;
        dg.CanUserDeleteRows = false;

        dg.AutoGenerateColumns = false;

        dg.EnableColumnVirtualization = true;
        dg.EnableRowVirtualization = false;     // unuseful in my case : I alawys have less lines than the DG can contain

        dg.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
        dg.GridLinesVisibility = DataGridGridLinesVisibility.None;
        dg.HorizontalGridLinesBrush = Brushes.LightGray;

        dg.MinRowHeight = 20;
        dg.RowHeaderWidth = 20;

        for (int i = 0; i < 100; i++)
        {
            DataGridTextColumn column = new DataGridTextColumn();
            column.Binding = new Binding(String.Format(CultureInfo.InvariantCulture, "[{0}].Text", i));
            Style style = new Style(typeof(DataGridCell));
            style.Setters.Add(new Setter(DataGridCell.BackgroundProperty, new Binding(String.Format(CultureInfo.InvariantCulture, "[{0}].Background", i))));
            style.Setters.Add(new Setter(DataGridCell.ForegroundProperty, new Binding(String.Format(CultureInfo.InvariantCulture, "[{0}].Foreground", i))));
            column.CellStyle = style;
            column.Header = "Column " + i;
            dg.Columns.Add(column);
        }

        for (int i = 0; i < 35; i++)
        {
            Row dgRow = new Row();
            Source.Add(dgRow);
            for (int j = 0; j < 100; j++)
                dgRow.Add(new TextBox() { Text = "cell " + i + "/" + j, Background = Brushes.AliceBlue, Foreground = Brushes.BlueViolet });
        }
    }
}

public class Row : ObservableCollection<TextBox>
{
}

my problem is: with the VolumnVirtualisation On (I don't need row Virtualization in my case), the grid takes about 2sec to load, and then 1sec each time I move the horizontal scrollbar by a big leap (clic in the scrollBar bg, not the arrow)

this is too much for my purpose

so my question is: am I doing something wrong and if yes, what? what better way to do this do I have?

thanks for reading

Best Answer

If ColumnVirtualization make so problems, why do you need it? You can do a several improvements, but they can't solve the problem completely.

  1. Change TextBoxes for light-weight objects:

    public class TextItem
    {
        public string Text { get; set; }
        public Brush Background { get; set; }
        public Brush Foreground { get; set; }
    }
    
    
    public class Row : ObservableCollection<TextItem>
    {
    }
    
  2. Enable VirtualizingStackPanel: dg.SetValue(VirtualizingStackPanel.IsVirtualizingProperty, true);

  3. Replace styles with templates:

        for (int i = 0; i < 100; i++)
        {
            DataGridTemplateColumn column = new DataGridTemplateColumn();
            column.CellTemplate = (DataTemplate)XamlReader.Parse(
                "<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" +
                    "<TextBlock DataContext='{Binding [" + i + "]}' Text='{Binding Text}' Background='{Binding Background}' Foreground='{Binding Foreground}'/>" +
                "</DataTemplate>");
            column.Header = "Column " + i;
            dg.Columns.Add(column);
        }
    
Related Topic