应该如何实现 WinRT 对象中的异步回调?

How should an async callback in a WinRT object be implemented?

到目前为止我可以创建一个委托类型,例如:

// 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;

但是因为委托 returns 一个 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();
}

感觉必须有一种更简洁的方法来实现这一点。

这是由 Peter Torr 的评论提示的替代方法。

// 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();
    }
}