即使使用 UI 虚拟化,Datagrid 的性能也非常低

发布于 2024-11-08 14:20:55 字数 3820 浏览 4 评论 0原文

我目前正在使用数据网格。 大约 24 列是在 C# 中动态创建的。

我的 DataGrid 中始终有大约 300 个条目(并且由于一个条目代表一个“标题”,所以我无法创建分页系统,因为我必须在同一页面中获取所有数据)。

它工作得很好,但如果我使用 DataGridTemplateColumns (因为我需要一个带有分隔符和 2 个标题的样式化列标题,因为我需要每列上有 2 个子列)和单元格模板(仍然是因为我需要这 2 个子列),它具有双重绑定(每个子列一个绑定),当我加载网格时,它无法使用...

我尝试了所有类型的虚拟化(StackPanel、RowVirtualization、具有所有不同类型的值组合的列虚拟化)。 我可以获得的“最佳”性能是将 RowVirtualization 和 ColumnVirtualization 设置为 True。

它现在“可用”,但当我进行水平滚动时仍然非常慢(即使有一点图形错误,因为我使用了 FrozenColumn...)

我什至尝试使用我自己的 ListView / GridView,并在处理了几个小时之后(在为了重现冻结的列等...)仍然存在相同的“问题”。

不可能使用数据虚拟化(因为“只有”24 列和 285 行,所以用户根本不友好)。

谢谢 !

编辑1:这是生成列的代码

        ColumnCollection = new ObservableCollection<DataGridColumn>();
        DataGridTemplateColumn firstDtc_l = new DataGridTemplateColumn();
        firstDtc_l.Header = "Titles";
        FrameworkElementFactory spFactory_l = new FrameworkElementFactory(typeof(Grid));
        ColumnCollection.Add(firstDtc_l);
        int i = 0;

        foreach (string s in DynamicColumns)
        {
            DataGridTemplateColumn dtc_l = new DataGridTemplateColumn();
            Binding bindColor = new Binding();
            bindColor.Converter = new ChangedColorConverter();
            bindColor.ConverterParameter = "Column" + i;

            //DataTemplate
            DataTemplate dt_l = new DataTemplate("MyObject");
            spFactory_l = new FrameworkElementFactory(typeof(Grid));
            spFactory_l.Name = "CellTemplate";
            FrameworkElementFactory columnDefinition1 = new FrameworkElementFactory(typeof(ColumnDefinition));
            FrameworkElementFactory columnDefinition2 = new FrameworkElementFactory(typeof(ColumnDefinition));
            FrameworkElementFactory border1 = new FrameworkElementFactory(typeof(Border));
            border1.SetValue(Grid.ColumnProperty, 0);
            border1.SetValue(Border.BorderBrushProperty, Brushes.Gray);
            border1.SetValue(Border.BorderThicknessProperty, new Thickness(0,0,0,0));
            FrameworkElementFactory border2 = new FrameworkElementFactory(typeof(Border));
            border2.SetValue(Grid.ColumnProperty, 1);
            border2.SetValue(Border.BorderBrushProperty, Brushes.Gray);
            border2.SetValue(Border.BorderThicknessProperty, new Thickness(1, 0, 0, 0));
            FrameworkElementFactory textBlock1 = new FrameworkElementFactory(typeof(TextBlock));
            textBlock1.SetValue(Grid.ColumnProperty, 0);
            textBlock1.SetValue(TextBlock.ForegroundProperty, bindColor);
            Binding firstBind = new Binding("MyObject[Column"+i+"].FirstBinding");
            textBlock1.SetValue(TextBlock.TextProperty, localBind);
            FrameworkElementFactory textBlock2 = new FrameworkElementFactory(typeof(TextBlock));
            Binding secongBind = new Binding("MyObject[Column" + i + "].SecondBinding");
            textBlock2.SetValue(Grid.ColumnProperty, 0);
            textBlock2.SetValue(TextBlock.TextProperty, firstBind) 
            textBlock2.SetValue(TextBlock.ForegroundProperty, secongBind);
            border1.AppendChild(textBlock1);
            border2.AppendChild(textBlock2);

            spFactory_l.AppendChild(columnDefinition1);
            spFactory_l.AppendChild(columnDefinition2);
            spFactory_l.AppendChild(border1);
            spFactory_l.AppendChild(border2);
            dt_l.VisualTree = spFactory_l;

            dtc_l.Width = DataGridLength.Auto;
            dtc_l.CellTemplate = dt_l;
            dtc_l.Header = s;
            ColumnCollection.Add(dtc_l);
            i++;
        }   

DataGrid 绑定到“TheObject”的集合。 TheObject 类有一个 public Dictionary。 MyObject { 获取;放; } MyCell 类具有 FirstBinding 和 SecondBinding 属性(字符串)。

I'm currently using a DataGrid.
about 24 columns are created dynamically in C#.

There's always about 300 entries in my DataGrid (and since one entry represent a "title", I can't create paging systems, cause I have to get all the data in the same page).

It works well, but if I use DataGridTemplateColumns (because I need a styled column header which have a separator and 2 titles, as I need 2 sub columns on each column) and cell templates (still because I need these 2 sub columns), which has a double-binding (one binding for each sub column), when I load the Grid, it's just unusable...

I tried ALL types of virtualization (StackPanel, RowVirtualization, ColumnVirtualization with all different types of value combinations).
The "best" performance I could get is with the RowVirtualization and ColumnVirtualization set to True.

