如果没有MethodInvoker,Control.BeginInvoke()无效 - 但为什么?

时间:2014-04-22 13:18:46

标签: c# winforms delegates freeze begininvoke

Ich有一个WinForms程序,它有1个Button和1个Textbox。如果我单击按钮,则程序从1到100000计数,并在每个步骤中显示文本框中当前时间(以毫秒为单位)。 countloop正在单独运行。

                public partial class Form1 : Form {

                   public delegate void myDelegate();
                   public myDelegate mydelegate;

                    public Form1() {
                        InitializeComponent();

                        mydelegate = new myDelegate(b);
                    }

                    private void button1_Click(object sender, EventArgs e) {
                        button2.Focus();

                        Thread t = new Thread(a);
                        t.Start();
                    }

                    private void Form1_KeyDown(object sender, KeyEventArgs e) {
                        Console.WriteLine(e.KeyCode);
                    }

                    public void a() {
                        for (int i = 0; i < 100000; i++) {
                            textBox1.BeginInvoke(mydelegate);



                        }
                    }

                    public void b() {
                        textBox1.Text = GetCurrentMilli().ToString();
                        textBox1.Refresh();
                    }

                    public static double GetCurrentMilli() {
                        DateTime Jan1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                        TimeSpan javaSpan = DateTime.UtcNow - Jan1970;
                        return javaSpan.TotalMilliseconds;
                    }

                }

如果我运行它,程序可以运行,但是gui会冻结直到循环结束。 但为什么? 我打电话给BeginInvoke?!

如果我替换

                textBox1.BeginInvoke(mydelegate);

                      textBox1.Invoke(new MethodInvoker(b));

然后它没有任何冻结或问题。 但为什么呢?

2 个答案:

答案 0 :(得分:2)

当您调用BeginInvoke时,您正在安排UI更新,然后继续执行您的程序,而无需等待UI更新发生。当你这样做几次就没事了,但你遇到的问题是你一次发送了100,000个请求,并且它会花一些时间来完成所有这些请求因为任何新的UI更新都会到达行尾,并且在其他请求完成之前不会执行,因此在那段时间内无法完成任何其他工作。

虽然有办法让你的一般方法保持一致并试图让其他操作切到最前面,但正确的方法是首先避免问题。您无需一次向单个文本框发送100,000个更新。

如果您希望文本框具有时钟的外观,那么它会在其中打勾,那么Timer将是一个很好的工具;您可以处理Tick事件,以每秒,四分之一秒或其他更多“人类时间”间隔更新文本框。

如果想要通过一些长时间运行的操作来更新UI,那么您只需要确保不经常更新进度。例如,每隔几十次循环更新进度,而不是每一次迭代。

答案 1 :(得分:-1)

您可能需要在两者之间调用UpdateLayout,不确定是否需要调用它来防止跨线程异常

public void a() {
    for (int i = 0; i < 100000; i++) {
        textBox1.BeginInvoke(mydelegate);
        textBox1.UpdateLayout();
    }
}