Почему я должен избегать использования Dispatcher? - PullRequest
7 голосов
/ 07 марта 2011

Я прочитал много постов, статей и т. Д. О привязке и схожести веток элементов управления GUI. Есть пост, в котором люди не хотят использовать Dispatcher.

У меня также есть напарник, который избегает использования Dispatcher в своем коде. Я спросил его о причине, но его ответ не удовлетворил меня. Он сказал, что ему не нравится такая «магия», спрятанная в классе.

Ну, я фанат следующего класса.


public class BindingBase : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

   private Dispatcher Dispatcher
   {
#if SILVERLIGHT
      get { return Deployment.Current.Dispatcher; }
#else
      get { return Application.Current.Dispatcher; }
#endif
   }

   protected void RaisePropertyChanged<T>(Expression<Func<T>> expr)
   {
      var memberExpr = (MemberExpression)expr.Body;
      string property = memberExpr.Member.Name;

      var propertyChanged = PropertyChanged;
      if (propertyChanged == null) return;

      if (Dispatcher.CheckAccess())
         propertyChanged.Invoke(this, new PropertyChangedEventArgs(property));
      else
         Dispatcher.BeginInvoke(() => RaisePropertyChanged(expr));
   }
}

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

Вы должны признать, есть одна странная вещь. Dispatcher.CheckAccess() исключен из Intellisense. Возможно, они немного страшны из-за этого факта.

Привет

EDIT:

Хорошо, еще один пример. Рассмотрим сложный объект. Коллекция в качестве примера, возможно, была не лучшей идеей.


public class ExampleVm : BindingBase
{
   private BigFatObject _someData;
   public BigFatObject SomeData
   {
      get { return _someData; }
      set
      {
         _someData = value;
         RaisePropertyChanged(() => SomeData);
      }
   }

   public ExampleVm()
   {
      new Action(LoadSomeData).BeginInvoke(null, null); //I know - it's quick and dirty
   }

   private void LoadSomeData()
   {
      // loading some data from somewhere ...
      // result is of type BigFatObject

      SomeData = result; // This would not work without the Dispatcher, would it?
   }
}

1 Ответ

5 голосов
/ 07 марта 2011

Я также лично не против Dispatcher в модельных классах.Я не видел каких-либо серьезных проблем с ним, но он дает большую гибкость вашему коду.

Но мне нравится идея инкапсулировать использование Dispatcher в коде инфраструктуры в максимально возможной степени.Как и в случае с методом RaisePropertyChanged (кстати, в случае RaisePropertyChanged вам не нужно ничего отправлять - привязка уже делает это за вас; вам нужно только отправить изменения в коллекции).

Самый большой и единственный недостаток, который я вижу здесь, это юнит-тестирование.Когда вы пытаетесь проверить свою логику, которая использует Dispatcher, все может быть сложно.Представьте, что у вас есть что-то подобное в модели представления:

private void UpdateMyCollection() 
{
   IList<ModelData> dataItems = DataService.GetItems();

   // Update data on UI
   Dispatcher.BeginInvoke(new Action(() => {
      foreach (ModelData dataItem in dataItems)
      {
         MyObservableCollection.Add(new DataItemViewModel(dataItem));
      }
   }));
}

Этот тип кода довольно типичен для обновления коллекций из потока, не являющегося пользовательским интерфейсом.Теперь, как бы вы написали модульный тест, который проверяет логику добавления элементов в наблюдаемую коллекцию?Прежде всего, вам нужно будет смоделировать свойство Dispatcher, поскольку Application.Current равно null во время выполнения модульного теста.Во-вторых, как ты будешь издеваться?Будете ли вы создавать специальный поток, который будет имитировать поток пользовательского интерфейса и использовать Dispatcher этого потока?Итак, такого рода вещи.

Суть в том, что если вы хотите, чтобы ваш код был дружественным к юнит-тестам, вам нужно подумать о том, как вы будете издеваться над Dispatcher.Это единственная проблема.

Обновление:

Второй предоставленный вами пример БУДЕТ работать без Dispatcher (связывание поможет).

...