Должны ли у меня возникать проблемы с большим списком объектов, реализующих INotifyPropertyChanged? - PullRequest
2 голосов
/ 22 июля 2010

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

Эта коллекция, которая реализует IBindingListView, привязана к данным к DataGridView с использованием стандартной поддержки конструктора Visual Studio, что приводит к BindingSource в обычной роли прокси между элементами управления и их источником данных. Несколько других элементов управления также подключены к классу коллекции, используя некоторые обобщенные свойства (например, TotalCountWithPropertyXXX)

Ранее код в форме фактически использовал таймер для вызова BindingSource.ResetBindings (false); для того, чтобы обновить связанные элементы управления. Я подумал, что это не совсем идеально, поэтому я реализовал базовую поддержку INotifyPropertyChanged для самих объектов данных, чтобы изменения на уровне объектов доходили до BindingSource и, в конечном счете, DataGridView автоматически обновлялся для отображения новых значений отредактированных свойств. (и, очевидно, разорвал вызовы BindingSource.ResetBindings).

Моя реализация INotifyPropertyChanged была довольно простой: просто запустил событие из установщика метода доступа к свойству со строковым значением, содержащим имя соответствующего свойства, например ::

public event PropertyChangedEventHandler PropertyChanged;

public string Name
{
    get { return _name; }
    set
    {
        if (value != _name)
        {
            _name = value;
            NotifyPropertyChanged("Name");
        }
    }
}

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

Для меня это работало нормально, хотя в нашем списке было от нескольких сотен до нескольких тысяч объектов данных, я заметил небольшую медлительность в обновлении сетки. Смертельный удар (с точки зрения производительности) произошел при тестировании некоторой существующей функциональности для массового обновления объектов данных - т. Е. В форме есть кнопка для переключения одного из логических свойств для всех объектов данных в список. Когда срабатывает обработчик событий этой кнопки, он перечисляет весь список объектов данных и устанавливает флаг в значение true / false, а пользовательский интерфейс просто зависает на 8-10 секунд, прежде чем возвращается к жизни и помечает все объекты обновленным логическим значением (используя DataGridViewCheckBoxColumn).

Моей первой мыслью было отключить запуск события ListChanged BindingSource (RaiseListChangedEvents = false;), когда дескриптор события кнопки обновлял все объекты данных, но это не сделало заметной разницы.

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

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

Я провел некоторый поиск, и я не нашел много упоминаний о том, что INotifyPropertyChanged является значительным перфоментом для числа объектов, с которыми я имею дело, поэтому я не уверен, есть ли в нашем коде ошибки, которые должны быть исправлено - например, моя неэффективная реализация INotifyPropertyChanged, возможно, плохая реализация IBindingListView в нашем классе коллекции, или что-то глупое в нашей привязке данных - или если я достигаю предела того, что я могу сделать в DataGridView без реализации виртуального режима .

На данный момент я отцепил код INotifyPropertyChanged, который я написал, и пытался сделать недействительной сетку всякий раз, когда я думаю, что у нас есть изменения в объектах данных с помощью обработчиков событий в CellChanged, нажатия кнопки и т. Д., Но я могу 'мне не хочется ощущать, что я не совсем понимаю проблему с корневым перфом, и что я могу выбрать менее чистую стратегию реализации только потому, что не понимаю, в чем заключается моя проблема перфектов.

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

TIA, Matt

1 Ответ

1 голос
/ 23 июля 2010

В нашем текущем приложении есть несколько больших видов сетки, и когда они вялы, я просто делаю несколько стеков, чтобы посмотреть, что происходит.

Обычно все, что требуется, - это безумные уведомления. Там, где это возможно, лучше не пытаться держать данные в строгом соответствии с уведомлениями, а, скорее, допускать некоторую временную несогласованность и время от времени очищать их в какой-то однократный проход.

...