UI Thread issue with view model in MVVMCross
Asked Answered
L

3

6

I am using MVVMCross with my cross-platform Windows Phone and Android app. In the core project's main view model, I am doing some background work using TPL and I want to make sure that in the callback, when I make changes to the properties of the view model which will trigger UI change, that the code is run on UI thread, how do I achieve this?

For code, here is how it likes

    private MvxGeoLocation _currentLocation;
    private Task<MvxGeoLocation> GetCurrentLocation()
    {
        return Task.Factory.StartNew(() =>
            {
                while (_currentLocation == null && !LocationRetrievalFailed)
                {
                }
                return _currentLocation;
            });
    }

    var location = await GetCurrentLocation();
    if (LocationRetrievalFailed)
    {
        if (location == null)
        {
            ReverseGeocodingRequestFailed = true;
            return;
        }
        // Show toast saying that we are using the last known location
    }
    Address = await GooglePlaceApiClient.ReverseGeocoding(location);
Liponis answered 12/2, 2014 at 13:54 Comment(0)
A
2

Method RequestMainThreadAction is now obsolete. Today you have to do

var dispatcher = Mvx.Resolve<IMvxMainThreadAsyncDispatcher>();
await dispatcher.ExecuteOnMainThreadAsync(()=> { .... });
Angry answered 26/2, 2020 at 12:25 Comment(0)
H
15

Did you try IMvxMainThreadDispatcher?

var dispatcher = Mvx.Resolve<IMvxMainThreadDispatcher>();
dispatcher.RequestMainThreadAction(()=> { .... });

See more on the implementation:

https://github.com/MvvmCross/MvvmCross/search?q=IMvxMainThreadDispatcher&type=Code

Usually I don't think you need this though.

Since you start the async processing from main thread, the async operations should return back to main thread.

Can you give an example of the async code you are doing?

Homeroom answered 12/2, 2014 at 14:22 Comment(6)
Also see lots of questions on here - like #16143129Ouster
I added some code example. Also I want to know if it's safe to modify the ViewModel property in the thread other than the main UI thread?Liponis
When you said that "Since you start the async processing from main thread, the async operations should return back to main thread.", do you mean C# 5.0's async/await or just Task<T>? Or both? I want to know if I attach a ContinueWith callback to a Task<T>, is it on the caller's thread or the Task's thread?Liponis
Never mind my previous question, I'll try to figure it out myself by writing an testLiponis
ContinueWith returns to the caller thread. it's the same thing with calling await again. Here's a very good read: jaylee.org/post/2012/06/18/…Homeroom
This answer solved my problem. In my case I was adding an object to an ObservableCollection in a SignalR method called from serverAllysonalma
E
3

Update on 24th August 2020: As @claudio-redi has mentioned, ExecuteOnMainThreadAsync needs to be used. But Mvx.Resolve is now obsolete. So the latest snippet would be:

var mainThreadAsyncDispatcher = Mvx.IoCProvider.Resolve<IMvxMainThreadAsyncDispatcher>();
await mainThreadAsyncDispatcher.ExecuteOnMainThreadAsync( async ()=> { await SomeAsyncTask() });
Einkorn answered 24/8, 2020 at 5:47 Comment(0)
A
2

Method RequestMainThreadAction is now obsolete. Today you have to do

var dispatcher = Mvx.Resolve<IMvxMainThreadAsyncDispatcher>();
await dispatcher.ExecuteOnMainThreadAsync(()=> { .... });
Angry answered 26/2, 2020 at 12:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.