2011-03-07 3 views
7

Я прочитал много сообщений о нитях, статьях и т. Д. О привязке и сходстве потоков с элементами управления графическим интерфейсом. Есть сообщение, в котором люди не хотят использовать 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. Из-за этого они немного страшны.

Привет

РЕДАКТИРОВАТЬ:

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


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? 
    } 
} 

ответ

5

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

Но мне нравится идея максимально возможного использования кода Dispatcher в коде инфраструктуры. Так же, как вы это делали с RaisePropertyChanged (BTW, в случае 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. Это единственная проблема.

Update:

Второй пример вы предоставили будет работать без Dispatcher (связывание будет делать трюк).

+0

«(BTW, в случае RaisePropertyChanged вам не нужно ничего отправлять - привязка уже делает это для вас, вам нужно только отправлять изменения в коллекции)« Ну, если это правда, то что-то было изменено с .Net 3.5. Рассмотрим коллекцию, которая загружается в отдельный поток, а затем передается этим потоком в свойство в ViewModel. Я не думаю, что это возможно без Dispatcher или BackGroundWorker. – DHN

+0

Я не понимаю, почему во время модульного теста есть недостатки. Не могли бы вы объяснить это больше, пожалуйста? – DHN

+0

@DHN - Смотрите мое обновление для примера проблемы с модульными тестами. Что касается «Рассмотрим коллекцию, которая загружается в отдельный поток, а затем передается этим потоком в свойство в ViewModel», я прямо упоминал, что «вам нужно только отправлять изменения в коллекции», поэтому да, вам нужно использовать ' Dispatcher' для изменения коллекций, но не для обычных свойств (т. Е. Вам не нужно поднимать событие INotifyPropertyChanged.PropertyChanged в потоке пользовательского интерфейса, но вы должны поднять 'INotifyCollectionChanged.CollectionChanged' в потоке пользовательского интерфейса). –

Смежные вопросы