简体   繁体   中英

WPF MVVMLight Messenger UI thread issue

I have an issue regarding using MVVMLight messenger in a WPF (MVVM) application. In a view I have an element ( LoadingControl ) which visibility property is bound to a viewmodel property ( IsBusy ) by using custom visibility converter. In a viewmodel I change the property value ( IsBusy ) by sending a MVVM message:

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

Here I have the method in a viewmodel which is resgistered to accept LoadingMessage messages, where IsBusy property is changed.

This works fine, however in one of my viewmodel methods where I send this message, UI thread blocks and IsBusy property value changes, but visibility of my UI element LoadingControl doesn't until main operation is not finished, eg:

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

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

I guess that the problem is because in a viewmodel the execution is not on the ui thread, so I tried to call this directly in a Call() method:

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

But this doesn't work too, LoadingControl is not shown until method ends. As I'm not so familiar with multithreading, I supose that there is some other issue here. Any help is appreciated.

Messenger sends message in your thread so you need to wait. I think you need to send message in another thread.

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

Another (lighter) way can be to fire and forget your code with Task

Task.Factory.StartNew(() => 
   { 
       Messenger.Default.Send(new LoadingMessage(true));
       SomeServiceCall();
       Navigate();
   });

If you want to force your Action to be executed on another thread, you can pass TaskScheduler.Default to the StartNew() call. But by doing so, you might fall on Invalid cross-thread access Exception , since you code no longer executes on the UI thread, but on a Background one. So you might need to Dispatch your code setting view-bounded properties (like your IsBusy ) back to the UI-Thread by using the Dispatcher :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM