在没有虚拟化的WPF DataGrid上排序时性能不佳

时间:2011-09-13 09:43:44

标签: wpf performance sorting datagrid

我们有一个简单的WPF演示应用程序,包含1000行和32列(请参阅下面的代码)。

除了禁用虚拟化之外,我们没有做任何特别的事情,我们的用户需要这样做,否则滚动太慢(他们整天都在大型数据集上执行此操作,因此响应/快捷对他们来说非常重要)。 / p>

我们遇到的问题是,如果您单击其中一个标题对数据进行排序,则需要约20秒(在此处使用2x3GHz Core 2 Duo计算机)。有什么方法可以加快速度吗?

在排序时似乎正在重建整个可视树,而且似乎没必要。任何有关如何加速这种特定情况的指示都将受到赞赏,即使它已经编译我们自己的网格版本。

感谢。

<Window x:Class="WpfGridTest1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid Name="dataGrid" VirtualizingStackPanel.IsVirtualizing="False">

        </DataGrid>
    </Grid>
</Window>

using System.Collections.Generic;

namespace WpfGridTest1
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();

            List<Row> rows = new List<Row>();

            for (int i = 0; i < 1000; i++)
            {
                Row row = new Row
                              {
                                  Column0 = i,
                                  Column1 = i,
                                  Column2 = i,
                                  Column3 = i,
                                  Column4 = i,
                                  Column5 = i,
                                  Column6 = i,
                                  Column7 = i,

                                  Column8 = i,
                                  Column9 = i,
                                  Column10 = i,
                                  Column11 = i,
                                  Column12 = i,
                                  Column13 = i,
                                  Column14 = i,
                                  Column15 = i,

                                  Column16 = i,
                                  Column17 = i,
                                  Column18 = i,
                                  Column19 = i,
                                  Column20 = i,
                                  Column21 = i,
                                  Column22 = i,
                                  Column23 = i,

                                  Column24 = i,
                                  Column25 = i,
                                  Column26 = i,
                                  Column27 = i,
                                  Column28 = i,
                                  Column29 = i,
                                  Column30 = i,
                                  Column31 = i
                              };
                rows.Add(row);
            }

            dataGrid.ItemsSource = rows;
        }
    }
}



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace WpfGridTest1
{
    class Row : INotifyPropertyChanged
    {
        private double column0 ;
        private double column1 ;
        private double column2 ;
        private double column3 ;
        private double column4 ;
        private double column5 ;
        private double column6 ;
        private double column7 ;

        private double column8 ;
        private double column9 ;
        private double column10;
        private double column11;
        private double column12;
        private double column13;
        private double column14;
        private double column15;

        private double column16;
        private double column17;
        private double column18;
        private double column19;
        private double column20;
        private double column21;
        private double column22;
        private double column23;

        private double column24;
        private double column25;
        private double column26;
        private double column27;
        private double column28;
        private double column29;
        private double column30;
        private double column31;

        public double Column0  { get { return column0 ; } set { column0  = value; NotifyPropertyChanged("Column0 "); } }
        public double Column1  { get { return column1 ; } set { column1  = value; NotifyPropertyChanged("Column1 "); } }
        public double Column2  { get { return column2 ; } set { column2  = value; NotifyPropertyChanged("Column2 "); } }
        public double Column3  { get { return column3 ; } set { column3  = value; NotifyPropertyChanged("Column3 "); } }
        public double Column4  { get { return column4 ; } set { column4  = value; NotifyPropertyChanged("Column4 "); } }
        public double Column5  { get { return column5 ; } set { column5  = value; NotifyPropertyChanged("Column5 "); } }
        public double Column6  { get { return column6 ; } set { column6  = value; NotifyPropertyChanged("Column6 "); } }
        public double Column7  { get { return column7 ; } set { column7  = value; NotifyPropertyChanged("Column7 "); } }

        public double Column8  { get { return column8 ; } set { column8  = value; NotifyPropertyChanged("Column8 "); } }
        public double Column9  { get { return column9 ; } set { column9  = value; NotifyPropertyChanged("Column9 "); } }
        public double Column10 { get { return column10; } set { column10 = value; NotifyPropertyChanged("Column10"); } }
        public double Column11 { get { return column11; } set { column11 = value; NotifyPropertyChanged("Column11"); } }
        public double Column12 { get { return column12; } set { column12 = value; NotifyPropertyChanged("Column12"); } }
        public double Column13 { get { return column13; } set { column13 = value; NotifyPropertyChanged("Column13"); } }
        public double Column14 { get { return column14; } set { column14 = value; NotifyPropertyChanged("Column14"); } }
        public double Column15 { get { return column15; } set { column15 = value; NotifyPropertyChanged("Column15"); } }

        public double Column16 { get { return column16; } set { column16 = value; NotifyPropertyChanged("Column16"); } }
        public double Column17 { get { return column17; } set { column17 = value; NotifyPropertyChanged("Column17"); } }
        public double Column18 { get { return column18; } set { column18 = value; NotifyPropertyChanged("Column18"); } }
        public double Column19 { get { return column19; } set { column19 = value; NotifyPropertyChanged("Column19"); } }
        public double Column20 { get { return column20; } set { column20 = value; NotifyPropertyChanged("Column20"); } }
        public double Column21 { get { return column21; } set { column21 = value; NotifyPropertyChanged("Column21"); } }
        public double Column22 { get { return column22; } set { column22 = value; NotifyPropertyChanged("Column22"); } }
        public double Column23 { get { return column23; } set { column23 = value; NotifyPropertyChanged("Column23"); } }

        public double Column24 { get { return column24; } set { column24 = value; NotifyPropertyChanged("Column24"); } }
        public double Column25 { get { return column25; } set { column25 = value; NotifyPropertyChanged("Column25"); } }
        public double Column26 { get { return column26; } set { column26 = value; NotifyPropertyChanged("Column26"); } }
        public double Column27 { get { return column27; } set { column27 = value; NotifyPropertyChanged("Column27"); } }
        public double Column28 { get { return column28; } set { column28 = value; NotifyPropertyChanged("Column28"); } }
        public double Column29 { get { return column29; } set { column29 = value; NotifyPropertyChanged("Column29"); } }
        public double Column30 { get { return column30; } set { column30 = value; NotifyPropertyChanged("Column30"); } }
        public double Column31 { get { return column31; } set { column31 = value; NotifyPropertyChanged("Column31"); } }


        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }
}

