WPF MVVMLight Messenger UI 线程问题

WPF MVVMLight Messenger UI thread issue

我有一个关于在 WPF (MVVM) 应用程序中使用 MVVMLight 信使的问题。在视图中,我有一个元素 (LoadingControl),其可见性 属性 绑定到视图模型 属性 (IsBusy) 通过使用自定义可见性转换器。在视图模型中,我通过发送 MVVM 消息更改 属性 值(IsBusy):

Messenger.Default.Send(new LoadingMessage(true));

这里我有一个视图模型中的方法,该方法被注册为接受 LoadingMessage 消息,其中 IsBusy 属性 已更改。

这工作正常,但是在我发送此消息的视图模型方法之一中,UI 线程块和 IsBusy 属性 值发生变化,但我的 UI 元素 LoadingControl 的可见性直到主操作未完成才可见,例如:

void Call() {
    Messenger.Default.Send(new LoadingMessage(true));

    SomeServiceCall();
    Navigate(); // <- this works with UI, too
} // <- this is the place when LoadingControl is shown.

我猜问题是因为在视图模型中执行不在 ui 线程上,所以我试图在 Call() 中直接调用它方法:

DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
    IsBusy = true;
});

但这也不起作用,LoadingControl 直到方法结束才显示。由于我对多线程不太熟悉,我想这里还有其他问题。感谢任何帮助。

Messenger 在您的线程中发送消息,因此您需要等待。我想你需要在另一个线程中发送消息。

DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
    Messenger.Default.Send(new LoadingMessage(true));
});

另一种(较轻的)方法可以是使用 Task

触发并忘记您的代码
Task.Factory.StartNew(() => 
   { 
       Messenger.Default.Send(new LoadingMessage(true));
       SomeServiceCall();
       Navigate();
   });

如果你想强制你的 Action 在另一个线程上执行,你可以将 TaskScheduler.Default 传递给 StartNew() 调用。但是这样做,您可能会陷入 Invalid cross-thread access Exception,因为您的代码不再在 UI 线程上执行,而是在后台线程上执行。因此,您可能需要使用 Dispatcher 将代码设置视图边界属性(如 IsBusy)分派回 UI-Thread:

Application.Current.Dispatcher.BeginInvoke(() =>
{
    IsBusy = true;
}