【问题标题】:WPF DataGrid is very slow to renderWPF DataGrid 渲染速度很慢
【发布时间】:2011-10-04 14:01:31
【问题描述】:

我已经尝试使用自定义的 DataGrid 以及 WPF 中的库存。我尝试过手动填充它们以及通过绑定填充它们。在这两种情况下,它们都很慢。

我有一个场景,用户单击一个按钮,然后出现一个带有适当数据的 DataGrid。目前我处于概念验证模式并且仅使用示例数据。我有一个包含 10 行的表的 DataSet。

如果我在单击按钮时没有将任何数据附加到 DataGrid,那么空的 DataGrid 会立即显示,用户不会察觉到延迟。我一添加 10 行数据,对于 6 列,延迟大约是 2 秒,对用户来说非常明显。

我什至尝试填充空数据,只是为了显示一个空网格,而且速度同样慢。

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

我放了一个计时器来计算从单击按钮到执行所有代码以绘制 DataGrid 时的滴答声,大约是 20 毫秒,因此代码执行得非常快,但在屏幕上是大滞后是。我尝试了一个 GridView,它在屏幕上的渲染速度非常快。

我听说过各种关于复杂场景和使用 1000 行的缓慢 DataGrid 绘制的报告,但这很简单,6 列 x 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 行数据集的方法。

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

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

【问题讨论】:

  • 我在另一个系统上也试过这个应用程序,它也很慢。问题是某些视图上有多个 DataGrid,因此每个额外的 DataGrid 延迟只会增加。
  • 我使用带有动态列和超过 10000 行的标准 wpf 数据网格,对此没有任何问题。你的物品来源是什么?数据表或某种集合?希望您没有像您发布的那样在 foreach 中添加项目??
  • 我在帖子中尝试了 for 循环,只是想看看它是否会有所作为,我不确定绑定是否是问题所在。在实际情况下,我有一个要绑定的 DataSet。我会更新帖子。
  • 我目前遇到了同样的问题,代码执行得非常快,但是 UI 会在 6 分钟内更新(我的 DataGrid 有超过 60k 项)。其他 cmets 似乎都没有帮助,您是否设法以某种方式修复它?

标签: wpf performance datagrid render


【解决方案1】:

你有吗:

  • 为网格启用VirtualizingStackPanel.VirtualizationMode?如果没有 - 尝试设置。
  • 为 DataGrid 设置 VirtualizingStackPanel.IsVirtualizing="true"
  • 用 StackPanel 容器包装了一个 Grid?如果是 - 尝试删除。
  • 通过外部 ScrollViewer 控件包装了 Grid?如果是 - 尝试删除。

还有一点, 您可以一次绑定整个项目集合,而不是将每个项目添加到 grid.Items 集合中吗?

【讨论】:

  • 尝试粘贴我的 XAML 但效果不佳,我将尝试更新我的原始问题。 DataGrid 包含在 DockPanel 中。对 ScrollViewer 不,我不引用 VirtualizingStackPanel.VirtualizationMode。
  • 尝试将 VirtualizingStackPanel.VirtualizationMode 设置为 Recycling,例如:
  • 感谢您的建议,但似乎没有帮助。
  • 感谢大佬的发帖,我没想到在堆栈面板中插入数据网格会导致渲染速度如此之快。就我而言,堆栈面板和外部的差异接近 100 倍。
  • @RayaChorbadzhiyska 是的。问题是阴影效果,在网格单元格中关闭它们,在网格容器中,关闭整个层次结构中的所有效果,看看会发生什么。我的网格容器有阴影效果。阴影效果非常低效。这解决了我的问题。
【解决方案2】:

DataGrid 性能问题的一般提示:我遇到了 DataGrid 的问题,在该问题中,在窗口调整大小、列排序等之后刷新需要几秒钟,并且在执行此操作时锁定了窗口 UI( 1000 行,5 列)。

这归结为 WPF 大小计算的问题(错误?)。我把它放在一个带有RowDefinitionHeight="Auto"的网格中,这导致渲染系统在运行时通过测量每一列和每一行的大小来尝试重新计算DataGrid的大小,大概是通过填充整个网格(据我了解)。它应该以某种方式智能地处理这个问题,但在这种情况下它不是。

快速检查这是否是相关问题是将 DataGrid 的 HeightWidth 属性设置为测试期间的固定大小,然后再次尝试运行。如果您的性能得到恢复,则可以使用以下选项进行永久性修复:

  • 将包含元素的大小更改为相对 (*) 或 固定值
  • 将DataGrid的MaxHeightMaxWidth设置为更大的固定值 比正常使用时更容易
  • 尝试使用不同大小调整策略的其他容器类型 (Grid, DockPanel等)

【讨论】:

  • 我在布局网格的星形行中包含的 DataGrid 遇到了同样的问题。按照建议设置 MaxHeight 就像一个魅力。
【解决方案3】:

在我的情况下,我遇到了 DataGridCell ControlTemplate 的问题,它减慢了渲染速度。

请注意,在 ReadOnly 模式下使用 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>

