wpf - 在没有虚拟化的情况下在 WPF DataGrid 上排序时性能不佳

标签 wpf performance sorting datagrid

我们有一个简单的 WPF 演示应用程序,它有 1000 行和 32 列(代码见下文)。

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

我们遇到的问题是,如果您单击其中一个标题对数据进行排序,这将需要大约 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;
         }

尽管性能问题仍然存在,因为它正在重建网格。

最佳答案

没有虚拟化,排序性能就没有机会提升!

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

话虽如此,有一种方法可以改进非虚拟化数据网格的排序。

  • 处理DataGrid.Sorting事件和设置e.Handled = true在它的处理程序中。这样datagrid不会执行排序。
  • 在上面的处理程序中,通过查看列名,您将知道该列所代表或绑定(bind)到的属性。因此,使用该属性名称并使用 LINQ 的 AsQueryable() 接口(interface)进行排序。这将是排序 ItemsSource 的最快方法的数据网格。
  • 将排序后的集合设置回 ItemsSource .

  • 我们为一个只读的非虚拟化数据网格尝试了上述方法,它显示了各种颜色、效果和 30000 行 30 列,结果令人震惊。

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

    关于wpf - 在没有虚拟化的情况下在 WPF DataGrid 上排序时性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7399785/

    相关文章:

    c# - 在 WPF 中检测鼠标直接越过边框

    在达到特定值时重置 cumsum

    c++ - 在使用 NaCl 的 C++ 中,如何按值对 JSON 对象进行排序?

    java - “比较方法违反了其一般契约”,没有传递错误的迹象

    java - JavaFX ListView 中的 WPF ListView.ItemTemplate 等效项是什么?

    wpf - 所有 WPF 控件都可聚焦吗?

    java - java 1.4 支持 -javaagent 吗?

    java - 尝试按姓氏对对象的 ArrayList 进行排序,如果姓氏相同则按名字排序

    c# - 如何使用 .NET、C# 和 WPF 检查 Internet 连接

    c++ - 无锁多线程比单线程程序慢吗?