问题描述
有人可以阐明我遇到的一个问题吗?
Could someone shed some light on an issue I'm having?
我正在从事wpf项目。情况如下:
I'm working on a wpf project. The scenario is as below:
我需要在主UI线程上弹出一个窗口(模型窗口),然后将其关闭。这些工作从另一个UI线程开始(以阻止用户单击主UI窗口。),然后关闭此窗口。主要代码如下所示。
I need to pop up a window(model window) on main UI thread and then close it. These works are started from another UI thread (to deter user from clicking on the main UI window.) then I close this window. The main code are displayed below. And it works.
据我所知,在 ShowDialog()
返回之前,close方法不会被执行(至少在UI线程上是这种情况,我的意思是没有调度程序的代码),有人有使用多线程的经验吗?
As far as I know the close method would not get excuted before ShowDialog()
returns (at least this is the case on UI thread, I mean code without dispatcher), does anyone have experience with multithread?
Window window;
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
//create a window and let user work from this thread
//code is omitted.
//create another window on main UI thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
//do some work here
Thread.Sleep(1000);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
//Thread.Sleep(1000);
window.Close();
}));
});
thread.Start();
}
谢谢您的时间!
推荐答案
因此,如果我正确理解了您的问题,则表示您的代码完全按照您想要的方式工作,但是您只是想了解如何(以及为什么)起作用?
So if I understand your question correctly, you're saying that this code works exactly the way you want, but you're just trying to understand how (and why) it works?
这是它的工作原理。首先,您的线程运行以下代码:
Here's how it works. First, your thread runs this code:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
这将使您对主(UI)线程的调度程序队列进行操作,然后立即返回:您的工作人员线程继续运行。
That queues your action on the main (UI) thread's dispatcher queue, and then returns immediately: your worker thread continues running.
应用程序首次启动时(通常通过编译器生成的代码来初始化App.xaml对象,尽管您也可以通过调用来显式地执行该操作Application.Run),它开始了它的消息循环,如下所示(伪代码,非常简化):
When the Application first started up (typically via the compiler-generated code that initializes your App.xaml object, though you can also do it explicitly by calling Application.Run), it started its message loop, which goes something like this (pseudocode, very very simplified):
public class Application {
public void Run() {
while (!Exited && action = Dispatcher.DequeueAction())
action();
}
}
因此,在将操作排入队列后不久, UI线程将绕过您的操作并将其从队列中拉出并运行它,这时您的操作将创建一个窗口并以模态显示它。
So at some point shortly after you queue the action, the UI thread will get around to pulling your action off the queue and running it, at which point your action creates a window and shows it modally.
模态窗口现在开始它自己的消息循环,类似这样(再次非常简化):
The modal window now starts its own message loop, which goes something like this (again, very simplified):
public class Window {
public bool? ShowDialog() {
DisableOtherWindowsAndShow();
while (!IsClosed && action = Dispatcher.DequeueAction())
action();
EnableOtherWindowsAndHide();
return DialogResult;
}
}
稍后,您的工作线程将运行以下代码:
Later, your worker thread runs this code:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window.Close();
}));
您的操作再次排队到UI线程的调度程序队列中,然后BeginInvoke调用立即返回并您的工作线程将继续运行。
Again, your action is queued to the UI thread's dispatcher queue, and then the BeginInvoke call returns immediately and your worker thread continues running.
迟早,UI线程的消息循环将绕出队列并执行您的操作,从而告诉窗口关闭。这与用户单击标题栏的 X按钮具有基本相同的效果,即使您位于模式对话框中,也可以完全做到这一点。这将导致ShowDialog的消息循环终止(因为该窗口现在已关闭),此时该对话框被隐藏,其他窗口被重新启用,ShowDialog返回,原始(ShowDialog)操作已完成,因此返回,并且控件落下返回到Application.Run中的原始消息循环。
So sooner or later, the UI thread's message loop will get around to dequeuing and executing your action, which tells the window to close. This has essentially the same effect as the user clicking the title bar's "X" button, which of course is perfectly OK to do even when you're inside a modal dialog. This causes ShowDialog's message loop to terminate (because the window is now closed), at which point the dialog is hidden and the other windows are re-enabled, ShowDialog returns, your original (ShowDialog) action is complete and so returns, and control falls back to the original message loop in Application.Run.
请注意,每个线程有一个调度程序队列,不是每个消息循环一个。因此,您的关闭操作与显示对话框操作进入同一队列。现在,执行消息循环轮询是另一段代码(ShowDialog内部的代码而不是Application.Run内部的代码),但是循环的基本原理是相同的。
Note that there's one dispatcher queue per thread, not one per message loop. So your "close" action goes into the same queue that your "show dialog" action did. It's a different piece of code doing the message-loop polling now (the one inside ShowDialog instead of the one inside Application.Run), but the basics of the loop are the same.
这篇关于与Dispatcher.BeginInvoke()的行为混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!