C#中的PostMessage等价于用MVVM与主线程同步?主线、PostMessage、MVVM

2023-09-07 16:08:29 作者:嘴巴不干净就用大姨妈漱口

我一定是搜索迟缓,因为这是另一个我无法解决的看似常见的问题.

I must be retarded with searching, because here's another seemingly common problem that I haven't been able to solve.

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

Here's my problem -- I am using WPF and MVVM, and I have a statemachine that executes in the model. If an error occurs, I need to pass information up to the ViewModel to display the error. This part seems to work okay. When the user clicks the desired behavior, the code in the model continues, and looks at the object the user interacts with to determine what to do next.

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

The problem is that the model needs to reload a file, which updates the GUI with the contents of said file. Because the model is executing in a thread, you can imagine what I'm going to ask next -- how the hell do you synchronize with the GUI properly? In MFC, I would have used either SendMessage or PostMessage to accomplish the GUI update.

我已阅读有关 WinForms 的文章,建议使用 InvokeRequired 自动调用如有必要,请开始调用.我实际上不知道 BeginInvoke 会完成我想要的,所以我被鼓励去学习这个.

I've read articles for WinForms that suggest using InvokeRequired to automatically call BeginInvoke if necessary. I actually didn't know that BeginInvoke would accomplish what I wanted, so I was encouraged to learn this.

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

How do I actually call BeginInvoke from my model? Does this method even apply to WPF? I went ahead and implemented a delegate and then called Invoke, but I get the same error that tells me the collection can't be modified from this thread. I also tried BeginInvoke for the hell of it, but I assume that also wouldn't work because it would just launch from a different thread anyway.

困惑.如果我错过了在互联网上发布的非常明显的内容,请继续对我进行口头抨击,我可能应得的.

Confused. If I have missed something really obvious that's been posted about all over the internet, go ahead and give me a verbal lashing, I probably deserve it.

编辑 - 我可能还应该补充一点,我正在寻找除计时器或基于 BackgroundWorker 的解决方案之外的其他东西,除非这是在 WPF 中解决此问题的唯一方法/MVVM.另外,我想知道是否有任何 MVVM 工具包已经具备此类功能......

EDIT - I should probably also add that I am looking for something other than a timer or BackgroundWorker-based solution, unless that's the only way to solve this in WPF / MVVM. Also, I wonder if any of the MVVM toolkits would have facilities for this sort of thing already...

推荐答案

如果您想在 WPF 中将一些工作从后台线程调度到 UI 线程,请使用 DispatcherObject.这是一篇很好的文章,介绍了如何使用调度程序构建更多响应式应用程序.

If you want to schedule some work from a background thread to the UI thread in WPF, use the DispatcherObject. Here's a nice article on how to Build More Responsive Apps with the Dispatcher.

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

Update: Note that if you use an event to send notifications from the Model to the ViewModel, you still need to switch to the UI thread somewhere. Whether that switch should be in the Model or the ViewModel is a good design discussion, but it's orthogonal to your question.

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

The event will be raised on the corresponding Dispatcher thread. Since you need to get to the UI thread, you need to use a Dispatcher that is created on the UI thread. The easiest way to get one is to use the DispatcherObject.Dispatcher property on one of the UI elements. The alternative is to create one in your Model or ViewModel. If you are a design purist, I would suggest you create the Dispatcher in your Model and dispatch the call back to the UI thread before you raise the event to which the ViewModel is listening. This way all the thread switching and management is contained in your Model and the ViewModel works as a single-threaded on the UI thread only.