Winforms如何等待用户点击按钮?

Winforms how to wait for user to click a button?

我正在尝试设计一款 21 点游戏,在某些时候,我需要选择 take:Hit、停牌、拆分或双倍下注的动作。我为这些操作中的每一个都有一个按钮,并且我已经将它们的所有单击事件处理程序添加到表单设计器中的相同方法中,就像这样(我真的不知道描述它的确切方式,但我指的是事件处理程序和 btnRound_Click 方法之间的 link)

this.btnSplit.Click += new System.EventHandler(this.btnRound_Click);
this.btnDoubled.Click += new System.EventHandler(this.btnRound_Click);
this.btnHit.Click += new System.EventHandler(this.btnRound_Click);
this.btnStand.Click += new System.EventHandler(this.btnRound_Click);
//Inside the Form1 class

enum RoundPlay
        {
            hit,
            stand,
            doubled,
            split
        }
        RoundPlay playchoice = RoundPlay.none;

private void btnRound_Click(object sender, EventArgs e)
        {
            switch (((Button)sender).Text)
            {                
                case "Hit":
                    playchoice = RoundPlay.hit;
                    break;
                case "Stand":
                    playchoice = RoundPlay.stand;
                    break;
                case "Split":
                    playchoice = RoundPlay.split;
                    break;
                case "Double Down":
                    playchoice = RoundPlay.doubled;
                    break;
            }            
        }

在 main 方法中我会有:

//enabling the buttons so that I can click on one of them

//place to wait for the user to click on one of the buttons
//this is where I tried using await operator 

switch (playchoice)
                {
                    case RoundPlay.hit:
                        //one action
                        break;
                    case RoundPlay.stand:
                        //other action
                        break;
                    case RoundPlay.doubled:
                        //other action
                        break;
                    case RoundPlay.split:
                        //other action
                        break;
                }

那么,“等待”用户输入的最佳方式是什么?我进行了相当多的搜索,但我所能找到的只是针对只有一个按钮的问题的解决方案,或者主要方法是否更改(为每个事件处理程序创建一个方法)无关紧要的情况的解决方案。在这种情况下,我想保持相同的方法,这样我就可以重复几轮,也就是说,我想把它放在一个 Do...While() 循环中。

我试过使用 ManualResetEvent 和 async/await,但我对其中任何一个都没有太多了解,所以如果有人有任何建议,我将不胜感激! :)

关于另一个不太重要的问题,我刚刚注意到我在 Form1_Load 方法中编写了所有与游戏进度相关的代码,这是多么不正确?有没有更好的地方把它写在里面?抱歉,如果有什么不清楚,这是我第二次 post 谢谢

Winforms 是一个框架而不是一个库。框架通常具有控制反转 (IoC),它们调用您的代码而不是您控制它们。

最简单的更改是将 while 循环体添加到新方法中,例如

private void NextAction() 
{
  switch(playchoice) 
  {
    ...
  }
  playchoice = RoundPlay.none;
}

然后在按钮偶数处理程序的末尾调用此方法

private void btnRound_Click(...) 
{
  switch (((Button)sender).Text)
  {
    ...
  }
  NextAction(); 
}

下面的方法创建了一个 Task<Control>,当单击任何提供的 Control 时该方法完成:

public static Task<Control> OnClickAnyAsync(params Control[] controls)
{
    var tcs = new TaskCompletionSource<Control>();
    foreach (var control in controls) control.Click += OnClick;
    return tcs.Task;

    void OnClick(object sender, EventArgs e)
    {
        foreach (var control in controls) control.Click -= OnClick;
        tcs.SetResult((Control)sender);
    }
}

您可以使用此方法 await 从四个按钮中的任何一个单击,并 return Task<RoundPlay> 具有适当的值,具体取决于单击的按钮:

private async Task<RoundPlay> GetPlayChoiceAsync()
{
    var clickedButton = await OnClickAnyAsync(btnHit, btnStand, btnDoubled, btnSplit);
    if (clickedButton == btnHit) return RoundPlay.hit;
    if (clickedButton == btnStand) return RoundPlay.stand;
    if (clickedButton == btnDoubled) return RoundPlay.doubled;
    if (clickedButton == btnSplit) return RoundPlay.split;
    throw new NotImplementedException();
}

您终于可以像这样使用 GetPlayChoiceAsync 方法了:

// Enabling the buttons so that I can click on one of them
// Wait the player to make a choice, without blocking the UI
RoundPlay playchoice = await GetPlayChoiceAsync();
// Do something with the playchoice