在表单中,比较
BeginInvoke (new Action (() => {
MessageBox.Show ());
}));
与
Invoke (new Action (() => {
MessageBox.Show ());
}));
有什么区别,我什么时候应该使用另一个?如何通过MessageBox的消息泵来影响行为?
我做了一些测试,发现两种方法都阻止了用户界面。
唯一的区别是Invoke实际上是立即调用的,而BeginInvoke需要(非常短的)时间直到代码运行。这是可以预期的。
答案 0 :(得分:16)
BeginInvoke
将异步调用委托,立即返回将委托排队等待执行独立于当前线程。
Invoke
将同步调用委托,阻止调用线程直到委托完成。
要查看差异,请尝试以下代码:
BeginInvoke(new Action(()=>Console.WriteLine("BeginInvoke")));
Console.WriteLine("AfterBeginInvokeCalled");
Invoke(new Action(()=>Console.WriteLine("Invoke")));
Console.WriteLine("AfterInvokeCalled");
您应该看到类似于以下内容的输出,其中“BeginInvoke”文本由于其异步执行而延迟:
AfterBeginInvokeCalled
调用
AfterInvokeCalled
BeginInvoke的
关于您观察到的行为,因为它只是调用同步或异步的委托的行为;该方法的内容可能会导致调用线程停止或UI被阻止。在显示消息框的情况下,无论委托是否使用BeginInvoke
延迟,一旦调用委托,UI将被阻止,直到消息框被解除。
答案 1 :(得分:14)
西蒙其实没错。
BeginInvoke
就像向UI线程发送消息并说:“一旦有机会就这样做。”
Invoke
就像是在说:“现在这样做 。我会等。”
澄清:只是因为你告诉 UI线程,“立即行动”,这并不意味着你是UI线程的上帝,并且可以强制它放弃它的一切这样做。基本上,上述陈述中的关键词是“我会等。”
问题是,在您的示例代码中,您发送到UI线程的消息是:call MessageBox.Show
。你猜怎么着?这将阻止UI线程。
如果你想注意BeginInvoke
的异步行为,从一个单独的线程调用它,在你的代码中调用BeginInvoke
之后放一个断点,并注意断点即使在将显示消息框(并且UI已被阻止)。如果您致电Invoke
,则在用户取消消息框之前,代码将不会继续。
答案 2 :(得分:3)
BeginInvoke是异步的...这意味着调用线程不会等待被调用的方法返回。
好吧,对话框总是冻结GUI。但是现在应该清楚开始调用和调用之间的区别:
Invoke等待被调用的方法返回 BeginInvoke没有。
答案 3 :(得分:2)
虽然大部分答案在技术上都是正确的,但他们并没有提出明显的问题。
为什么要首先在Invoke / BeginOnvoke中包装MessageBox()调用?
在Jeff的解释中,在这种情况下使用BeginInvoke或Invoke没有任何好处。
听起来你在多线程情况下在Windows窗体/控件上使用Invoke / BeginInvoke,在委托实例上使用Invoke / BeginInvoke(即异步编程模型)时感到困惑。
这很容易做,因为名称显然是相同的,但是你使用它们的场景和它们的行为是不同的。
本书CLR Via C#很好地解释了两种类型的Invoke / BeginInvoke。
答案 4 :(得分:1)
对于MessageBox.Show,问题大多无关紧要。
唯一的区别在于使用BeginInvoke,调用线程本身不会阻塞,因此它可以继续处理(清理,进一步处理等)。
UI线程显然会阻塞,因为会弹出一个模态窗口,等待用户输入关闭它。