我的(WPF Toolkit)DataGrid存在性能问题。它包含大约1.000行(只有8列),滚动速度非常慢且滞后。另外,包含DataGrid的Window的初始加载需要5-10秒。
我做了一些研究(使用谷歌和StackOverflow)但除了打开UI虚拟化的建议之外找不到任何东西。但即使在明确表示滚动仍然非常缓慢之后。
我的DataGrid绑定到ICollectionView / CollectionViewSource。它是在XAML中定义的(列是明确定义的,不是自动生成的):
<tk:DataGrid x:Name="dataGrid"
ItemsSource="{Binding Path=Bookings}"
AutoGenerateColumns="False"
Grid.Row="1"
EnableRowVirtualization="True"
EnableColumnVirtualization="True"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
...
</tk:DataGrid>
整个Window的DataContext设置为包含DataGrid绑定的ICollectionView的类的实例。
我发现的每篇博客或论坛帖子都赞扬了DataGrid的表现,所以我显然做了一些严重的错误。由于我对WPF很新,特别是对于DataGrid,我不知道如何改进它。 有人对我有什么建议吗?您对DataGrid的体验如何?我做错了什么?
编辑:按照this问题的建议,将所有列的宽度设置为“自动”。这确实不改变了糟糕的滚动性能。另外,我没有使用DataGridTemplateColumns(只是一些DataGridTextColumns和两个DataGridComboBoxColumns)。
Edit2:我用Snoop查看我的应用程序。我所看到的表明虚拟化确实在起作用(只有19行,而不是一千行)。但每行包含52个元素,因此这些元素总计超过千个元素。可能是一个问题?
非常感谢!
答案 0 :(得分:18)
DataGrid有一个附加属性 ScrollViewer.CanContentScroll ,用于管理此行为。要获得平滑滚动,您需要将其设置为 False 。
答案 1 :(得分:6)
在最终花时间针对WPF的最新版本构建我的应用程序后,滚动问题似乎完全消失了。因此,如果有人仍然使用DataGrid的工具包版本只是“更新”到框架中包含的版本,那么你应该没问题。
答案 2 :(得分:4)
我使用的是.NET 4.0,但仍然遇到了滚动性能问题。我所做的是 - 禁用虚拟化。我在DataGrid中将EnableRowVirtualization设置为'false'。这大大提高了滚动性能。
我建议不要假设WPF提供的任何内容在所有情况下都有用。
答案 3 :(得分:3)
您的数据网格包含哪些容器?例如 - 如果您将其放在滚动查看器中,则数据网格将增长以显示每一行,从而有效地禁用虚拟化(并且滚动查看器将使其在发生这种情况时显示正常)。确保数据网格大小有界。
它确实听起来像一个虚拟化的东西,如果这个建议不起作用通过分析器运行你的应用程序,以确保虚拟化正在发生。
编辑:这是一个如何使用snoop(或者我猜的是)来快速查看虚拟化是否正常工作的示例。 http://blogs.msdn.com/jgoldb/archive/2008/03/25/quick-tips-to-improve-wpf-app-memory-footprint.aspx
答案 4 :(得分:2)
您可以尝试在datagrid中逐个(或逐行)添加项目,并在每次添加后更新UI线程。 这样,用户看到加载发生,似乎应用程序什么都不做。 请参阅here此方法的更详细说明
答案 5 :(得分:2)
就初始加载而言,我发现扩展公共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<DataGridColumn>
{
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<int>(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;
答案 6 :(得分:0)
我发现将列的宽度设置为Auto
(默认值!)会在有许多单元格时引入很大的垂直滚动滞后。在我的情况下,切换到固定宽度很有帮助,尽管在有许多列的情况下仍然存在一些可检测到的滞后。
如果您担心用户不喜欢您选择的宽度,则可以在网格上设置CanUserResizeColumns="True"
。