何时在mvvm中使用Dispatcher?

时间:2011-11-28 13:13:39

标签: c# wpf mvvm

根据Jason Dolinger视频,我创建了装饰正常模型的DispatchingWcfModel。但我不明白为什么需要它。我应该总是使用某种Dispatching模型吗?如果我使用普通模型而不是调度模型怎么办?为什么我需要“Dispatcher”?

class DispatchingWcfModel : IWcfModel
{

    private readonly IWcfModel _underlying;
    private readonly Dispatcher _currentDispatcher;

    public DispatchingWcfModel(IWcfModel model)
    {
        _currentDispatcher = Dispatcher.CurrentDispatcher;
        _underlying = model;
        _underlying.DataArrived += _underlying_DataArrived;
    }

    private void _underlying_DataArrived(List<ConsoleData> obj)
    {
        Action dispatchAction = () =>
        {
            if (DataArrived != null)
            {
                DataArrived(obj);
            }
        };
        _currentDispatcher.BeginInvoke(DispatcherPriority.DataBind, dispatchAction);
    }

    public List<ConsoleData> DataList
    {
        get { throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }

    public event Action<List<ConsoleData>> DataArrived;
}

4 个答案:

答案 0 :(得分:1)

TL; DR: DispatchingWcfModel类包装注入IWcfModel并保证在新数据出现时 - 将以安全方式事件{{1}将更改分发到UI事件已在后台线程中引发,因此IWcfModel.DataArrived始终使用Dispatcher将回调推送到UI线程。

更详细:在您的示例DispatchingWcfModel类订阅注入DispatchingWcfModel的事件,因此当事件被引发时 - 事件处理程序IWcfModel将是调用和最重要的点 - 它会在实际引发事件的线程上被调用,因此调用线程可能不是UI线程,因此对UI控件的任何更改都将失败,避免使用Dispatched。

在WPF中,当您需要更新UI元素时,Dispatcher非常有用,因此应该在UI Thread中完成。正确的方法 - 将此工作委托给Dispatcher,Dispatcher持久化应该在UIThread上执行的工作项(请求)队列。

MSDN

  

在WPF中,DispatcherObject只能由Dispatcher访问它   与....关联。例如,后台线程无法更新   与Dispatcher关联的Button的内容   UI线程。为了让后台线程访问内容   Button的属性,后台线程必须委托工作   到与UI线程关联的Dispatcher。这是完成的   通过使用Invoke或BeginInvoke。调用是同步的   BeginInvoke是异步的。该操作被添加到队列中   指定DispatcherPriority的Dispatcher。

答案 1 :(得分:1)

Dispatcher是WPF的主UI线程的内部消息队列。它可以在后台线程中用于在应用程序的主UI线程上运行命令。

这很重要,因为WPF不允许您访问在其他线程上创建的对象。例如,如果在主UI线程上创建了Button,则无法从另一个线程修改此按钮,但您可以使用另一个线程的Dispatcher将命令发送到主UI线程以更新按钮。

这适用于所有对象,而不仅仅是UI元素。如果在一个线程上创建类似ObservableCollection的东西,则另一个线程无法修改它。因此,所有对象通常都在主UI线程上创建。

可以同步或异步处理调度程序消息。例如,

// Will execute SomeMethod on the main UI thread synchronously
Dispatcher.Invoke(SomeMethod);

// Will execute SomeMethod on the main UI thread asynchronously
Dispatcher.BeginInvoke(SomeMethod);

Dispatcher对于不同的消息优先级也有不同的队列,您可以指定一个DispatcherPriority和您的消息,以便在指定的时间运行某些内容。

// Will execute SomeMethod on the main UI thread synchronously, 
// at the same priority as Rendering controls
Dispatcher.Invoke(DispatcherPriority.Render, SomeMethod);

// Will execute SomeMethod on the main UI thread asynchronously, 
// at the same priority as background processes
Dispatcher.BeginInvoke(DispatcherPriority.Background, SomeMethod);

答案 2 :(得分:0)

调度程序用于访问图形用户元素。这些用户元素是在调度程序的行为中创建的。其他线程不允许访问它们。因此,当您想要访问gui元素时,您必须在调度程序上调用该操作。

但调度模型似乎是错误的方法。这些事情应该在视图模型中完成。这就是为什么有一个视图模型的原因。该模型通常是POCO或DTO,因此您不能依赖实现IWcfModel接口的每个模型。

我不知道您正在谈论的视频,但似乎作者对MVVM的理解有点偏僻。

答案 3 :(得分:0)

如果没有详细介绍(请点击此处的其他答案),请在

时使用Dispatcher
  1. 你想稍后做点什么
  2. 您希望在UI线程上执行某些操作
  3. 没有。 2是多线程时的明显选择。当从后台线程调用时,必须将UI的更新移动或“编组”到UI线程。如果你不知道这意味着什么,请在这里做一点阅读,因为这是多线程开发新用户必须学习的最大障碍之一,这里有成千上万的相关问题。

    没有。 1更加模糊,但可以归功于BeginInvoke的重载值DispatcherPriority

    有时您在UI线程中工作,并且知道您想要更新UI,但您需要以后。示例包括可能需要等到用户完成键入的更新,以免按下下一个键消除UI更改。