简体   繁体   中英

What is the Xamarin Forms equivalent of Dispatcher.PushFrame?

I have the following code in my WPF application to call and wait for asnyc functions from a non-async function on the UI thread without blocking it. This is done by pumping messages in the background using DispatcherFrame:

public static void WaitWithPumping(this Task task)
{
    if (task == null) throw new ArgumentNullException(“task”);
    var nestedFrame = new DispatcherFrame();
    task.ContinueWith(_ => nestedFrame.Continue = false);
    Dispatcher.PushFrame(nestedFrame);
    task.Wait();
}


public static T ResultWithPumping<T>(this Task<T> task)
{
    if (task == null) throw new ArgumentNullException(“task”);
    var nestedFrame = new DispatcherFrame();
    task.ContinueWith(_ => nestedFrame.Continue = false);
    Dispatcher.PushFrame(nestedFrame);
    return task.Result;
}

Source

I'd like to use something like this in my Xamarin Forms iOS/Android app to be able to work with the same codebase.

This is all needed because of a 3rdparty library which does not support async/await. For the same reason I cannot just use Task.Run() or ConfigureAwait(false) because the functions are needed to be run on the UI tread and I need to wait for the result before launching the next Task from the same blocking function.

public async void RunTaskOnUi1Async()
{
  await ProcessAsync();

  UpdateUiInner();
}

public async object RunTaskOnUi2Async()
{
  var result = await ProcessAsync();

  UpdateUiInner(result);
  return result;
}

// Called from the UI thread
public void RunTasks()
{
    UpdateUi();

    RunTaskOnUi1Async().WaitWithPumping();

    UpdateUi();

    var result = RunTaskOnUi2Async().ResultWithPumping();

    UpdateUi(result);
}

EDIT #1: Updated example. I know the example is a bit lame. Why don't I change RunTasks to async? Or just run ProcessAsync() on a background thread? Well, I am working on a legacy project (of course) and RunTasks is a LUA script processing engine which calls into my C# code and also manipulates UI directly so it must be run on the UI thread and it's non-async by design. Changing it would be a tremendous work. But the rest of my code is async and I was able to work around this problem in WPF easily by using the message pumping method.

Try the code below:

public static Task<T> BeginInvokeOnMainThreadAsync<T>(Func<T> a)
{
var tcs = new TaskCompletionSource<T>();
Device.BeginInvokeOnMainThread(() =>
    {
        try
        {
            var result = a();
            tcs.SetResult(result);
        }
        catch (Exception ex)
        {
            tcs.SetException(ex);
        }
    });
return tcs.Task;
}

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