WPF.DataGrid scrolling performance issue.

Son Thai 1 Reputation point
2021-02-01T10:22:32.92+00:00

I want to improve my current WPF DataGrid control to display a large of records, over 1 million rows and 100 columns.

Currently, WPF DataGrid has a scrolling issue when the number of rows is over 1000rows, it's very lagging.

I found a better scrolling in the HeidiSQL application (see gif below), how can I make my DataGrid like this?

Here is my sample project: https://github.com/son11592/large-data-grid/tree/master

62409-sample.gif

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,706 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,311 Reputation points
    2021-02-01T12:39:38.447+00:00

    Hi,
    please, correct errors:

     using LargeDataGrid.Source.Controls.Models;
     using System;
     using System.Collections.Generic;
     using System.Windows;
     using System.Windows.Controls;
     using System.Windows.Data;
     using System.Windows.Media;
    
     namespace LargeDataGrid.Source.Controls.Columns
     {
       public class TemplateColumn : DataGridTemplateColumn
       {
         public ColumnModel Column { get; set; }
    
         public void UpdateCellStyle()
         {
     !!!
           var key = Column.Index.ToString();
     !!!
           var cellStyle = new Style(typeof(DataGridCell));
           cellStyle.Setters.Add(new Setter(DataGridCell.BackgroundProperty, null));
           var newTrigger = new DataTrigger { Binding = new Binding($"{key}_background"), Value = "New" };
           newTrigger.Setters.Add(new Setter(DataGridCell.BackgroundProperty, Brushes.Green));
           var deletedTrigger = new DataTrigger { Binding = new Binding($"{key}_background"), Value = "Deleted" };
           deletedTrigger.Setters.Add(new Setter(DataGridCell.BackgroundProperty, Brushes.Red));
           var modifiedTrigger = new DataTrigger { Binding = new Binding($"{key}_background"), Value = "Modified" };
           modifiedTrigger.Setters.Add(new Setter(DataGridCell.BackgroundProperty, Brushes.Yellow));
           var focusedTrigger = new Trigger { Property = DataGridCell.IsFocusedProperty, Value = true };
           focusedTrigger.Setters.Add(new Setter(DataGridCell.BorderBrushProperty, Brushes.DarkRed));
           cellStyle.Triggers.Add(newTrigger);
           cellStyle.Triggers.Add(deletedTrigger);
           cellStyle.Triggers.Add(modifiedTrigger);
           cellStyle.Triggers.Add(focusedTrigger);
           CellStyle = cellStyle;
         }
     ...
    

    And it's better to use async binding:

    <UserControl x:Class="LargeDataGrid.Source.Controls.TableContent"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 mc:Ignorable="d"
                 d:DesignHeight="450" d:DesignWidth="800">
      <DataGrid Name="TableData" ItemsSource="{Binding View, IsAsync=True}"
                EnableRowVirtualization="True" EnableColumnVirtualization = "true"
                Background="Transparent" BorderThickness="0" BorderBrush="#DFDFDF"
                ScrollViewer.CanContentScroll="true" ScrollViewer.PanningMode="Both"
                VerticalGridLinesBrush="#DFDFDF" HorizontalGridLinesBrush="#DFDFDF"
                HeadersVisibility="Column" ColumnWidth="150" CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False"
                AlternationCount="2"
                Sorting="SortHandler" SelectionChanged="RowDidChange" PreparingCellForEdit="CellDidBeginditing" CellEditEnding="CellDidEndEditing"
                PreviewKeyDown="Keydown"
                VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsContainerVirtualizable="True" VirtualizingPanel.ScrollUnit="Pixel"
                VirtualizingPanel.CacheLengthUnit="Pixel" VirtualizingPanel.IsVirtualizingWhenGrouping="True"/>
    </UserControl>
    

    And code:

     using LargeDataGrid.Source.Controls.Columns;
     using LargeDataGrid.Source.Controls.Models;
     using System;
     using System.Collections.Generic;
     using System.ComponentModel;
     using System.Data;
     using System.Threading.Tasks;
     using System.Windows;
     using System.Windows.Controls;
     using System.Windows.Input;
     using System.Windows.Media;
    
     namespace LargeDataGrid.Source.Controls
     {
       public partial class TableContent : UserControl
       {
         #region Public Variables
         public bool IsFixedHeaderWidth = false;
         public double FixedHeaderWidth = 100;
         public readonly List<ColumnModel> ResColumns = new List<ColumnModel>();
         public readonly List<RowModel> ResRows = new List<RowModel>();
         private readonly DataTable Source = new DataTable();
         #endregion
    
         #region Private Variables
         private ColumnModel SortColumn;
         private int SortDirection;
         private bool IsEditing = false;
         private bool IsModified = false;
         #endregion
    
         #region Filtered Columns
         private List<ColumnModel> FilteredColumns = new List<ColumnModel>();
    
         public void UpdateFilteredColumns()
         {
           FilteredColumns = ResColumns;
         }
         #endregion
    
         //public TableContent()
         //{
         //  InitializeComponent();
         //  TableData.ItemsSource = Source.DefaultView;
         //  RenderData();
         //}
    
         public TableContent()
         {
           InitializeComponent();
           this.DataContext = this;
           RenderData();
           View = Source.DefaultView;
         }
    
         public DataView View { get; set; }
     ...