我感到困惑,为什么不能在Count()方法中在我的Dispatcher上使用“BeginInvoke”使此测试计数器应用程序不能同时运行2个(或更多)计数器文本框。
您可以通过将Invoke替换为BeginInvoke来解决此问题。但这并不能解决我的困惑。
这是我正在谈论的示例代码:
public class CounterTextBox : TextBox
{
private int _number;
public void Start()
{
(new Action(Count)).BeginInvoke(null, null);
}
private void Count()
{
while (true)
{
if (_number++ > 10000) _number = 0;
this.Dispatcher.BeginInvoke(new Action(UpdateText), System.Windows.Threading.DispatcherPriority.Background, null);
}
}
private void UpdateText()
{
this.Text = "" + _number;
}
}
最佳答案
当您使用Dispatcher.BeginInvoke
时,它意味着它计划给定的操作在以后的某个时间点在UI线程中执行,然后返回控制权以允许当前线程继续执行。 Invoke
阻止调用者,直到计划的操作完成。
当您使用BeginInvoke
时,由于BeginInvoke
立即返回,因此您的循环将快速运行和 super 。这意味着您要向消息队列添加很多 Action 。您添加它们的速度比实际处理速度快得多。这意味着从安排消息到实际有机会运行之间有一段很长的时间。
您正在运行的实际操作使用字段_number
。但是,在操作处于队列中时,另一个线程很快地修改了_number
。这意味着在您计划操作时,它不会显示_number
的值,而是在紧密循环中继续显示之后的值。
如果改用Dispatcher.Invoke
,则它可以防止循环“超前”并具有多个计划的事件,从而确保其写入的值始终为“当前”值。另外,通过强制循环的每次迭代等待消息运行,它使循环“紧缩”了很多,因此一般来说运行速度不会如此之快。
如果要使用BeginInvoke
,您真正需要做的第一件事就是减慢循环速度。如果您希望它每秒更新一次文本,或者每10ms更新一次,则可以使用Thread.Sleep
等待适当的时间。
接下来,您需要先复制一份_number
,然后再将其传递给Dispatcher
,以便它在您计划时显示值,而不是在执行时显示值:
while (true)
{
if (_number++ > 10000)
_number = 0;
int copy = _number;
this.Dispatcher.BeginInvoke(new Action(() => UpdateText(copy))
, System.Windows.Threading.DispatcherPriority.Background, null);
Thread.Sleep(200);
}
private void UpdateText(int number)
{
this.Text = number.ToString();
}
关于c# - Dispatcher Invoke(…)vs BeginInvoke(…)的困惑,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19009174/