xia*_*jie 10 wpf dispatcher begininvoke
有人可以解决我遇到的问题吗?
我正在研究一个wpf项目.方案如下:
我需要在主UI线程上弹出一个窗口(模型窗口),然后关闭它.这些工作是从另一个UI线程开始的(阻止用户点击主UI窗口.)然后我关闭这个窗口.主要代码如下所示.它有效.
据我所知,close方法在ShowDialog()
返回之前不会被执行(至少在UI线程上是这种情况,我的意思是没有调度程序的代码),有没有人有多线程的经验?
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();
}
Run Code Online (Sandbox Code Playgroud)
感谢您的时间!
Joe*_*ite 19
所以,如果我正确地理解你的问题,你说,这个代码的工作正是你想要的方式,但你只是想了解如何(以及为什么它)的作品?
这是它的工作原理.首先,您的线程运行此代码:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
Run Code Online (Sandbox Code Playgroud)
将您的操作排入主(UI)线程的调度程序队列,然后立即返回:您的工作线程继续运行.
当应用程序首次启动时(通常通过编译器生成的代码初始化您的App.xaml对象,虽然您也可以通过调用Application.Run显式执行),但它启动了它的消息循环,类似于这样(伪代码,非常非常简化):
public class Application {
public void Run() {
while (!Exited && action = Dispatcher.DequeueAction())
action();
}
}
Run Code Online (Sandbox Code Playgroud)
因此,在排队操作后不久的某个时刻,UI线程将绕过将您的操作从队列中拉出并运行它,此时您的操作会创建一个窗口并以模态方式显示它.
模态窗口现在启动它自己的消息循环,这就像这样(再次,非常简化):
public class Window {
public bool? ShowDialog() {
DisableOtherWindowsAndShow();
while (!IsClosed && action = Dispatcher.DequeueAction())
action();
EnableOtherWindowsAndHide();
return DialogResult;
}
}
Run Code Online (Sandbox Code Playgroud)
稍后,您的工作线程运行此代码:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window.Close();
}));
Run Code Online (Sandbox Code Playgroud)
同样,您的操作排队到UI线程的调度程序队列,然后BeginInvoke调用立即返回,您的工作线程继续运行.
因此,UI线程的消息循环迟早会出现并执行您的操作,这会告诉窗口关闭.这与用户单击标题栏的"X"按钮的效果基本相同,即使您在模态对话框中,这当然也可以完成.这会导致ShowDialog的消息循环终止(因为窗口现在已关闭),此时对话框被隐藏,其他窗口重新启用,ShowDialog返回,原始(ShowDialog)操作完成,因此返回,控制落下回到Application.Run中的原始消息循环.
请注意,每个线程有一个调度程序队列,而不是每个消息循环一个.因此,您的"关闭"操作会进入与"显示对话框"操作相同的队列.这是一个不同的代码片段现在正在进行消息循环轮询(ShowDialog中的一个而不是Application.Run中的一个),但循环的基础是相同的.