You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将await.WhenAny()与GetAwaiter扩展方法结合实现按钮点击等待

解决方案:将按钮点击事件包装为Task以兼容Task.WhenAny

要让按钮点击能和Task.WhenAny配合使用,核心是把按钮点击事件转换为Task类型——因为Task.WhenAny仅接受Task/Task<T>作为参数,而非自定义的可等待对象。

1. 添加返回Task的扩展方法

修改你的ButtonAwaiterExtensions静态类,新增一个将按钮点击包装为Task的扩展方法:

public static class ButtonAwaiterExtensions
{
    // 保留原有的GetAwaiter方法,支持直接await Button
    public static ButtonAwaiter GetAwaiter(this Button button)
    {
        return new ButtonAwaiter()
        {
            Button = button
        };
    }

    // 新增:将按钮点击转换为Task,兼容Task.WhenAny/WhenAll
    public static Task WhenClickedAsync(this Button button)
    {
        var tcs = new TaskCompletionSource<object?>();
        RoutedEventHandler? handler = null;

        handler = (sender, e) =>
        {
            button.Click -= handler;
            tcs.TrySetResult(null);
        };

        button.Click += handler;
        return tcs.Task;
    }

    // 保留原有的ButtonAwaiter类
    public class ButtonAwaiter : INotifyCompletion
    {
        public bool IsCompleted => false;

        public void GetResult() { }

        public Button? Button { get; set; }

        public void OnCompleted(Action continuation)
        {
            RoutedEventHandler? h = null;
            h = (o, e) =>
            {
                Button!.Click -= h;
                continuation();
            };
            Button!.Click += h;
        }
    }
}

2. 使用Task.WhenAny等待任意按钮点击

现在你可以通过以下方式等待多个按钮中任意一个被点击:

// 等待Button1或Button2中任意一个被点击
await Task.WhenAny(Button1.WhenClickedAsync(), Button2.WhenClickedAsync());

额外优化:返回点击的按钮(可选)

如果需要知道是哪个按钮被点击,可以让方法返回Task<Button>:

public static Task<Button> WhenClickedAsync(this Button button)
{
    var tcs = new TaskCompletionSource<Button>();
    RoutedEventHandler? handler = null;

    handler = (sender, e) =>
    {
        button.Click -= handler;
        tcs.TrySetResult(button);
    };

    button.Click += handler;
    return tcs.Task;
}

使用时可以获取被点击的按钮:

Button clickedButton = await Task.WhenAny(Button1.WhenClickedAsync(), Button2.WhenClickedAsync());
// 处理点击的按钮

为什么原来的方式不行?

Task.WhenAny的参数要求是IEnumerable<Task>,它只识别标准的Task类型,不会处理自定义的INotifyCompletion可等待对象。通过将按钮点击包装为Task,就能完美兼容Task类的所有静态方法。

内容的提问来源于stack exchange,提问作者Tom667

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 10:25:25