Mvvmcross: IMvxMainThreadDispatcher needs a method where you can wait for the UI task to finish

Created on 19 Jun 2015  路  9Comments  路  Source: MvvmCross/MvvmCross

In my application I have the need to execute a task on UI and wait for it to return.

I know that (at least for iOS) there is such a method ... is such a method also available for all the other platforms? If yes, I would appreciate if such a method could be provided across platforms :wink:

needs-investigation

Most helpful comment

@tofutim and @SimonSimCity

why dont you just do something like:

        var myTaskCompletionSource = new TaskCompletionSource<bool>();
        var dispatcher = Mvx.Resolve<IMvxMainThreadDispatcher>();
        dispatcher.RequestMainThreadAction(async () =>
        {
            loginPage = new LoginPage(startUri, endUri);
            token = await loginPage.Display();
            myTaskCompletionSource.SetResult(true);
        });

        if(myTaskCompletionSource.Task.Result)
        {
            JObject tokenObj = JObject.Parse(token.Replace("%2C", ","));
        }

All 9 comments

If you have a Task can't you just call Wait() on it?

The problem is that I don't have ...

I have to call Mvx.Resolve<IMvxMainThreadDispatcher>().RequestMainThreadAction(() => { ... }); and I give away the control. If I could wait for that task, that is run on the main-thread there - that would be great!

You could always just set up your own await logic using a TaskCompletionSource in your action? But really you need to be careful with blocking threads... (It's something that always bites me, any way!)

Instead of RequestMainThreadAction() can't you use the current dispatcher or synchronization context with a Task?

If I take a look at http://developer.xamarin.com/guides/ios/user_interface/controls/part_2_-_working_with_the_ui_thread/ I read of two different methods:

If code is executing on a background thread, in a task or a callback then it is likely NOT executing on the main UI thread. In this case you should wrap the code in a call to InvokeOnMainThread or BeginInvokeOnMainThread like this:

When you take a look at the implementation in MvvmCross (https://github.com/MvvmCross/MvvmCross/blob/e9802dfb45f0d52da3fb056b020032963142b9c3/Cirrious/Cirrious.MvvmCross.Touch/Views/MvxTouchUIThreadDispatcher.cs) it only offers that asynchronous method, where you can't wait for the action to finish before resuming.

How would you solve that with code? I just can't see a way of solving this by the given ways ...

You could update that interface and always use InvokeOnMainThread(), putting it into a separate task and return it, so the user can easily choose to await it. Don't know how much overload that would add when directly awaiting that task ... maybe a second method would do ...

Just my 2 cent ...

I ran into this today. I had a login page that had to be called on the main thread. The code looks like

        var dispatcher = Mvx.Resolve<IMvxMainThreadDispatcher>();
        dispatcher.RequestMainThreadAction(async () =>
        {
            loginPage = new LoginPage(startUri, endUri);
            token = await loginPage.Display();
        });

        JObject tokenObj = JObject.Parse(token.Replace("%2C", ","));

of course, token never gets set because (I think) it hops straight out of the async function before token is set.

Update. In this case I am using Windows, and it calls this

    public bool RequestMainThreadAction(Action action)
    {
        if (this._uiDispatcher.HasThreadAccess)
        {
            action();
            return true;
        }

        this._uiDispatcher.RunAsync(CoreDispatcherPriority.Normal, () => ExceptionMaskedAction(action));
        return true;
    }

so... no way to wait. :P

@tofutim and @SimonSimCity

why dont you just do something like:

        var myTaskCompletionSource = new TaskCompletionSource<bool>();
        var dispatcher = Mvx.Resolve<IMvxMainThreadDispatcher>();
        dispatcher.RequestMainThreadAction(async () =>
        {
            loginPage = new LoginPage(startUri, endUri);
            token = await loginPage.Display();
            myTaskCompletionSource.SetResult(true);
        });

        if(myTaskCompletionSource.Task.Result)
        {
            JObject tokenObj = JObject.Parse(token.Replace("%2C", ","));
        }

@gabrieligbastos you just saved few hours of my life :)

Was this page helpful?
0 / 5 - 0 ratings