如何重现Window.ShowDialog()

时间:2015-05-04 21:54:39

标签: c# wpf dispatcher event-loop

简短版本:如何在特定堆栈帧中抽取消息,这样我就可以等待自定义对话框在阻塞时返回,就像Window.ShowDialog()一样。理想情况下避免异步或多线程。

我正在为我的应用程序创建一个自定义通知对话框,它支持一组不同的显示模式。

它可以用作阻塞弹出窗口,与MessageBox.Show完全一样,使用Window.ShowDialog()。它也可以通过使用常规的Show命令充当非阻塞消息框。

但是,我希望有第三种模式,可以使用非阻塞调用显示对话框,但稍后另一个调用将阻塞,直到用户关闭对话框。这样我就可以让用户更早地知道他们何时需要做某事,但是到时候,如果用户还没有解雇它,主应用程序线程就会阻止。

请记住,我没有使用Async。

基本上: NotifyDialog.ShowNonBlocking(“请删除设备,然后单击确定。”); //做东西,等待处理完成。

//处理完成后,我们真的需要摆脱下一件事之前的设备启动。 NotifyDialog.BlockUntilClosed(); //禁用主窗口,在此处启动嵌套消息泵。

我首先错误地认为创建一个新窗口会自动创建一个新线程和Dispatcher队列,所以我尝试使用一个条件。事实证明它并没有创建新的线程。我假设这是因为Window.ShowDialog()在显示新对话框时被阻止,但据我现在所知它只是禁用所有其他窗口,并且劫持消息泵(我假设堆栈看起来像主要的那样) - >消息泵 - >事件,引导我们进入ShowDialog()调用 - >新的,被劫持的消息泵循环。)

无论如何,我想手动重现这种行为,所以在我的NotifyDialog.BlockUntilClosed()调用中,我可以劫持消息泵,禁用我的主窗口,等待窗口关闭。

如果这是不可能的,我将回到在一个新线程上启动窗口的计划,似乎有一些文章在解释。

我想让它易于使用,所以我不想依赖消费者需要使用的封闭事件回调,而我的应用程序现在还没有使用Async,所以我可以& #39;等待结果。

1 个答案:

答案 0 :(得分:0)

好吧,想通了。

调度程序有一个名为PushFrame的方法。这个函数是一个简单的事件循环。这是一个while循环,在传递的DispatcherFrame中的continue标志设置为false之前不会返回,此时它会停止处理事件并返回。

解决方案是将一个成员Dispatcher框架添加到我的类中,并在调用BlockUntilClosed方法时构造它并使用PushFrame调用将其传递给Dispatcher。然后,在对话框的Close事件处理程序中,我将continue标志设置为false。 Dispatcher完成处理close事件后,会检测到continue标志已被清除并返回。

这里有一个相当不错的描述:

DispatcherFrame. Look in-Depth