WPF数据网格的渲染速度非常慢。

46

我曾尝试使用自定义的 DataGrid,也试过 WPF 自带的 DataGrid。无论是手动填充还是通过绑定数据,两种情况下都很慢。

我的场景是用户点击按钮后,会出现一个包含相应数据的 DataGrid。目前我处于概念验证模式,只使用示例数据。我有一个包含 10 行数据的表格 DataSet。

如果我在点击按钮时不将任何数据附加到 DataGrid 上,则空的 DataGrid 几乎瞬间显示,用户无法察觉到延迟。但是一旦添加了10行具有6个列的数据,延迟就会约为2秒钟,对用户来说非常明显。

我甚至试图填充空数据,只是为了让空的网格出现,但速度同样很慢。

for (int i = 0; i < 10; i++)
    _dataGrid.Items.Add("");

我在点击按钮后设置了一个计时器来计算从点击到执行所有代码以绘制DataGrid所需的时间,大约为20毫秒,因此代码执行非常快,但是屏幕上存在很大的延迟。我尝试了GridView,它在屏幕上呈现得更快。

我听说过在复杂场景下使用1000多行时DataGrid绘制速度慢的各种报道,但这是最简单的情况,只有6列和10行填充了空数据。

对于只读显示,GridView是否与DataGrid具有同样可行性?


更新:

以下是我的列的创建方式。

                DataGridTextColumn column = new DataGridTextColumn();
                column.ColumnWidthChanged += new ColumnWidthChangedEventHandler(column_ColumnWidthChanged);

                column.Header = entity.GetPropertyValue("ColumnLabel");
                column.Binding = new Binding(entity.GetPropertyValue("Tag"));
                column.Width = new DataGridLength(entity.GetPropertyDouble("DisplaySize"));
                _dataGrid.Columns.Add(column);

以下是我如何绑定含有10行数据的DataSet。

                _dataGrid.ItemsSource = ds.Tables[0].DefaultView;
                _dataGrid.DataContext = ds.Tables[0];

我不确定我能做些什么不同的事情。


我也在另一个系统上尝试过该应用,但速度同样很慢。问题在于一些视图上有多个 DataGrid,因此每增加一个 DataGrid,延迟时间就会相应增加。 - David Gunther
我使用标准的WPF DataGrid,具有动态列和超过10000行,并且没有任何问题。你的ItemSource是什么?是DataTable还是某种集合?希望你没有像你发布的那样使用foreach添加项? - blindmeis
我尝试了与帖子中相同的for循环,只是为了看看它是否会有所不同,我不确定绑定是否是问题所在。在实际情况中,我有一个要绑定的DataSet。我将更新帖子。 - David Gunther
1
非常相关:https://dev59.com/LHRB5IYBdhLWcg3wLUu3#7413000 - Robert Harvey
我目前也遇到了同样的问题,代码执行得非常快,但UI更新需要6分钟(我的DataGrid有超过60k个项目)。其他评论似乎都没有帮助,你设法解决了吗? - Raya
11个回答

41

您有以下问题吗:

  • 为Grid启用了VirtualizingStackPanel.VirtualizationMode吗?如果没有,请尝试设置。
  • 为DataGrid设置了VirtualizingStackPanel.IsVirtualizing="true"吗?
  • 使用StackPanel容器包装了Grid吗?如果是,请尝试去除。
  • 使用外部ScrollViewer控件包装了Grid吗?如果是,请尝试去除。

另外一个要点, 您能否一次绑定整个项集合,而不是将每个项添加到grid.Items集合中?


谢谢您的建议,但似乎并没有起到帮助的作用。 - David Gunther
你肯定是尝试将这个属性添加到 DataGrid 控件而不是 Grid 控件吧?另外,试试为 DataGrid 设置 VirtualizingStackPanel.IsVirtualizing="true"。 - sll
3
谢谢你的帖子,我没想到在 StackPanel 中插入 DataGrid 会导致渲染速度如此之慢。在我的情况下,与放在外部相比,差别几乎达到了100倍。 - Vahagn Nahapetyan
@HrvojeBatrnek,这些对我也没有用,你找到任何解决方案了吗? - Raya
1
@RayaChorbadzhiyska 是的。问题在于阴影效果,在网格单元格中关闭它们,在网格容器中关闭整个层次结构中的所有效果,看看会发生什么。我的网格容器有阴影效果。阴影效果非常低效。这解决了我的问题。 - Hrvoje Batrnek
显示剩余4条评论

34
一条关于 DataGrid 性能问题的普遍提示:我在使用 DataGrid 时遇到一个问题,窗口调整大小、列排序等操作需要几秒钟才能刷新,而且在此期间 UI 界面会被锁定(1000 行,5 列)。
问题源于 WPF 大小计算的问题(是否为 bug 尚不确定)。我将其放在了一个包含 RowDefinition 的网格中,而该 RowDefinitionHeight="Auto" 属性导致渲染系统尝试在运行时通过测量每个行和列的大小来重新计算 DataGrid 的大小,可能是通过填充整个网格来完成的(据我所知)。它应该能够以某种智能的方式处理这个问题,但在这种情况下它没有这样做。
要快速检查是否存在相关问题,可以将 DataGrid 的 HeightWidth 属性设置为固定大小,然后再次运行测试。如果性能得到恢复,则可采用以下永久性修复方案之一:
  • 更改包含元素的大小为相对(*)或固定值
  • 将 DataGrid 的 MaxHeightMaxWidth 设置为大于正常使用情况下可能达到的固定值
  • 尝试使用其他容器类型,采用不同的调整策略(如 GridDockPanel 等)

