How I can safely run async code, when handling messages from Messenger?

0

I am using MVVM, inparticular MVVMLight. For boradcasting to all of my modelviews, that no internet connection is available I am using Messenger class. The modelviews subscribe to this event in order to reload itself with offline data, inform user etc.

However, I have a problem. When I have the folowing handler:

private void HandleNoInternetMessage(NoInternetAccessMessage obj)
{
    Task.Run(async () => await InitializeForOfflineInternalAsync());
}
public async Task InitializeForOfflineInternalAsync()
{
    try
    {
        WaitingLayerViewModel.ShouldBeVisible = true;
        WaitingLayerViewModel.IsBusy = true; //<--exception HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)
        bool switchToOffline = await CommonViewModelProvider.InformUserOfNoInternetAccessAndChangeAppState(); //<!- CoreWindow.GetForCurrentThread().Dispatcher is null
        await FilterTestItemViewModel.InitializeForOfflineAsync();
        await FilterTestItemViewModel.InitializeForOfflineAsync();
        WaitingLayerViewModel.ShouldBeVisible = false;
        WaitingLayerViewModel.IsBusy = false;
        ...
    }
}

I got exception HRESULT: 0x8001010E (RPC_E_WRONG_THREAD), because in InitializeForOfflineInternalAsync I am changing some properties of the viewmodel wchich are bound in XAML (or at least I think it is because of that). However, it is weird, because I am changing in other code bound properties regularly and have no problems with it (and the thread is a working thread).

Now, how can i solve that?

  • The messanger let me provide only delegate which is not async (which make kind of sense), so I can not have the HandleNoInternetMessage method async

  • I am using async await ... no explicit spawning of threads

  • I dont have access in VM to Dispatcher, because I am in VM which should not know about platform dependent stuff. And when I tried to use it to show a message, NullPointer excpetion was thrown when calling CoreWindow.GetForCurrentThread().Dispatcher; And again when calling from other places, no such exception was thrown

I guess the question is How I can safely run async code, which changes boudn properties, when handling messages from Messenger?

asynchronous
mvvm
windows-runtime
async-await
mvvm-light
asked on Stack Overflow Oct 24, 2014 by Ondrej Peterka • edited Oct 26, 2014 by svick

1 Answer

4

You're responding to messages that are logically events, so this is an acceptable use case for async void.

private async void HandleNoInternetMessage(NoInternetAccessMessage obj)
{
    await InitializeForOfflineInternalAsync();
}

public async Task InitializeForOfflineInternalAsync()
{
    try
    {
        WaitingLayerViewModel.ShouldBeVisible = true;
        WaitingLayerViewModel.IsBusy = true;
        bool switchToOffline = await CommonViewModelProvider.InformUserOfNoInternetAccessAndChangeAppState();
        await FilterTestItemViewModel.InitializeForOfflineAsync();
        await FilterTestItemViewModel.InitializeForOfflineAsync();
        WaitingLayerViewModel.ShouldBeVisible = false;
        WaitingLayerViewModel.IsBusy = false;
        ...
    }
}

Remember that Task.Run is for CPU-bound code (as I describe on my blog).

answered on Stack Overflow Oct 24, 2014 by Stephen Cleary

User contributions licensed under CC BY-SA 3.0