Низкая производительность при сортировке в WPF DataGrid без виртуализации - PullRequest
4 голосов
/ 13 сентября 2011

У нас есть простое демонстрационное приложение WPF с 1000 строками и 32 столбцами (см. Код ниже).

Мы не сделали с ним ничего особенного, кроме отключения виртуализации, которое требуется нашим пользователям, иначе прокруткаслишком вялый (они делают это целый день на больших наборах данных, поэтому для них важны отзывчивость / быстрота).

Проблема, с которой мы столкнулись, - если вы нажмете один из заголовков, чтобы отсортировать данные, этозаймет ~ 20 секунд (на процессоре Core 2 Duo 2x3 ГГц).Есть ли способ ускорить это?

Кажется, что при сортировке восстанавливается все визуальное дерево, и это кажется ненужным.Любые указатели на то, как ускорить эту конкретную ситуацию, будут оценены, даже если это дойдет до компиляции нашей собственной версии сетки.

Спасибо.

<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 ]

4 голосов
/ 13 сентября 2011

Без виртуализации невозможно повысить производительность сортировки!

Зачем терять виртуализацию?Проблема медленной прокрутки сетки данных может быть решена ... как эти посты могут помочь ... Производительность WPF Datagrid , Медленная и заикляющаяся прокрутка сетки WPF при загрузке больших объемов данных (40 столбцов,2000 строк) , http://www.codeproject.com/KB/WPF/WpfDataVirtualization.aspx.

Сказав, что существует один способ улучшить сортировку в не виртуализированной сетке данных.

  1. Обработайте событие DataGrid.Sorting и установите e.Handled = true в его обработчик.Таким образом, таблица данных не будет выполнять сортировку.
  2. В приведенном выше обработчике, посмотрев на имя столбца, вы узнаете свойство, которое столбец представляет или с которым связан.Поэтому используйте это имя свойства и используйте интерфейс LINQ AsQueryable () для сортировки.Это будет самый быстрый способ сортировки ItemsSource таблицы данных.
  3. Установите отсортированную коллекцию обратно на ItemsSource.

Мы попробовали описанный выше подход для не только для чтения.- виртуализированная сетка данных, которая отображала множество цветов, эффектов и 30000 строк по 30 столбцов, и результат был поразительным.

Запрашиваемый LINQ может творить чудеса!

1 голос
/ 28 декабря 2011

У меня была проблема с сеткой данных, в которой буквально за секунды потребовалось обновление после сортировки столбца, изменения размера и т. Д. И блокировки пользовательского интерфейса окна (1000 строк, 5 столбцов).

Это привело к проблеме с расчетами размеров WPF. У меня это было в сетке с RowDefinition Height = "Auto", которая заставляла систему рендеринга пытаться пересчитать размер DataGrid во время выполнения, измеряя размер каждого столбца и строки, предположительно, заполняя всю сетку ( как я понимаю). Предполагается, что это нужно как-то разумно, но в данном случае это не так.

Быстрая проверка, чтобы увидеть, является ли это связанной проблемой, состоит в том, чтобы установить свойства Высота и Ширина DataGrid на фиксированный размер на время теста, и попробуйте запустить снова. Если ваша производительность восстановлена, постоянное исправление может быть среди этих вариантов:

  • Изменить размеры содержащихся элементов на относительные (*) или фиксированные значения
  • Установите для MaxHeight и MaxWidth DataGrid фиксированное значение, большее чем он мог бы получить при обычном использовании
  • Попробуйте другой тип контейнера с другой стратегией изменения размера (Сетка, DockPanel и др.)
0 голосов
/ 28 сентября 2011

Из обновленного раздела:

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

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

Почему бы вам не отключить WriteLine? Это не может быть хорошо с точки зрения производительности. Кроме того, есть ли причина, по которой вы повторно инициализируете переменную _rows для новой ObservableCollection? Если возможно, преобразуйте _rows в свойство, а затем вызовите событие NotifyPropertyChanged при изменении значения.

Конечно, вам также придется изменить привязку данных для сетки к этому новому свойству.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...