更新:我尝试过AngelWPF的建议如下:

private void dataGrid_Sorting(object sender, System.Windows.Controls.DataGridSortingEventArgs e)
        {
            e.Handled = true;

            IQueryable<Row> iqueryable = _rows.AsQueryable();

            var v = iqueryable.OrderBy(row => row.Column0);

            foreach (Row row in v)
                System.Diagnostics.Debug.WriteLine("Row " + row.Column0);

            _rows = new ObservableCollection<Row>(v.ToList());

            dataGrid.ItemsSource = _rows;
         }

虽然性能问题仍然存在,但正在重建网格。

3 个答案:

答案 0 :(得分:4)

如果没有虚拟化,就没有机会对性能进行分类改进!

为什么要放弃虚拟化?数据网格滚动缓慢的问题可以解决......就像这些帖子可能会有所帮助...... WPF Datagrid PerformanceSlow and Stuttery WPF Grid Scrolling when loaded with large amounts of data (40 columns, 2000 rows)http://www.codeproject.com/KB/WPF/WpfDataVirtualization.aspx

说过有一种方法可以改善非虚拟化数据网格的排序。

  1. 处理DataGrid.Sorting事件并在其处理程序中设置e.Handled = true。这样数据网格就不会执行排序。
  2. 在上面的处理程序中,通过查看列名称,您将知道该列表示或绑定的属性。因此,使用该属性名称并使用LINQ的AsQueryable()接口进行排序。这将是对数据网格ItemsSource进行排序的最快方法。
  3. 将已排序的集合设置回ItemsSource
  4. 我们尝试了上述方法,用于一个只读的非虚拟化数据网格,它显示了各种颜色,效果和300列30列,结果令人震惊。

    可查询的LINQ可以创造奇迹!

答案 1 :(得分:1)

我在使用DataGrid时出现问题,在列排序,调整大小等等之后花了几秒钟刷新它并锁定了窗口UI(1000行,5列)。

归结为WPF大小计算的问题。我在RowDefinition Height =“Auto”的网格中得到它,这导致渲染系统尝试通过测量每个列和行的大小来尝试重新计算DataGrid的大小,可能是通过填充整个网格(据我所知)。它应该以某种方式智能地处理它,但在这种情况下它不是。

快速检查以确定这是否是一个相关问题是在测试期间将DataGrid的高度和宽度属性设置为固定大小,然后再次尝试运行。如果您的性能已恢复,则可以在以下选项中进行永久性修复:

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

答案 2 :(得分:0)

从更新的部分:

foreach (Row row in v)
       System.Diagnostics.Debug.WriteLine("Row " + row.Column0);

_rows = new ObservableCollection<Row>(v.ToList());

为什么不禁用WriteLine?从性能的角度来看,这不是一件好事。另外,您是否有理由将_rows变量重新初始化为新的ObservableCollection?如果可能,将_rows转换为属性,然后在更改值时引发NotifyPropertyChanged事件。

当然,您还必须将网格的数据绑定更改为此新属性。