为什么在关键事件上使用异步等待时出现不可预测的结果

时间:2019-05-04 09:35:57

标签: winforms async-await

我不明白为什么在窗体中使用keywait的async等待在winForm应用程序中的按键事件上得到奇怪的结果。这是我的问题的非常简单的演示。 完整的应用程序:

using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }
       int counter = 0;
       private async void Form1_KeyDown(object sender, KeyEventArgs e)
       {
           await HandleKeypress();
       }
       private async Task HandleKeypress()
       {
           switch (counter)
          {
            case 0:
                label1.BackColor = Color.Red;
                label2.BackColor = Color.White;
                label3.BackColor = Color.White;
                break;
            case 1:
                label1.BackColor = Color.White;
                label2.BackColor = Color.Red;
                label3.BackColor = Color.White;
                break;
            case 2:
                label1.BackColor = Color.White;
                label2.BackColor = Color.White;
                label3.BackColor = Color.Red;
                label3.Refresh();
                await Task.Delay(5000);

                break;
        }
        counter++;
        if (counter == 3)
        {
            counter = 0;
        }
    }
}

}

窗体KeyPreview处于打开状态,窗体上的KeyDown事件 触发异步方法。当计数器达到3时,计数器从0递增到3,计数器重置为0。根据计数器值0,1,2,共有三个标签,相应的标签背景设置为红色,另外两个标签设置为白色。计数器== 2时有5秒的延迟。如果计数器== 2时我一直按Enter键,我希望标签3变为红色,而其他两个标签重置为白色。然后在5秒钟后,我希望label1恢复为红色,并且序列继续。这不是发生的情况,并且序列变得有些混乱。为什么会发生这种情况。您必须按住一个键。

2 个答案:

答案 0 :(得分:0)

那是因为当您在延迟期间按键时,计数器仍为2,因为它在等待延迟完成以进行计数器++。也许如果您移动计数器++,您会得到想要的结果

    int counter = 0;
           private async void Form1_KeyDown(object sender, KeyEventArgs e)
           {
               HandleKeypress();
           }
           private void HandleKeypress()
           {

               switch (counter)
              {
                case 0:
                    label1.BackColor = Color.Red;
                    label2.BackColor = Color.White;
                    label3.BackColor = Color.White;
                    counter++;
                    break;
                case 1:
                    label1.BackColor = Color.White;
                    label2.BackColor = Color.Red;
                    label3.BackColor = Color.White;
                    counter++;
                    break;
                case 2:
                    label1.BackColor = Color.White;
                    label2.BackColor = Color.White;
                    label3.BackColor = Color.Red;
                    label3.Refresh();
                   MyWait();


                    break;
            }

            if (counter == 2)
            {
                counter = 0;
            }
        }

private async Task MyWait()
{
 await Task.Delay(5000);
 counter++;
}

答案 1 :(得分:0)

如果您可以在延迟之前设置bool(cancelAction)取消按键,则可以完成所需的操作。

    int counter = 0;
    bool cancelAction = false;
    private async void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        await HandleKeypress();
    }
    private async Task HandleKeypress()
    {
        if (cancelAction)
        {
            return;
        }

        switch (counter)
        {

            case 0:
                label1.BackColor = Color.Red;
                label2.BackColor = Color.White;
                label3.BackColor = Color.White;
                break;
            case 1:
                label1.BackColor = Color.White;
                label2.BackColor = Color.Red;
                label3.BackColor = Color.White;
                break;
            case 2:
                label1.BackColor = Color.White;
                label2.BackColor = Color.White;
                label3.BackColor = Color.Red;
                label3.Refresh();
                cancelAction = true;
                await Task.Delay(5000);
                cancelAction = false;

                break;
        }
        counter++;
        if (counter == 3)
        {
            counter = 0;
        }
    }