使用来自同步UI线程的回调调用异步方法

时间:2016-07-11 10:58:37

标签: c# asynchronous asynccallback

我真的被困在这里......我有一个XAML页面UI,并希望每次用户与UI交互时都调用异步函数。
我使用SignalR进行联网:

public static class ProtocolClient
{
    private static HubConnection hubConnection;
    private static IHubProxy protocolHubProxy;

    public static async void connect(string server)
    {
        hubConnection = new HubConnection(server);
        protocolHubProxy = hubConnection.CreateHubProxy("ProtocolHub");
        protocolHubProxy.On<Body>("BodiesChanged", body =>
            //call a callback to return body
        );
        await hubConnection.Start(); //wait for connection
    }

    public static async void sendTouch(Touch touch)
    {
        Body body = await protocolHubProxy.Invoke<Body>("GetBodyForTouch", touch);
        //call a callback to return body
    }
}

UI:

public sealed partial class MainPage : Page
{
    [...]
    private void Canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
    {
        [...]
        switch (ptrPt.PointerDevice.PointerDeviceType)
        {
            case Windows.Devices.Input.PointerDeviceType.Mouse:
                if (ptrPt.Properties.IsLeftButtonPressed)
                {
                    //call sendTouch
                }
                break;
            default:
                break;
        }
        [...]
    }
}

我需要一个可以修改UI的回调。如何从界面调用connect和sendTouch并向其传递回调?

2 个答案:

答案 0 :(得分:0)

您不需要回调。只需在await hubConnection.Start();语句后添加代码即可。您的方法是“多种方法切割”,并在等待回来后“继续”。 await的工作方式类似于阻止语句,但不会冻结gui。

public static async void connect(string server)
{
    hubConnection = new HubConnection(server);
    protocolHubProxy = hubConnection.CreateHubProxy("ProtocolHub");
    protocolHubProxy.On<Body>("BodiesChanged", body =>
        //call a callback to return body
    );
    await hubConnection.Start(); //wait for connection

    // add code here.
}

处理命令async(来自gui事件)时,不要忘记禁用控件以防止执行命令多于。

答案 1 :(得分:0)

不要使用async void方法。如果您不需要返回值,请使用async Task - 如果您这样做,请使用async Task<SomeType>

然后,当您需要调用异步方法时(按照惯例,这些方法应该命名为ConnectAsyncSendTouchAsync),await它:

await SendTouchAsync(...);

当异步工作流程结束时,您的延续将被编组回UI线程(因为您在同步上下文中await编辑),并且您可以轻松地操作UI。

当您使用await时,

async void似乎有效,但问题是调用者无法跟踪异步工作流 - 就调用者而言,该方法刚刚结束当时和现在,调用者中的代码照常继续。

确保将Canvas_PointerPressed标记为async - 遗憾的是,在这种情况下,必须async void。确保永远不要直接调用事件处理程序 - UI线程可以正确处理回调,而代码则不能。如果您需要来自其他方法的相同逻辑,只需将其分离为适当的async Task方法和await来自事件处理程序的方法。