提高 WPF DataGrid 性能

问题描述 投票:0回答:7

在我的

.NET 3.5
WPF
应用程序中,我有一个
WPF
DataGrid
,它将填充 500 列和 50 行。 应用程序的性能在滚动时非常非常差,或者当我执行
DataGrid.Items.Refresh()
或选择行时。

实际上应用程序将需要大约 20 秒来更新布局。

Layout_Updated()
事件将在 20 秒后触发。

如果我将列数减少到 50 或更少,应用程序的响应速度将会非常快。根据我的发现,性能与列数直接相关。

如何提高

DataGrid
性能?

c# wpf datagrid wpfdatagrid
7个回答
94
投票

您可以打开一些选项来帮助您处理 DataGrid 对象

EnableColumnVirtualization = true
EnableRowVirtualization = true

这两个是我认为可能有帮助的主要内容。接下来尝试使您的绑定异步

ItemsSource="{Binding MyStuff, IsAsync=True}"

最后,我听说设置最大高度和宽度可以有所帮助,即使它高于最大屏幕尺寸,但我自己没有注意到差异(声称与自动尺寸测量有关)

MaxWidth="2560"
MaxHeight="1600"

也永远不要将

DataGrid
放入
ScrollViewer
中,因为你基本上会失去虚拟化。让我知道这是否有帮助!


11
投票

检查您是否有属性

ScrollViewer.CanContentScroll
设置
False
。 将此属性设置为 false 会禁用虚拟化,从而降低数据网格的性能。有关更多说明,请参阅此CanContentScroll


3
投票

设置

DataGrid.RowHeight
值,这将产生巨大的差异。

我知道这是一个非常老的问题,但我刚刚遇到它,这是我最大的不同。我的默认高度是 25。


1
投票

第1步:从2分钟到10秒

这个答案(将 ScrollViewer.CanContentScroll 设置为 True)让我走上了正确的道路。但我需要将其设置为

false
。为了在刷新时将其设置为
true
,我编写了这两个方法。

internal static void DataGridRefreshItems(DataGrid dataGridToRefresh)
{
    /// Get the scrollViewer from the datagrid
    ScrollViewer scrollViewer = WpfToolsGeneral.FindVisualChildren<ScrollViewer>(dataGridToRefresh).ElementAt(0);
    bool savedContentScrollState = scrollViewer.CanContentScroll;
    scrollViewer.CanContentScroll = true;

    dataGridToRefresh.Items.Refresh();

    /// Was set to false, restore it
    if (!savedContentScrollState)
    {
        /// This method finishes even when the update of the DataGrid is not 
        /// finished. Therefore we use this call to perform the restore of
        /// the setting after the UI work has finished.
        Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => SetScrollViewerCanContentScrollFalse(scrollViewer)), DispatcherPriority.ContextIdle, null);
    }
}

private static void SetScrollViewerCanContentScrollFalse(ScrollViewer scrollViewer)
{
    scrollViewer.CanContentScroll = false;
}

这是我用来获取 VisualChildren 的方法:

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            if (child != null && child is T)
            {
                yield return (T)child;
            }

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}

在此之后,我刷新 50.000 个新项目仅持续 10 秒(与 2 分钟不同),并且仅消耗 2 MB RAM,而不是之前的 4 GB。

第2步:从10秒到0.5秒

为了测试,我禁用了所有

IValueConverter
并实现了直接绑定的属性。如果没有转换器,DataGrid 会立即刷新。所以我就留下了。


0
投票

也许可以尝试这个,而不是一次加载所有 50 行

http://www.codeproject.com/Articles/34405/WPF-Data-Virtualization


0
投票

我发现对加载和滚动性能最好的折衷方案是为所有列的绑定设置

IsAsync=True
,而不是 DataGrid ItemsSource 绑定。示例:

<DataGridTextColumn Binding="{Binding Path=MaterialName, Mode=OneTime, IsAsync=True}" Header="Name" />

顺便说一句,当 DataGrid 上的虚拟化关闭时,此解决方案效果更好。不过,即使开启了虚拟化,仍然值得一试。此外,当应用于显示图像等的 DataGridTemplateColumn 时,此解决方案非常有效。


0
投票

我在 ScrollViewer 中有一个 DataGrid,允许

DataGrid
增长到无限高度。将 DataGrid 的
Height
MaxHeight
设置为合理的值可以解决我的大部分性能问题。

© www.soinside.com 2019 - 2024. All rights reserved.