首页 > 解决方案 > Unity 中 UI 的异步/等待样式

问题描述

我想在 Unity for UI 中实现异步/等待样式。我突然想到,您可以编写一个静态类,在其中定义一个像这样的方法public static async Task<Button> WaitForButtonClickAsync(CancellationToken ct, params Button[] buttons)。这个方法将等待任何传输的按钮被按下Task.whenAny,然后它会返回一个按钮。但那之后呢?我只能想出一个巨大的switch-case块来确定按下了哪个按钮或立即将带有回调的按钮传递给该方法,但在我看来,这些不是最好的解决方案。

标签: c#unity3dasync-await

解决方案


我已经非常成功地使用了这种模式。但是您对巨型开关盒的看法是正确的,它确实需要一些样板。但是话又说回来,回调实际上并没有更短。

例子:

Button pressedButton = await WaitForButtonClickAsync(ct, button1, button2, button3);
if (pressedButton == button1) await DoStuff1(ct);    
if (pressedButton == button2) await DoStuff2(ct);
if (pressedButton == button3) await DoStuff3(ct);

或者使用回调(请注意,我们没有在这里删除事件处理程序,所以这个解决方案实际上一点也不短),尽管在这里我们没有获得链接异步代码的优势:

button1.onClick += () => DoStuff1();
button2.onClick += () => DoStuff2();
button3.onClick += () => DoStuff3();

您还可以制作某种帮助来避免 if-else,如下所示:

await WaitForButtonHandlersAsync(ct, 
                                (button1, DoStuff1), 
                                (button2, DoStuff2),
                                (button3, DoStuff3));

但是当你开始混合除了按钮之外的其他等待时,这可能会变得混乱,而且我总是回到 if-else 列表。

编辑:广告的一件事是您还可以对事物进行分组。例如,如果除了一些特定于上下文的按钮之外,您还有一组常用的导航按钮/手势,则可以将导航按钮捆绑到一个任务中。此示例还包含视频中显示的链接令牌的用法。

using (var cts = CreateLinkedTokenSource(ct))
{
    var navigationTask = WaitForNavigationEventAsync(cts.Token);
    var buttonTask1 = WaitForButtonClickAsync(cts.Token, button1);
    var buttonTask2 = WaitForButtonClickAsync(cts.Token, button2);

    var finishedTask = await Task.WhenAny(navigationTask, buttonTask1, buttonTask2);
    await finishedTask; // "Reveal" and propagate exceptions
    cts.Cancel();

    if (finishedTask == navigationTask) await Navigate(navigationTask.Result, ct);
    if (finishedTask == buttonTask1) await DoStuff1(ct);
    if (finishedTask == buttonTask2) await DoStuff2(ct);
}

使用这种结构,列表永远不会失控,并且您可以避免一些重复的代码。


推荐阅读