Как должен быть реализован асинхронный обратный вызов в объекте WinRT? - PullRequest
0 голосов
/ 02 июля 2018

До сих пор я мог сделать тип делегата, например:

// Can't use Task in WinRT interface and TypedEventHandler doesn't work with async await
public delegate IAsyncOperation<string> AsyncEventHandler(object sender, object args);

А потом выставить в WinRT объект так:

public AsyncEventHandler OnMyEvent { get; set; }

В объекте WinRT я бы назвал его так:

if (OnMyEvent != null)
{
    var result = await OnMyEvent.Invoke(this, someArgs);
    // Do something with the result...
}

И клиентский код, потребляющий объект WinRT, может сделать это:

instanceOfWinRTObject.OnMyEvent = OnCalledBackFromWinRT;

Но так как делегат возвращает IAsyncOperation, нам нужно сделать обтекание:

private async Task<string> OnCalledBackFromWinRTAsync(object sender,
        object args)
{
    return await GetSomeStringAsync(args);
}

private IAsyncOperation<string> OnCalledBackFromWinRT(object sender, object args)
{
    return OnCalledBackFromWinRTAsync(sender, args).AsAsyncOperation();
}

Такое ощущение, что должен быть более чистый способ достижения этого.

1 Ответ

0 голосов
/ 04 июля 2018

Вот альтернатива, предложенная комментарием Питера Торра.

// Custom event args class
public sealed class MyEventArgs
{
    public string Result;
    public Deferral Deferral;
}

// Declare the event handler on the WinRT component
public event TypedEventHandler<object, MyEventArgs> OnSuspendingEvent;

Затем в компоненте WinRT вы можете вызвать событие следующим образом:

if (OnSuspendingEvent != null)
{
    var tcs = new TaskCompletionSource();
    using (var deferral = new Deferral(() => tcs.SetResult(true)))
    {
        var myArgs = MyEventArgs();
        myArgs.Deferral = deferral;
        OnSuspendUnloading.Invoke(this, myArgs);
        await tcs.Task;
        DoSomethingWithResult(args.Result);
    }
}

И, наконец, в коде клиента добавьте такой обработчик:

instanceOfWinRTObject.OnSuspendingEvent += async (sender, args) =>
{
    var deferral = args.Deferral;
    try
    {
        // Client does some async work with a result
        args.Result = await GetSomeStringAsync(args);
    }
    finally
    {
        deferral.Complete();
    }
}
...