简体   繁体   English

Button.DialogResult、Form.ShowDialog 和异步事件处理程序超出预期的执行顺序

[英]Button.DialogResult, Form.ShowDialog and async event handlers out of -expected- order execution

I gonna try to be brief.我会尽量简短。 Two Forms:两个 Forms:

Form1 (button1, textBox1)窗体 1(按钮 1,文本框 1)


public partial class Form1 : Form
{
    private readonly Form2 fr2 = new Form2();

    public Form1()
    {
        InitializeComponent();
        fr2.textBox1 = textBox1;
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        textBox1.Text = string.Empty;
        if (fr2.ShowDialog() == DialogResult.OK)
        textBox1.AppendText("Form1" + Environment.NewLine);
    }
}

Form2 (button1 with button1.DialogResult == DialogResult.OK ) Form2(button1 和button1.DialogResult == DialogResult.OK


public partial class Form2 : Form
{
    public TextBox textBox1;

    public Form2()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        textBox1.AppendText("Form2 A" + Environment.NewLine);
        await Task.Delay(1000);
        textBox1.AppendText("Form2 B" + Environment.NewLine);
        Hide();
    }
}

  • Run
  • Click on Form1.Button1点击 Form1.Button1
  • Click on Form2.Button1单击 Form2.Button1

WHY Textbox.Text ==为什么是 Textbox.Text ==

@"Form2 A
Form1
Form2 B
";

instead of代替

@"Form2 A
Form2 B
Form1
"?

WHY the form "returns" to the caller without even finishing the event handler and finish later?为什么表单“返回”给调用者甚至没有完成事件处理程序并稍后完成?

Is this a documented behaviour or a bug?这是记录在案的行为还是错误?

Update:更新:

Apparently the original winform's form event handing code wasn't updated to account for an async event handler in case button.DialogResult is preset, it's just treated as a "fire and forget" async method call.显然,在 button.DialogResult 是预设的情况下,原始 winform 的表单事件处理代码没有更新以考虑异步事件处理程序,它只是被视为“触发并忘记”异步方法调用。 I have to study some more to see what happens in case an exception is thrown.我必须研究更多,看看如果抛出异常会发生什么。 It seems that is "fired and forgotten" too by the async machinery (no Task to save it for later)?.异步机器似乎也被“解雇并忘记了”(没有Task将其保存以备后用)? It is a very different behaviour from the serial case and it's not documented anywhere.这是与串行案例非常不同的行为,并且在任何地方都没有记录。 Spot on comment about await , Hans Passant!现货评论await ,汉斯帕桑特!

This is expected behaviour, as you wait asynchronously for the Task.Delay task to finish.这是预期的行为,因为您异步等待Task.Delay任务完成。 While that is being done, the method returns to its caller, and this is by design.在此过程中,该方法返回给它的调用者,这是设计使然。 Take this example:举个例子:

private void button1_Click(object sender, EventArgs e)
{
   method();
   textBox1.Text += "C";
}

async void method()
{
   textBox1.Text += "A";
   await Task.Delay(1000);
   textBox1.Text += "B";
}

This is pretty much the same situation, the text of the TextBox will be ACB after pressing button1, as the method method() returns to its caller when await Task.Delay(1000);这几乎是相同的情况,TextBox 的文本将在按下 button1 后为ACB ,因为方法method()await Task.Delay(1000); is called.叫做。

To get the desired output, do it as Hans Passant suggested in the comments: Set the DialogResult property of the button to None , so that the method does not return to the Form1 .要获得所需的 output,请按照 Hans Passant 在评论中的建议进行操作:将按钮的DialogResult属性设置为None ,以便该方法不会返回Form1 Then, whenever you wish to hand control over to Form1 again, simply call this.DialogResult = DialogResult.OK in the method on runtime, which will have the same effect.然后,每当您希望再次将控制权交给Form1时,只需在运行时的方法中调用this.DialogResult = DialogResult.OK即可,效果相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM