Массовые обновления сложного интерфейса
У меня очень сложный пользовательский интерфейс с постоянно меняющейся строкой состояния с несколькими типами сообщений о состоянии и пользовательским интерфейсом со сложным элементом управления диаграммой и загруженной ориентировочной географической картой.
Теперь контекст данных этих небольших, но сложных областей имеет одинаково сложные модели представления, такие как StatusBarVM, ChartingVM, GeoMapVM и т. Д. Они реализуют INotifyPropertyChanged и ObservableCollections.
Подсчитывая мои обновления, я вижу, что у меня есть около 5000 элементов пользовательского интерфейса (метки, индикаторы выполнения, точки данных диаграммы, bgcolorsbrushes и т. Д.), Которые меняются со скоростью 1000 обновлений элементов данных в секунду.
Каков наилучший способ добиться массового обновления данных в пользовательском интерфейсе WPF?
Способна ли модель связывания WPF для такого рода огромных обновлений? Если так, как? Потому что я вижу, что это не оптимально в моем случае. Я также использую bgworker (для индикаторов прогресса) и использую DIspatcher BeginInvoke... но дело в том, что даже тогда обновления действительно висят в потоке пользовательского интерфейса, поскольку сообщения диспетчера попадают в очередь в ожидании завершения.
Я не могу реализовать виртуализацию, так как статусы выполняются в реальном времени, и я должен видеть их все в пользовательском интерфейсе передо мной... Я не могу позволить себе пропустить их даже на пару секунд (например, по-разному меняющиеся географические данные спутника).
Пожалуйста, помогите мне найти правильный инструмент или какой-либо способ создания сложного, но очень отзывчивого пользовательского интерфейса WPF. Это Dispatcher.PushFrame()?
1 ответ
При таком количестве обновлений в секунду вы будете получать сообщения об обновлениях "в резервной копии" в очереди, поэтому ваши фоновые рабочие обновления блокируются.
Чтобы решить эту проблему, вам нужно регулировать количество создаваемых событий обновления.
Я бы использовал такой подход:
В моих ViewModels замените обычную реализацию INotifyPropertyChanged вызовом одноэлементного объекта, который будет отправлять уведомление от имени этого объекта.
private void OnPropertyChanged(string propertyName)
{
PropertyChangedNotifier.Notify(this, propertyName, propertyChanged);
}
куда propertyChanged
переменная-член, хранящая обработчики событий этих объектов
Notify
Метод будет выглядеть примерно так:
public static void Notify(
object sender,
string propertyName,
PropertyChangedEventHandler handlers)
{ ... }
В уведомителе не отправляйте событие немедленно - просто сохраните тот факт, что оно должно быть отправлено.
Если вы получаете уведомление несколько раз для одного и того же объекта / свойства, откажитесь от дополнительных уведомлений. Если вы получаете уведомление много раз для одного и того же объекта, но с разными свойствами, замените уведомление одним для всех свойств.
Теперь используйте таймер потока UX, чтобы "выпускать" уведомления каждые 50 мс или около того - все еще достаточно быстро, чтобы пользователь не заметил никакой разницы, и он выглядит как обновления в реальном времени, но достаточно медленно, чтобы обнаруживать (и удалять) дубликаты уведомлений.