It's now "usable", but still very slow when I do horizontal scrolling (even with a little graphic bug since I use a FrozenColumn...)

I even tried using my own ListView / GridView, and after working on it for hours (in order to reproduced the frozen column, etc...) There's still the same "issue".

It's not possible to use Data Virtualization (since there's "only" 24 columns with 285 rows, it will not user friendly at all).

Thanks !

EDIT 1 : Here is the code generating the columns

        ColumnCollection = new ObservableCollection<DataGridColumn>();
        DataGridTemplateColumn firstDtc_l = new DataGridTemplateColumn();
        firstDtc_l.Header = "Titles";
        FrameworkElementFactory spFactory_l = new FrameworkElementFactory(typeof(Grid));
        ColumnCollection.Add(firstDtc_l);
        int i = 0;

        foreach (string s in DynamicColumns)
        {
            DataGridTemplateColumn dtc_l = new DataGridTemplateColumn();
            Binding bindColor = new Binding();
            bindColor.Converter = new ChangedColorConverter();
            bindColor.ConverterParameter = "Column" + i;

            //DataTemplate
            DataTemplate dt_l = new DataTemplate("MyObject");
            spFactory_l = new FrameworkElementFactory(typeof(Grid));
            spFactory_l.Name = "CellTemplate";
            FrameworkElementFactory columnDefinition1 = new FrameworkElementFactory(typeof(ColumnDefinition));
            FrameworkElementFactory columnDefinition2 = new FrameworkElementFactory(typeof(ColumnDefinition));
            FrameworkElementFactory border1 = new FrameworkElementFactory(typeof(Border));
            border1.SetValue(Grid.ColumnProperty, 0);
            border1.SetValue(Border.BorderBrushProperty, Brushes.Gray);
            border1.SetValue(Border.BorderThicknessProperty, new Thickness(0,0,0,0));
            FrameworkElementFactory border2 = new FrameworkElementFactory(typeof(Border));
            border2.SetValue(Grid.ColumnProperty, 1);
            border2.SetValue(Border.BorderBrushProperty, Brushes.Gray);
            border2.SetValue(Border.BorderThicknessProperty, new Thickness(1, 0, 0, 0));
            FrameworkElementFactory textBlock1 = new FrameworkElementFactory(typeof(TextBlock));
            textBlock1.SetValue(Grid.ColumnProperty, 0);
            textBlock1.SetValue(TextBlock.ForegroundProperty, bindColor);
            Binding firstBind = new Binding("MyObject[Column"+i+"].FirstBinding");
            textBlock1.SetValue(TextBlock.TextProperty, localBind);
            FrameworkElementFactory textBlock2 = new FrameworkElementFactory(typeof(TextBlock));
            Binding secongBind = new Binding("MyObject[Column" + i + "].SecondBinding");
            textBlock2.SetValue(Grid.ColumnProperty, 0);
            textBlock2.SetValue(TextBlock.TextProperty, firstBind) 
            textBlock2.SetValue(TextBlock.ForegroundProperty, secongBind);
            border1.AppendChild(textBlock1);
            border2.AppendChild(textBlock2);

            spFactory_l.AppendChild(columnDefinition1);
            spFactory_l.AppendChild(columnDefinition2);
            spFactory_l.AppendChild(border1);
            spFactory_l.AppendChild(border2);
            dt_l.VisualTree = spFactory_l;

            dtc_l.Width = DataGridLength.Auto;
            dtc_l.CellTemplate = dt_l;
            dtc_l.Header = s;
            ColumnCollection.Add(dtc_l);
            i++;
        }   

The DataGrid is bound to a Collection of "TheObject".
TheObject class has a public Dictionary<string, MyCell> MyObject { get; set; }
MyCell class has FirstBinding and SecondBinding properties (string).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

姐不稀罕 2024-11-15 14:20:55

我在 DataGrid 上也遇到了类似的问题,在调整窗口大小、列排序等之后,实际上需要几秒钟的时间来刷新,并在执行此操作时锁定窗口 UI(1000 行,5 列)。

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

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

  • 将包含元素的大小更改为相对大小 (*) 或
    固定值
  • 将DataGrid的MaxHeight和MaxWidth设置为较大的固定值
    比正常使用时可以得到的
  • 尝试使用不同的调整大小策略的其他容器类型(Grid、DockPanel 等)

I had a similar problem with the DataGrid in which it took literally seconds to refresh after a window resize, column sort, etc. and locked up the window UI while it was doing so (1000 rows, 5 columns).

It came down to an issue (bug?) with the WPF sizing calculations. I had it in a grid with the RowDefinition Height="Auto" which was causing the rendering system to try and recalculate the size of the DataGrid at runtime by measuring the size of each and every column and row, presumably by filling the whole grid (as I understand it). It is supposed to handle this intelligently somehow but in this case it was not.

A quick check to see if this is a related problem is to set the Height and Width properties of the DataGrid to a fixed size for the duration of the test, and try running again. If your performance is restored, a permanent fix may be among these options:

  • Change the sizes of the containing elements to be relative (*) or
    fixed values
  • Set MaxHeight and MaxWidth of the DataGrid to a fixed value larger
    than it could get in normal use
  • Try another container type with different resizing strategy (Grid, DockPanel, etc)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文