如何在WinRT对象中实现异步回调?

时间:2018-07-02 12:58:28

标签: c# uwp async-await windows-runtime winrt-component

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

// 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 :(得分:0)

这是彼得·托尔(Peter Torr)的评论提示的另一种选择。

public SCardError ListReaders(IntPtr hContext, string[] groups, out string[] readers) {
    var dwReaders = 0;

    // initialize groups array
    byte[] mszGroups = null;
    if (groups != null)
    mszGroups = SCardHelper.ConvertToByteArray(groups, TextEncoding);            

    // determine the needed buffer size
    var rc = SCardHelper.ToSCardError(
        SCardListReaders(hContext,
        mszGroups,
        null,
        ref dwReaders));

    if (rc != SCardError.Success) {
        readers = null;
        return rc;
    }

    //doubling buffer size to work through thin clients
    dwReaders *= 2; // <------------------ New line

    // initialize array
    var mszReaders = new byte[dwReaders * sizeof(char)];

    rc = SCardHelper.ToSCardError(
        SCardListReaders(hContext,
        mszGroups,
        mszReaders,
        ref dwReaders));

    readers = (rc == SCardError.Success)
              ? SCardHelper.ConvertToStringArray(mszReaders, TextEncoding)
              : null;

    return rc;
}

然后在WinRT组件中,您可以像这样调用事件:

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

最后在客户端代码中添加如下处理程序:

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