Как передать Диспетчер пользовательского интерфейса в ViewModel - PullRequest
68 голосов
/ 01 марта 2010

У меня должна быть возможность доступа к Диспетчеру , который принадлежит к представлению, мне нужно передать его в ViewModel. Но View не должен ничего знать о ViewModel, так как вы его передаете? Представить интерфейс или вместо передачи его экземплярам создать глобальный диспетчер-синглтон, который будет записан в представлении? Как вы решаете это в ваших MVVM-приложениях и фреймворках?

РЕДАКТИРОВАТЬ: обратите внимание, что поскольку мои ViewModels могут быть созданы в фоновых потоках, я не могу просто сделать Dispatcher.Current в конструкторе ViewModel.

Ответы [ 15 ]

1 голос
/ 04 октября 2010

Если вам нужен только диспетчер для изменения связанной коллекции в другом потоке, взгляните на SynchronizationContextCollection здесь http://kentb.blogspot.com/2008/01/cross-thread-collection-binding-in-wpf.html

Работает хорошо, единственная проблема, которую я обнаружил, - это использование моделей представления со свойствами SynchronizationContextCollection с контекстом синхронизации ASP.NET, но их легко обойти.

НТН Sam

0 голосов
/ 05 октября 2017

Может быть, я немного опоздал к этой дискуссии, но нашел 1 хорошую статью https://msdn.microsoft.com/en-us/magazine/dn605875.aspx

Есть 1 параграф

Кроме того, весь код вне слоя View (то есть ViewModel и слои модели, сервисы и т. д.) не должны зависеть от какого-либо типа привязан к конкретной платформе пользовательского интерфейса. Любое прямое использование Dispatcher (WPF / Xamarin / Windows Phone / Silverlight), CoreDispatcher (Windows Store) или ISynchronizeInvoke (Windows Forms) - плохая идея. (SynchronizationContext немного лучше, но едва.) Например, есть много кода в Интернете, который делает некоторые асинхронная работа, а затем использует Dispatcher для обновления пользовательского интерфейса; больше портативным и менее громоздким решением является использование await для асинхронного работать и обновлять интерфейс без использования Dispatcher.

Предположим, что вы можете правильно использовать async / await, это не проблема.

0 голосов
/ 14 сентября 2011

Я нашел другой (самый простой) способ:

Добавить для просмотра действия модели, которое должно вызываться в Dispatcher:

public class MyViewModel
{
    public Action<Action> CallWithDispatcher;

    public void SomeMultithreadMethod()
    {
        if(CallWithDispatcher != null)
            CallWithDispatcher(() => DoSomethingMetod(SomeParameters));
    }
}

И добавьте этот обработчик действия в конструктор представления:

    public View()
    {
        var model = new MyViewModel();

        DataContext = model;
        InitializeComponent();

        // Here 
        model.CallWithDispatcher += act => _taskbarIcon.Dispatcher
            .BeginInvoke(DispatcherPriority.Normal, act) ;
    }

Теперь у вас нет проблем с тестированием, и его легко реализовать. Я добавил его на мой сайт

0 голосов
/ 23 октября 2010

если вы используете uNhAddIns , вы можете легко сделать асинхронное поведение. посмотрите здесь

И мне нужно несколько модификаций, чтобы он работал на Castle Windsor (без uNhAddIns)

0 голосов
/ 01 марта 2010

С некоторыми из моих проектов WPF я столкнулся с такой же ситуацией. В моем MainViewModel (экземпляр Singleton) я получил статический метод CreateInstance (), принимающий диспетчер. И экземпляр create вызывается из View, чтобы я мог передать Dispatcher оттуда. И тестовый модуль ViewModel вызывает CreateInstance () без параметров.

Но в сложном многопоточном сценарии всегда полезно иметь реализацию интерфейса на стороне просмотра, чтобы получить соответствующий диспетчер текущего окна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...