Я пытаюсь улучшить производительность 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