gpt4 book ai didi

wpf - 对 Dispatcher.BeginInvoke() 的行为感到困惑

转载 作者:行者123 更新时间:2023-12-04 02:50:56 26 4
gpt4 key购买 nike

有人可以对我遇到的问题有所了解吗?

我正在做一个 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();
}

感谢您的时间!

最佳答案

因此,如果我正确理解您的问题,您是说这段代码完全按照您想要的方式工作,但您只是想了解它是如何(以及为什么)工作的?

这是它的工作原理。首先,您的线程运行此代码:

Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));

这将您的操作排在主(UI)线程的调度程序队列中,然后立即返回:您的工作线程继续运行。

当应用程序第一次启动时(通常通过编译器生成的代码初始化你的 App.xaml 对象,虽然你也可以通过调用 Application.Run 显式地完成它),它启动了它的消息循环,它是这样的(伪代码,非常非常简化):
public class Application {
public void Run() {
while (!Exited && action = Dispatcher.DequeueAction())
action();
}
}

因此,在您将操作排队后不久的某个时刻,UI 线程将开始将您的操作从队列中拉出并运行它,此时您的操作会创建一个窗口并以模态方式显示它。

模态窗口现在开始它自己的消息循环,它是这样的(同样,非常简化):
public class Window {
public bool? ShowDialog() {
DisableOtherWindowsAndShow();
while (!IsClosed && action = Dispatcher.DequeueAction())
action();
EnableOtherWindowsAndHide();
return DialogResult;
}
}

稍后,您的工作线程运行以下代码:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window.Close();
}));

同样,您的操作将排入 UI 线程的调度程序队列,然后 BeginInvoke 调用立即返回,您的工作线程继续运行。

因此,UI 线程的消息循环迟早会出列并执行您的操作,这会告诉窗口关闭。这与用户单击标题栏的“X”按钮的效果基本相同,即使您在模态对话框中,这当然也完全可以。这会导致 ShowDialog 的消息循环终止(因为窗口现在已关闭),此时对话框被隐藏,其他窗口被重新启用,ShowDialog 返回,您的原始 (ShowDialog) 操作已完成,因此返回,并且控制落下回到 Application.Run 中的原始消息循环。

请注意,每个线程有一个调度程序队列,而不是每个消息循环一个。因此,您的“关闭”操作进入与“显示对话框”操作相同的队列。这是现在执行消息循环轮询的另一段代码(ShowDialog 中的代码而不是 Application.Run 中的代码),但循环的基础是相同的。

关于wpf - 对 Dispatcher.BeginInvoke() 的行为感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5867703/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com