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));
然后它没有任何冻结或问题。 但为什么呢?
答案 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();
}
}