Задержка обновления свойств до тех пор, пока не будет изменена группа свойств (т. е. блокировка элемента управления)

#c# #wpf #dependency-properties

#c# #wpf #зависимость-свойства

Вопрос:

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

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

Цель: элемент управления необходимо обновлять только тогда, когда программа завершит изменение всех свойств.

Что я пробовал:

  • Сделайте свойство ленивым, обновляя его только по запросу. (Не работает, WPF все равно запрашивает его);
  • Кэшируйте результат вычисления. (Не работает, потому что всегда изменяется 1 ввод, что делает кеш недействительным);
  • Создайте метод для одновременной установки нескольких свойств. (Не работает, некоторые свойства наследуются и поступают из другого элемента управления);
  • Сделайте элемент управления свернутым, прежде чем манипулировать свойствами. (Не работает, WPF по-прежнему обновляет свойства).

У кого-нибудь есть лучшее решение?

Ответ №1:

Вы можете отложить создание события изменения свойства. Или создайте метод, который остановит распространение этого события (т. Е. StartUpdating ) и другой метод, который будет запускать все события (т. Е. EndUpdating ).

 private bool _isUpdating;
private List<string> _properties = ...;

private void RaisePropertyChanged(string propertyName)
{
   if(_isUpdating) 
   {
     if(!_properties.Contains(propertyName)) _properties.Add(propertyName);
     return;
   } 

   PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

void StartUpdating() { _isUpdating = true; }

void EndUpdating()
{
  _isUpdating = false;
  foreach(var propertyName in _properties) RaisePropertyChanged(propertyName);
}
  

и в ваших методах

 void LongRunningMethodSync()
{
  try
  {
    StartUpdating(); 
    // do something synchronously
  }
  finally
  {
    EndUpdating();
  }
}

void LongRunningMethodAsync()
{
  StartUpdating(); 
  ExecuteMyAsyncTask(done => EndUpdating());
}
  

Комментарии:

1. Это работает довольно хорошо, но не совсем то, что я искал (я хотел, чтобы поведение было прозрачным для конечного пользователя). В итоге я получил вспомогательный класс, который использует диспетчер с низким приоритетом для планирования уведомлений об обновлении.

Ответ №2:

Взгляните на свойство IsAsync привязки. Я полагаю, что это может работать в сочетании с шаблоном, подобным debounce.