开发者

Datagrid very low performance, even with UI Virtualization

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(firs开发者_JAVA百科tDtc_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).


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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