我有一个窗口,里面有一个按钮。
代码隐藏是
private void Button_Click(object sender, RoutedEventArgs e)
{
Trace.TraceInformation("Button ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
Thread w = new Thread((ThreadStart) Worker);
w.SetApartmentState(ApartmentState.STA); // removing/adding this doesn't make effect
w.Start();
MessageBox.Show("Direct");
}
void Worker()
{
Trace.TraceInformation("Worker ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
this.Dispatcher.Invoke((Action)delegate
{
Trace.TraceInformation("Invoked ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
MessageBox.Show("Invoked");
});
}
点击该按钮会生成 2 消息框。
同时,trace为 Button ThreadId 和 Invoked ThreadId 显示相同的数字。
答案 0 :(得分:2)
Dispatcher始终在GUI线程上执行工作。这就是你的ThreadId匹配的原因。你问GUI线程 - “你的ThreadId是什么?”然后通过Dispatcher执行一些工作,Dispatcher再次进入GUI线程。
答案 1 :(得分:1)
散步后,我明白了发生了什么。
这是我的解释想法代码有什么问题(或问题发布的原因)。
Button_Click
在Dispatcher
主题中执行。正如我所知,Dispatcher
线程是一个窗口及其子窗口的单个线程。
即使Button_Click
花费的时间超过一秒(足够长),并且用户设法再次点击该按钮(或以某种方式与UI交互),下一个Button_Click
(或其他适当的处理程序)不会立即执行,而是放在调度队列中。
Dispatcher.Invoke
在UI线程中执行委托。我想,Invoke
会向委托GetMessage()
循环发送一条消息并阻塞调用线程,直到消息完成。
我希望代表只有在退出 Button_Click
后才能开始执行。
MessageBox.Show()
是一个阻止通话。在用户单击“确定”之前,不会执行下一个语句。
实际发生的事情是Dispatcher实际上区分了不同的窗口,并且知道Button_Click
已经调用了一个模态对话框,因此与窗口的任何交互都应该发出一声嘟嘟声,并且消息框应该闪烁。
但继续调度消息。毕竟,这就是为什么所有用户点击都被翻译成Button.Click消息并且消息框被关闭。
这就是在 Button_Click
退出之前执行被调用的委托的原因。
被调用的代理分为 Button_Click
。
P.S。正如您在代码中看到的那样,代理人也会调用MessageBox.Show()
。这会导致新的消息框与前一个消息框模态。我注意到在“调用”之前我无法在“直接”msgBox上单击“确定”。
答案 2 :(得分:0)
我是WPF Dispatcher的新手,所以如果我完全错了,请向我投票,但看起来你对 this.Dispatcher 的调用实际上是你的Window(UI线程)Dispatcher。因此,任何代码都将由UI线程执行,而不是您的应用程序实例化线程。
[编辑]
以下是我通过运行上述代码
收到的控制台输出DispatcherQuestion.vshost.exe Information: 0 : Button ThreadId: 9 // UI Thread
DispatcherQuestion.vshost.exe Information: 0 : Worker ThreadId: 11 // Thread w
DispatcherQuestion.vshost.exe Information: 0 : Invoked ThreadId: 9 // UI Thread
ThreadID 9是用户界面线程。您的Button和您的Invoke调用都是由UI线程按设计执行的。
我在MSDN上发现了this article today,它确实澄清了WPF线程/调度程序模型的内容。