I am using wpf datagrid to display large amounts of data (around 100 columns and 1000 rows). The columns are bound to properties dynamically added using typedescripter. By default the datagrid shows all the column however we have added functionality that allows user to only see subset of all columns and they can also change the order of displayed columns. I am currently achieving this by toggling the visibility property of the columns and changing their displayindex. However the performance of doing so really sucks.
Below is an example to reproduce the issue
The XAML looks pretty straight forward
<Window x:Class="WpfDataGridTestApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowState="Maximized">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Height="Auto" Margin="5">
<CheckBox x:Name="ApplyColumns" Width="200" Margin="5" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked">Show Predefined Columns</CheckBox>
</StackPanel>
<DataGrid
x:Name="Grid" EnableColumnVirtualization="False"
EnableRowVirtualization="False"
Grid.Row="1" SelectionUnit="Cell"
ItemsSource="{Binding MyDataView}">
</DataGrid>
</Grid>
The code behind is as follows
public partial class MainWindow : Window
{
/// <summary>
/// this dictionary stores the column name of columns to display and their displayIndex
/// </summary>
Dictionary<string,int> _predefinedColumns=new Dictionary<string, int>()
{
{"Column_8",0},
{"Column_9",1},
{"Column_11",2},
{"Column_14",3},
{"Column_12",4},
{"Column_34",5},
{"Column_78",6},
{"Column_54",7},
{"Column_88",8},
{"Column_98",9},
{"Column_90",10},
{"Column_51",11},
{"Column_100",12},
{"Column_35",13},
{"Column_112",14},
{"Column_101",15}
};
public MainWindow()
{
InitializeComponent();
DataContext = new MyClassViewModel();
}
/// <summary>
/// Toggle display of only subset of columns
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
if (ApplyColumns.IsChecked ?? false)
{
foreach (var col in this.Grid.Columns)
{
if (_predefinedColumns.ContainsKey(col.Header as string))
{
col.Visibility = Visibility.Visible;
col.DisplayIndex = _predefinedColumns[col.Header as string];
}
else
{
col.Visibility = Visibility.Collapsed;
}
}
}
else
{
foreach (var col in this.Grid.Columns)
{
col.Visibility = Visibility.Visible;
var header = col.Header.ToString();
col.DisplayIndex = Int32.Parse(header.Substring(7)) - 1;
}
}
}
}
This viewmodel reproduces large data using manually created DataTable. However in the actual code behind datagrid binds to class with dynamic property added using typedescripter
public class MyClassViewModel
{
public DataView MyDataView
{
get
{
var dt = new DataTable();
foreach (var colNum in Enumerable.Range(1, 120))
{
dt.Columns.Add(String.Format("Column_{0}", colNum), Type.GetType("System.Int32"));
}
var r = new Random();
for (int x = 1; x <= 1000; x++)
{
var dr = dt.NewRow();
foreach (var colNum in Enumerable.Range(1, 120))
{
dr[String.Format("Column_{0}", colNum)] = r.Next(100);
}
dt.Rows.Add(dr);
}
return dt.DefaultView;
}
}
}
I have tried the following but no luck so far
1. The performance is better if I turn on row and column virtualization. However this ruins the scrolling performance which is not acceptable (especially if you try drag the thumb).
2. Instead of changing display and visibility I tried removing all columns and then adding only the required ones but it did not effect performance either.
I will really appreciate any help with this. We don't want performance gains at the expense of adverse scrolling performance. So if virtualization needs to be turned on how can we improve scrolling performance. Or there any better way of achieving both good scrolling performance and good performance of column show/hide/move with such large datagrids.
You really should leave Virtualization on when using larger data sets, otherwise every cell is going through the layout / measure pass even if it's not rendered on screen. I've had some success by using ScrollViewer.IsDeferredScrollingEnabled="False" to tweak the scrolling behavior, but overall, haven't had much luck with performance with big datasets in the WPF datagrid.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With