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

poc*_*oco 19 c# wpf observablecollection mvvm

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

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

型号:我有多个可以同时登录的角色,每个角色都有一个聊天类.聊天课开始一个后台工作人员从游戏中抓取和下一行聊天,并使用此行触发一个名为IncomingChat的事件.

public event Action<Game.ChatLine> IncomingChat;
Run Code Online (Sandbox Code Playgroud)

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

ViewModel:由于我有多个字符,我正在创建多个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);
}
Run Code Online (Sandbox Code Playgroud)

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

Ree*_*sey 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());
}
Run Code Online (Sandbox Code Playgroud)

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

void Chat_Incoming(Game.ChatLine line)
{
    uiFactory.StartNew( () => Chat.Add(line) );
}
Run Code Online (Sandbox Code Playgroud)

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

void Chat_Incoming(Game.ChatLine line)
{
    uiFactory.StartNew( () => Chat.Add(line) ).Wait();
}
Run Code Online (Sandbox Code Playgroud)