【讨论】:

    【解决方案4】:

    我有一个 Surface Pro 3,我的数据网格有大约 200 行和 10 列,滚动速度非常慢、生涩和犹豫。

    我以为是网络问题,其实是显卡跟不上 - 等等 - 数据网格本身的阴影效果,即使控件的背景设置为纯色。

    我把效果注释掉了,快了4-5倍。

    希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      A blog 我在 Google 上找到了一种解决方案。正如作者所说,我禁用了 GroupStyle,渲染速度问题得到了解决。但我需要分组。作者说

      VirtualizingPanel.IsVirtualizingWhenGrouping
      

      已添加到 .NET 4.5。所以我把它设置为真。现在通过分组快速渲染。问题是......滚动是生涩的。不是不可接受的生涩,而是明显生涩。当我尝试创建一个扩展了 2000 多个节点的 TreeView 时,我遇到了类似的问题。如果没有虚拟化,渲染速度很慢,但滚动很流畅。使用虚拟化,渲染速度很快,但滚动很生涩。

      为什么我们不能两者兼得……

      【讨论】:

      • 这一行解决了我的确切问题 - 非常感谢!当我终于意识到渲染是真正的问题时,我正在搞乱我用来加载数据的异步任务。添加了VirtualizingPanel.IsVirtualizingWhenGrouping="True",我的 DataGrid 的数量现在从大约 10 秒减少到不到 1 秒。
      • 这个也对我有用!从 10-30 秒下降到不到 1 秒。
      • 不使用分组有什么解决办法?
      【解决方案6】:

      绑定数据网格也有同样的问题,我注意到在第一次加载时它很快,但在第二次和下一次加载时很慢。所以当我添加代码时

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

      【讨论】:

      • 对不起,我可以知道更多细节吗?
      • 需要更多细节,因为您可以看出数据网格似乎存在很多性能问题。
      【解决方案7】:

      对我来说是:

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

      我从样式中删除了它,渲染变得很快。

      【讨论】:

      • 为了澄清,将 ScrollViewer.CanContentScroll 设置为 true 作为 false 的值将禁用虚拟化。
      • 如果 CanContentScroll 为 false,我有 20 秒的加载时间……如果为 true,加载时间是即时的。但是平滑滚动消失了。
      【解决方案8】:

      好吧,添加更多内容(我知道它很老的话题,但它仍然可以帮助某人)...

      我试过了

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

      对于 DataGrid(AutoGenerateColumns="True") 绑定到 DataTable.DefaultView() 并且对速度没有影响,它对于速度以及行之间的导航仍然很糟糕。然后,我想出了设置 DataGrid 的固定高度和宽度的解决方案。另外我还设置了

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

      这使我的页面填充得非常快...而不是 2 分钟,现在只需 10-12 秒。

      希望对某人有所帮助。

      注意:我使用的是 .Net 4.5

      【讨论】:

        【解决方案9】:

        我遇到了 1000 行 5 列的渲染时间需要 7-10 秒的大问题,但在 https://www.elegant-software.net/2014/05/performance-of-the-wpf-datagrid.html 找到的解决方案使网格立即加载!

        <DataGrid
           EnableRowVirtualization="True"
           EnableColumnVirtualization="True">
        

        【讨论】:

        • 作为对此的快速更新 - 在我的场景中,我在每行末尾都有一个复选框,供用户选择他们需要的行,一旦完成,他们将提交所选的行,但我发现当启用行虚拟化时,由于其仅呈现屏幕上的内容的性质,它不会计算屏幕上不可见的选定行,这会导致几个问题。要打击此操作,请在选择行时将所选ID添加/删除到Hashset变量,然后以这种方式跟踪它们 span>
        【解决方案10】:

        我的问题是我在 DataGrid 上设置了ScrollViewer.CanContentScroll="False"。这将禁用 DataGrid 的所有虚拟化。更多信息可以在这里找到:

        https://stackoverflow.com/a/3724695/4383302

        【讨论】:

          【解决方案11】:

          如果你有像 belove 这样的行定义:

           <Grid.RowDefinitions>
                  <RowDefinition x:Name="topRow" Height="*"/>
                  <RowDefinition x:Name="mainRow" Height="*"/>
                  <RowDefinition x:Name="dataGridRow" Height="*"/>
              </Grid.RowDefinitions>
          

          你一定要小心!例如,如果您的 Datagrid 在其中一行中,那么它将一遍又一遍地为每一行调整大小。如果您有 1000 行,那么它将被调整为您的 Datagrid 的 1000 倍!

          让我们告诉您您的 Datagrid 在 3rd RowDefinition 中,那么我建议您以这种方式更改代码。

               <Grid.RowDefinitions>
                  <RowDefinition x:Name="topRow" Height="*"/>
                  <RowDefinition x:Name="mainRow" Height="*"/>
                  <RowDefinition x:Name="dataGridRow" Height="400"/>
              </Grid.RowDefinitions>
          

          当然你也可以随心所欲地改变“400”。

          【讨论】:

            猜你喜欢
            • 2018-08-08
            • 2013-09-22
            • 1970-01-01
            • 2013-08-18
            • 2015-07-17
            • 2015-04-15
            • 1970-01-01
            • 2014-07-25
            • 2015-05-23
            相关资源
            最近更新 更多