相当于C#中的PostMessage与主线程与MVVM同步?

我必须坚持不懈地寻找,因为这是我无法解决的另一个看似常见的问题。

这是我的问题 – 我正在使用WPF和MVVM,并且我有一个在模型中执行的状态机。 如果发生错误,我需要将信息传递给ViewModel以显示错误。 这部分似乎工作正常。 当用户单击所需行为时,模型中的代码将继续,并查看用户与之交互的对象以确定下一步操作。

问题是模型需要重新加载文件,该文件使用所述文件的内容更新GUI。 因为模型在一个线程中执行,你可以想象我接下来要问的问题 – 你到底该如何正确地与GUI同步? 在MFC中,我会使用SendMessage或PostMessage来完成GUI更新。

我读过WinForms的文章 ,建议使用InvokeRequired在必要时自动调用BeginInvoke。 我实际上不知道BeginInvoke会完成我想要的东西,所以我被鼓励学习这个。

我如何从我的模型中实际调用BeginInvoke? 这种方法甚至适用于WPF吗? 我继续并实现了一个委托,然后调用了Invoke,但是我得到了同样的错误,告诉我无法从这个线程修改集合。 我也尝试过BeginInvoke,但我认为这也行不通,因为它无论如何都会从另一个线程启动。

困惑。 如果我错过了一些非常明显的内容,这些内容已经发布在互联网上,请继续给我一个口头抨击,我可能应该得到它。

编辑 – 我应该补充一点,我正在寻找除定时器或基于BackgroundWorker的解决方案以外的东西,除非这是在WPF / MVVM中解决这个问题的唯一方法。 另外,我想知道是否有任何MVVM工具包已经具有此类function的设施……

如果要将后台线程中的某些工作安排到WPF中的UI线程,请使用DispatcherObject 。 这是一篇关于如何使用Dispatcher构建更多响应式应用程序的好文章。

更新:请注意,如果您使用事件将模型中的通知发送到ViewModel,则仍需要切换到某处的UI线程。 该开关应该在模型中还是ViewModel中是一个很好的设计讨论,但它与您的问题正交。

该事件将在相应的Dispatcher线程上引发。 由于您需要访问UI线程,因此需要使用在UI线程上创建的Dispatcher。 获得一个的最简单方法是在其中一个UI元素上使用DispatcherObject.Dispatcher属性。 另一种方法是在Model或ViewModel中创建一个。 如果您是设计纯粹主义者,我建议您在模型中创建Dispatcher,并在引发ViewModel正在侦听的事件之前将调用分派回UI线程。 这样,所有线程切换和管理都包含在模型中,而ViewModel仅作为UI线程上的单线程工作。

我认为你的ViewModel真的不应该知道关于View的任何信息,包括它是否是WPF UI,或者该UI是否具有Dispatcher线程的概念,所以红旗应该在你启动时立即飞行在ViewModel中编写代码,尝试CheckAccess()或InvokeRequired,以便将一些代码封送到UI线程。 相反,我会让模型引发一个View可以监听并相应更新自身的事件,或让ViewModel公开一个View简单绑定的属性(例如bool FileIsLoading),以便检测并显示模型是什么异步执行,ViewModel负责确保该属性的值是准确的。

例如:

 public partial class MainWindow : Window { private ViewModel _model = new ViewModel(); public MainWindow() { InitializeComponent(); DataContext = _model; } private void Button_Click(object sender, RoutedEventArgs e) { _model.Run(); } }      public class ViewModel : INotifyPropertyChanged { private bool _isIdle = true; public bool IsIdle { get { return _isIdle; } set { _isIdle = value; OnPropertyChanged("IsIdle"); } } public void Run() { ThreadPool.QueueUserWorkItem((state) => { IsIdle = false; Thread.Sleep(10000); IsIdle = true; }); } #region INotifyPropertyChanged Implementation protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler propertyChanged = this.PropertyChanged; if (propertyChanged != null) { propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; #endregion } 

我有另一种似乎有效的方法,我只是想把它扔出去得到一些评论(如果有人甚至再读这个问题了!)。

我开始使用MVVM Light Toolkit的Messenger类,它似乎对我来说非常好用。 例如,我们以ProgressBar为例。 我使用ViewModel注册了两条消息,用于设置进度值和进度最大值。 然后在我的模型中,当它设置任务和整个过程时,它会发送这些消息。 当VM收到消息时,它只会更新数据绑定值,我的GUI会自动更新! 这很容易,但我想知道你们对这种方法的看法。 没有其他人这样做没有事故吗?