[英]Control.BeginInvoke() not working without MethodInvoker - But why?
Ich有一个小的WinForms程序,其中包含1 Button和1 Textbox。 如果我单击按钮,则程序从1计数到100000,并在每一步中以毫秒为单位显示当前时间。 countingloop在单独的线程中运行。
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));
那么它就可以正常工作,没有任何冻结或问题。 但为什么?
当您调用BeginInvoke
您计划进行一次UI更新,然后继续执行程序而不等待该UI更新发生。 当您几次执行此操作时,您就可以了,但是问题是您一次要发送100,000个请求,这将需要UI花费一些时间来处理所有这些请求,并且那时将无法进行其他操作,因为任何新的UI更新都将移至该行的末尾,并且只有在其他请求完成后才能执行。
尽管有一些方法可以使您的一般方法保持不变,并尝试让其他操作切入行列,但正确的方法是首先避免出现问题。 您无需一次向单个文本框发送100,000个更新。
如果您希望文本框具有时钟的外观(在时钟中滴答作响),那么Timer
将是完成此项工作的好工具; 您可以处理“ Tick
事件,以每秒,每刻四分之一秒或其他“人工时间”间隔更新文本框。
如果您的想法是使用一些长期运行的操作来更新UI,那么您只想确保您不会经常更新进度。 例如,循环的每几十次更新进度,而不是每一次更新一次。
您可能需要在两者之间调用UpdateLayout
,不确定是否需要调用它以防止跨线程异常
public void a() {
for (int i = 0; i < 100000; i++) {
textBox1.BeginInvoke(mydelegate);
textBox1.UpdateLayout();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.