在我的ViewModel中使用Dispatcher是错误的吗?

时间:2011-09-19 16:09:46

标签: c# wpf mvvm observablecollection

我正在为我在c#winforms中编写的游戏转换为wpf的聊天解析器,主要是为了更好地处理MVVM和wpf。这是我如何设置项目的故障

查看: 现在它只是一个简单的ListBox,ItemSource绑定到我的viewmodels可观察聊天集合

模型: 我有多个可以一次登录的角色,每个角色都有一个聊天课。聊天课开始一个后台工作人员从游戏中抓取和下一行聊天,然后用这一行发起一个名为IncomingChat的事件。

public event Action<Game.ChatLine> IncomingChat;

我正在使用后台工作人员在我的backgroundworkers progresschaged事件中触发事件,因为当我使用计时器时,我一直遇到线程问题。起初我通过将我的Timer更改为DispatchTimer来纠正这个问题,但是在我的模型中有一个DispatchTimer这似乎不合适。

视图模型: 由于我有多个字符,我正在创建多个ChatViewModel。我将一个字符传递给ChatViewModels构造函数并订阅Chat事件。我创建了一个ObservableColleciton来在收到此事件时保留我的聊天行。现在,当我尝试将我从聊天事件中收到的行添加到我的observablecollection时,我在viewModel上收到了一个线程问题。

我通过使我的viewmodels传入聊天事件处理程序看起来像这样来解决这个问题

public ObservableCollection<Game.ChatLine) Chat {get; private set;}

void Chat_Incoming(Game.ChatLine line)
{
  App.Current.Dispatcher.Invoke(new Action(delegate
  {
    Chat.Add(line)
  }), null);
}

但这对我来说并不合适。虽然它有效,但在我的viewmodel中使用Dispatcher对我来说似乎不合适。

3 个答案:

答案 0 :(得分:38)

  

虽然它有效,但在我的viewmodel中使用Dispatcher对我来说似乎不合适。

这不是一种完全不合理的方法,也是许多人采取的方法。就个人而言,如果你正在使用WPF(或Silverlight 5)并且可以访问TPL,我更愿意使用TPL来处理这个问题。

假设您的ViewModel是在UI线程上构建的(即:通过View,或者响应View相关事件),这种情况几乎总是IMO,您可以将它添加到构造函数中:

// Add to class:
TaskFactory uiFactory;

public MyViewModel()
{
    // Construct a TaskFactory that uses the UI thread's context
    uiFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
}

然后,当你收到你的活动时,可以用它来整理它:

void Chat_Incoming(Game.ChatLine line)
{
    uiFactory.StartNew( () => Chat.Add(line) );
}

请注意,这略微与原始版本不同,因为它不再阻止(这更像是使用BeginInvoke而不是Invoke)。如果您需要阻止此操作直到UI完成处理消息,您可以使用:

void Chat_Incoming(Game.ChatLine line)
{
    uiFactory.StartNew( () => Chat.Add(line) ).Wait();
}

答案 1 :(得分:0)

View Model是进行线程同步的好地方。从模型中删除DispatcherTimer并让VM处理它。

答案 2 :(得分:0)

我喜欢里德的回答,同意你对使用Dispatcher时出现问题的担忧。您的VM引用App,在我看来,它是对UI工件(或控件)的引用。请改用Application,或者更好地将正确的Dispatcher实例注入您的VM,这样就无需在UI线程中实例化您的VM。