5
我曾在一个布局 Grid 的 star 行中包含一个 DataGrid 时遇到同样的问题。按照建议设置 MaxHeight 即可完美解决。 - EagleBeak

19

我在Google上找到的一篇博客给了我一个部分解决方案。正如作者所说,我禁用了GroupStyle,渲染速度问题得到了解决。但我仍需要进行分组。作者提到:

VirtualizingPanel.IsVirtualizingWhenGrouping

在.NET 4.5中添加了虚拟化。所以我将其设置为true。现在分组渲染很快,但问题是……滚动不够流畅。不是不能接受的卡顿,但还是能够明显察觉到。当我尝试创建一个展开了2000个以上节点的TreeView时,我也遇到了类似的问题。没有虚拟化时,渲染速度慢但滚动很流畅。使用虚拟化后,渲染很快但滚动很卡。

为什么我们不能两者兼得呢...


1
这一行代码解决了我的确切问题 - 非常感谢!我一直在尝试使用异步任务来加载数据,最终意识到渲染才是真正的问题。添加了 VirtualizingPanel.IsVirtualizingWhenGrouping="True" 后,我的 DataGrid 的填充时间从大约 10 秒减少到不到一秒。 - M463
这个对我也起作用了!从10-30秒降到不到1秒。 - Will Wainwright
不使用分组时的解决方案是什么? - AndrewRalon
这对我也是解决方案。但是,“为什么我们不能两者兼得……?”是一个非常好的问题。 - h.m.i.13

12

在我的情况下,我遇到了一个DataGridCell ControlTemplate的问题,它使得渲染速度变慢。

请注意,对于大型数据集,相对加载速度使用非可选文本的TextBlock或只读模式下的TextBox截然不同:

加载时间为59秒:

<Style TargetType="{x:Type DataGridCell}" x:Key="DataGridCellTextStyle">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <TextBox IsReadOnly="True" Text="{Binding Mode=OneWay}"/> 
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

加载时间21秒:

<Style TargetType="{x:Type DataGridCell}" x:Key="DataGridCellTextStyle">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                     <ContentPresenter Content="{Binding}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

加载时间 16 秒:

<Style TargetType="{x:Type DataGridCell}" x:Key="DataGridCellTextStyle">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <TextBlock Text="{Binding}"></TextBlock>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

7

稍微多加一些内容(我知道这是一个非常旧的话题,但仍然可以帮助一些人)...

我尝试过

EnableColumnVirtualization="True" VirtualizingPanel.VirtualizationMode="Recycling"
EnableRowVirtualization="True" 

对于绑定到DataTable.DefaultView()的DataGrid(AutoGenerateColumns="True"),即使没有影响速度,但在速度和行之间导航时仍然非常糟糕。因此,我想到了设置DataGrid的固定高度和宽度的解决方案。另外,我还设置了

RowHeight="23" 
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollBarVisibility="Visible"

这使得我的页面加载速度非常快...现在只需要10-12秒,而不是2分钟。
希望能对某些人有所帮助。
注意:我正在使用 .Net 4.5。

5

对我而言,这是:

<Setter Property='ScrollViewer.CanContentScroll' Value='False' />

我将这个从样式中移除,渲染速度变得更快了。

1
请注意,将ScrollViewer.CanContentScroll设置为“true”,而不是“false”作为值,将禁用虚拟化。 - Slate
将CanContentScroll属性设置为false时,加载时间为20秒... 将其设置为true,则加载时间即时。但平滑滚动效果消失了。 - Welcor

5

2
关于这个问题的快速更新 - 在我的场景中,我在每一行的末尾都有一个复选框供用户选择他们需要的行,完成后,他们会提交所选内容,但是当启用行虚拟化时,由于它只呈现屏幕上的内容,它不会计算未在屏幕上可见的选定行,这导致了一些问题。为了解决这个问题,我添加/删除了选定的ID到哈希集变量中,每当行被选中时,以此方式跟踪它们。 - Nick

2
我有一台Surface Pro 3电脑,其中我的数据网格(大约200行和10列)在滚动时非常缓慢、卡顿和犹豫不决。起初我认为是网络问题,但实际上是因为显卡无法跟上数据网格本身的阴影效果 - 尽管控件的背景设置为纯色。我注释掉了这个效果,速度快了4-5倍。希望这可以帮到你。

0

我遇到了与绑定数据网格相同的问题,我注意到在第一次加载时速度很快,但在第二次和以后就变慢了。所以当我在代码中添加

DataGrid.ItemsSource = Nothing 然后 TableAdapter.Fill(Mydataset.MyStoredProcedure,....) DataGrid.ItemsSource=Mydataset.MyStoredProcedure 它变得非常快


2
抱歉,我可以了解更多细节吗? - Po-Sen Huang
需要更多细节,正如您所看到的,数据网格存在许多性能问题。 - bjhuffine

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接