C# 等待用户在多个控件中单击一个控件

C# 等待用户在多个控件中单击一个控件,c#,winforms,async-await,C#,Winforms,Async Await,这个问题是从一堆其他人的同样的话开始的。。。我试着用c做一个纸牌游戏,我见过很多类似的问题,但是没有人真正解决我的问题 我将用一个小场景介绍我的问题: 玩家A与目标B玩牌X 玩家B需要选择一张牌Y或传球 玩家B视图包含他的牌,每张牌由a表示 图片盒 要继续游戏,我需要玩家B的控制器等待,直到他点击卡 属于Y型,或通过转弯 对我来说,最简单的方法就是用布尔值假装等待。很容易记录最后一张牌,例如X,然后等待该牌。在Y类型的牌上触发Click事件或按下pass按钮时,单击事件 问题是它需要使用大量布尔

这个问题是从一堆其他人的同样的话开始的。。。我试着用c做一个纸牌游戏,我见过很多类似的问题,但是没有人真正解决我的问题

我将用一个小场景介绍我的问题:

玩家A与目标B玩牌X

玩家B需要选择一张牌Y或传球

玩家B视图包含他的牌,每张牌由a表示 图片盒

要继续游戏,我需要玩家B的控制器等待,直到他点击卡 属于Y型,或通过转弯

对我来说,最简单的方法就是用布尔值假装等待。很容易记录最后一张牌,例如X,然后等待该牌。在Y类型的牌上触发Click事件或按下pass按钮时,单击事件

问题是它需要使用大量布尔变量和if/else来处理这些事件

有什么更好的方法来实现这样的事情呢

编辑


一般来说,这些问题都是通过创建一个状态机来解决的,即知道游戏处于什么状态的东西,以及根据这个状态如何处理下一个输入。有几种方法可以对状态机进行编程,但其中一种方法是使用async/await让编译器进行编程

您可以将按钮包装在类中,以便在每次按下按钮时完成任务:

public class ButtonAwaiter
{
    private readonly Button button;
    private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    public ButtonAwaiter(Button button)
    {
        this.button = button;
        this.button.Click += OnClick;
    }

    private void OnClick(object sender, EventArgs e)
    {
        tcs.SetResult(true);
        tcs  = new TaskCompletionSource<bool>();
    }

    public Task GetTask() => tcs.Task;
}

当用户需要遵循某个操作序列时,此方法特别好,因为它可以让您以相当简单的方式编写代码。

也许您可以向CardClass添加一个存储枚举值的变量。如果已单击某张卡,则可以使用switchcase禁用与单击类型不匹配的卡。。。这只是一个想法。。。也许你可以在文章中添加一些代码或GUI的屏幕截图,这将非常有用async/await关键字用于异步编程。在这里,您没有尝试异步运行IO或CPU绑定的代码。您正在尝试确定玩家何时执行了某个动作、玩了一张牌或通过了某个动作。玩家B打牌/传球的动作应该调用一个方法或调用一个事件,将控制权传递回玩家a。根据您提供的信息,不需要等待任何事情。这实际上很好,我必须稍微更改代码以强制使用Task,否则我无法获得结果。我仍然需要相当多的控件来执行,但代码要简单得多。谢谢
GameForm.cs

public void PlayCardFromHand(int index)
{
    if (playY)
    {
       // Check if card at index is instance of Y
    }
}

public void NotifyPlayYCard()
{
    playY = true;
}

public void CardClick(object sender, EventArgs e)
{
    PictureBox current = (PictureBox)sender;
    PlayCardFromHand(pnl_cards.Controls.IndexOf(current));
}
public class ButtonAwaiter
{
    private readonly Button button;
    private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
    public ButtonAwaiter(Button button)
    {
        this.button = button;
        this.button.Click += OnClick;
    }

    private void OnClick(object sender, EventArgs e)
    {
        tcs.SetResult(true);
        tcs  = new TaskCompletionSource<bool>();
    }

    public Task GetTask() => tcs.Task;
}
    public async Task DoGameLoop()
    {
        var b1 = new ButtonAwaiter(button1);
        var b2 = new ButtonAwaiter(button2);
        while (GameIsInProgress)
        {
            var pressed = await Task.WhenAny(new[] {b1.GetTask(), b2.GetTask()});
        }
    }