WPF Toolkit DataGrid滚动性能问题 – 为什么?

我的(WPF Toolkit)DataGrid存在性能问题。 它包含大约1.000行(只有8列),滚动速度非常慢且滞后。 另外,包含DataGrid的Window的初始加载需要5-10秒。

我做了一些研究(使用谷歌和StackOverflow)但除了打开UI虚拟化的建议之外找不到任何东西。 但即使在明确地允许滚动仍然非常缓慢之后。

我的DataGrid绑定到ICollectionView / CollectionViewSource。 它是在XAML中定义的(列是明确定义的,不是自动生成的):

 ...  

整个Window的DataContext设置为包含DataGrid绑定的ICollectionView的类的实例。

我发现的每篇博客或论坛post都赞扬了DataGrid的表现,所以我显然做了一些严重的错误。 由于我对WPF一般都是新手,特别是对于DataGrid,我不知道如何改进它。 有人对我有什么建议吗? 您对DataGrid的体验如何? 我究竟做错了什么?

编辑:只需按照此问题的建议将所有列的宽度设置为“自动”。 这并没有改变糟糕的滚动性能。 另外,我没有使用DataGridTemplateColumns(只是一些DataGridTextColumns和两个DataGridComboBoxColumns)。

Edit2:我用Snoop查看我的应用程序。 我所看到的表明虚拟化确实在起作用(只有19行,而不是一千行)。 但每行包含52个元素,因此这些元素总计超过千个元素。 可能是一个问题吗?

非常感谢!

DataGrid有一个Attached属性ScrollViewer.CanContentScroll ,用于管理此行为。 要获得平滑滚动,您需要将其设置为False

在最终花时间针对WPF的最新版本构建我的应用程序之后,滚动问题似乎完全消失了。 因此,如果任何人仍然使用DataGrid的工具包版本只是“更新”到框架中包含的版本,你应该没问题。

我使用.NET 4.0仍然得到滚动性能问题。 我所做的是 – 禁用虚拟化。 我在DataGrid中将EnableRowVirtualization设置为’false’。 这大大改善了滚动性能。

我建议不要假设WPF提供的任何内容在所有情况下都有用。

您的数据网格容纳在哪个容器中? 例如 – 如果将其放在滚动查看器中,则数据网格将增长以显示每一行,从而有效地禁用虚拟化(并且滚动查看器将使其在发生这种情况时显示正常)。 确保数据网格大小有界。

它确实听起来像一个虚拟化的东西,如果这个建议不起作用通过分析器运行您的应用程序,以确保虚拟化正在发生。

编辑:这是一个如何使用snoop(或者我想是鼹鼠)快速查看虚拟化是否正常工作的示例。 http://blogs.msdn.com/jgoldb/archive/2008/03/25/quick-tips-to-improve-wpf-app-memory-footprint.aspx

您可以尝试在datagrid中逐个(或逐行)添加项目,并在每次添加后更新UI线程。 这样,用户就会看到加载发生,并且看起来应用程序似乎什么都不做。 在这里看到这种方法的更详细的描述

就初始加载而言,我发现扩展公共API以显着改善大量列加载是必要的 – 我们谈论的时间不到一秒钟。 也就是说,我在滚动性能方面遇到了类似的问题,即使500多列的滚动速度也很慢。

在我的派生数据网格中设置列:

 var columns = new DataGridColumnCollection(true, dataGrid); for (int i = 0; i < pivotTable.DetailsColumnCount; i++) { if (!pivotTable.NullColumns.Contains(i)) { columns.Add(new PivotDetailColumn(pivotTable, i)); } } columns.ForceUpdate(); dataGrid.Columns = columns; dataGrid.ItemsSource = Enumerable.Range(0, pivotTable.DetailsRowCount) .Where(i => !pivotTable.NullRows.Contains(i)) // Only non null rows .ToList(); 

修复DataGridColumnCollection:

 public class DataGridColumnCollection : ObservableCollection { private bool _DeferColumnChangeUpdates = false; public DataGridColumnCollection(bool deferColumnChangeUpdates, DataGrid dataGridOwner) : this(dataGridOwner) { _DeferColumnChangeUpdates = deferColumnChangeUpdates; } public DataGridColumnCollection(DataGrid dataGridOwner) { Debug.Assert(dataGridOwner != null, "We should have a valid DataGrid"); DisplayIndexMap = new List(5); _dataGridOwner = dataGridOwner; RealizedColumnsBlockListForNonVirtualizedRows = null; RealizedColumnsDisplayIndexBlockListForNonVirtualizedRows = null; RebuildRealizedColumnsBlockListForNonVirtualizedRows = true; RealizedColumnsBlockListForVirtualizedRows = null; RealizedColumnsDisplayIndexBlockListForVirtualizedRows = null; RebuildRealizedColumnsBlockListForVirtualizedRows = true; } #region Protected Overrides public void ForceUpdate() { if (DisplayIndexMapInitialized) { UpdateDisplayIndexForNewColumns(this, 0); } InvalidateHasVisibleStarColumns(); } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: if (!_DeferColumnChangeUpdates) { if (DisplayIndexMapInitialized) { UpdateDisplayIndexForNewColumns(e.NewItems, e.NewStartingIndex); } InvalidateHasVisibleStarColumns(); } break;