【问题标题】:Improve WPF DataGrid performance提高 WPF 数据网格性能
【发布时间】:2012-11-25 17:16:01
【问题描述】:

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

实际上 App 大约需要 20 秒来更新布局。 Layout_Updated() 事件将在 20 秒后触发。

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

如何提高DataGrid 的性能?

【问题讨论】:

  • 列数超过 10 列的网格可能不是一个好主意。但是考虑Custom Paging
  • @Boomer 真的吗?见过外汇网格吗?
  • @WPFK 您是否考虑过使用针对性能进行了优化的第三方网格?
  • @TomTom - 你能告诉我一些第三方网格吗?
  • 我不知道什么是外汇,但我认为任何理智的人都不会滚动浏览 500 列数据。

标签: c# wpf datagrid wpfdatagrid


【解决方案1】:

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

EnableColumnVirtualization = true
EnableRowVirtualization = true

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

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

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

MaxWidth="2560"
MaxHeight="1600"

也永远不要将DataGrid 放在ScrollViewer 中,因为您实际上会失去虚拟化。让我知道这是否有帮助!

【讨论】:

  • 我也会让你的列固定宽度。
  • @testpattern datagrid 会自行滚动,您只是不想将其放在 DataGrid 外部的您自己的 ScrollViewer 中,否则您将失去控件的虚拟化。
  • 太棒了。我想知道为什么其他线程从未谈论过这个 Enable Row and Column Virtualization。非常感谢。
  • 绝对值得一试!事实上,他们为我提高了很多性能。谢谢@艾伦
  • 设置 MaxHeight 取得了显着的改进。非常感谢。设置 MaxWidth 也略有改进。在我找到这个解决方案之前,我快疯了。谢谢。
【解决方案2】:

检查您是否有属性ScrollViewer.CanContentScroll 设置False。 将此属性设置为 false 会以某种方式禁用虚拟化,从而降低数据网格的性能。有关更多说明,请参阅CanContentScroll

【讨论】:

    【解决方案3】:

    设置DataGrid.RowHeight 值,这将产生巨大的影响。

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 感谢您的建议。但我要求一次有 500 列。
      • 好吧,您说滚动,所以我认为您不会一次显示所有行(无论如何,您如何使用 500 列做到这一点)数据虚拟化的想法是您加载某个数字来填充您的网格,然后在滚动时删除和替换行
      【解决方案5】:

      第 1 步:2 分钟到 10 秒

      这个答案 (Set ScrollViewer.CanContentScroll to 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。

      第二步:10秒到0.5秒

      为了测试,我禁用了我的所有IValueConverter 并实现了我直接绑定的属性。如果没有转换器,DataGrid 会立即刷新。所以我离开了。

      【讨论】:

        猜你喜欢
        • 2011-03-31
        • 2010-10-16
        • 1970-01-01
        • 1970-01-01
        • 2022-08-17
        • 2011-09-10
        • 2010-12-13
        相关资源
        最近更新 更多