C# Dispatcher Invoke(...) 与 BeginInvoke(...) 混淆
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19009174/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dispatcher Invoke(...) vs BeginInvoke(...) confusion
提问by Jerev
I'm confused why I can't make this test counter application work with 2 (or more) simultaneous running countertextboxes with the use of "BeginInvoke" on my Dispatcher in the Count() method.
我很困惑,为什么我不能在我的 Dispatcher 的 Count() 方法中使用“BeginInvoke”使这个测试计数器应用程序与 2 个(或更多)同时运行的计数器文本框一起工作。
You can solve the issue by replacing the BeginInvoke by an Invoke. But this doesn't solve my confusion.
您可以通过将 BeginInvoke 替换为 Invoke 来解决该问题。但这并不能解决我的困惑。
Here's the sample code I'm talking about:
这是我正在谈论的示例代码:
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;
}
}
采纳答案by Servy
When you use Dispatcher.BeginInvoke
it means that it schedulesthe given action for execution in the UI thread at a later point in time, and then returns control to allow the current thread to continue executing. Invoke
blocks the caller until the scheduled action finishes.
当您使用Dispatcher.BeginInvoke
它时,意味着它会在稍后的时间点安排给定的操作在 UI 线程中执行,然后返回控制权以允许当前线程继续执行。 Invoke
阻止调用者,直到计划的操作完成。
When you use BeginInvoke
your loop is going to run superfast since BeginInvoke
returns right away. This means that you're adding lotand lotsof actions to the message queue. You're adding them muchfaster than they can actually be processed. This means that there's a long time between when you schedule a message and when it actually gets a chance to be run.
当你使用BeginInvoke
你的循环时,它会运行得非常快,因为它会立即BeginInvoke
返回。这意味着你要添加很多和很多的行动,以消息队列。您添加它们的速度比实际处理它们的速度要快得多。这意味着在您安排消息和它真正有机会运行之间有很长的时间。
The actual action that you're running uses the field _number
. But _number
is being modified by the other thread very quicklyand while the action is in the queue. This means that it won't display the value of _number
at the time you scheduled the action, but rather what it is after it has been continuing on in it's very tight loop.
您正在运行的实际操作使用该字段_number
。但是_number
正在被另一个线程非常快地修改并且动作在队列中。这意味着它不会显示_number
您安排操作时的值,而是显示它在非常紧凑的循环中继续执行后的值。
If you use Dispatcher.Invoke
instead then it prevents the loop from "getting ahead of itself" and having multiple scheduled events, which ensures that the value that it's writing is always the "current" value. Additionally, by forcing each iteration of the loop to wait for the message to be run it makes the loop a lot less "tight", so it can't run as quickly in general.
如果您Dispatcher.Invoke
改为使用,则它可以防止循环“超前”并具有多个预定事件,从而确保它写入的值始终是“当前”值。此外,通过强制循环的每次迭代等待消息运行,它会使循环变得不那么“紧”,因此它通常不能运行得那么快。
If you want to use BeginInvoke
the first thing you really need to do is slow down your loop. If you want it to update the text every second, or ever 10ms, or whatever, then you can use Thread.Sleep
to wait the appropriate amount of time.
如果你想使用BeginInvoke
你真正需要做的第一件事就是减慢你的循环。如果您希望它每秒或每 10 毫秒更新一次文本,那么您可以使用Thread.Sleep
等待适当的时间。
Next, you need to take a copy of _number
before passing it to the Dispatcher
so that it displays the value at the time you scheduled it, not at the time it is executed:
接下来,您需要_number
在将其传递给 the 之前获取一个副本,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();
}