Application.Current.Shutdown()与Application.Current.Dispatcher.BeginInvokeShutdown()的区别

10

首先,我有一个WPF应用程序,它是一个GUI前端,与遗留的Win32应用程序进行交互。遗留应用程序在单独的线程中作为DLL运行。用户在UI中选择的命令在“遗留线程”上调用。

如果“遗留线程”完成,GUI前端就不能再执行任何有用的操作,因此我需要关闭WPF应用程序。因此,在线程方法结束时,我调用 Application.Current.Shutdown()

由于我不在主线程上,所以需要调用此命令。但是,我注意到Dispatcher也有BeginInvokeShutdown()来关闭dispatcher。那么我的问题是:调用两者之间有什么区别?

Application.Current.Shutdown();

并调用

Application.Current.Dispatcher.BeginInvokeShutdown();
3个回答

10

我进行了更多的测试,现在我认为我知道它们之间的区别:

1) 如MSDN页面所述,BeginInvokeShutdown除了关闭Dispatcher外,还清除/中止其队列。 Shutdown 首先处理Dispatcher队列中的所有项。

一旦关闭过程开始,队列中的所有待处理工作项都将被中止。

2) 在应用程序中,可以处理Application.Exit事件。当我调用Shutdown时,会触发此事件,但是当我调用BeginInvokeShutdown时,不会触发此事件!Window.ClosingWindow.Closed也是如此。

至于相似之处,在两种情况下都会退出主线程。根据其他正在运行的线程,这也会关闭进程:非后台线程在进程退出之前运行到完成。

以下是我的测试代码。请在Application_Startup中注释其中一个方法调用:

public partial class App
{
    private void Application_Exit(object sender, ExitEventArgs e)
    {
        MessageBox.Show("Exiting");
    }

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        var testThread = new Thread(
            () =>
            {
                Thread.Sleep(2000);
                Application.Current.Dispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Send);
                //Application.Current.Dispatcher.BeginInvoke(new Action(() => Application.Current.Shutdown()));
            });
        testThread.Start();
    }
}

public partial class Window1
{
    public Window1()
    {
        this.InitializeComponent();

        Dispatcher.BeginInvoke(new Action(() =>
        {
            Thread.Sleep(1000);
            Console.WriteLine("One");
        }));

        Dispatcher.BeginInvoke(new Action(() =>
        {
            Thread.Sleep(1000);
            Console.WriteLine("Two");
        }));

        Dispatcher.BeginInvoke(new Action(() =>
        {
            Thread.Sleep(1000);
            Console.WriteLine("Three");
        }));

        Dispatcher.BeginInvoke(new Action(() =>
        {
            Thread.Sleep(1000);
            Console.WriteLine("Four");
        }));
    }

    private void Window_Closed(object sender, EventArgs e)
    {
        Console.WriteLine("Closed");
    }

    private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        Console.WriteLine("Closing");
    }
}

1

Shutdown() 的 MSDN 页面
BeginInvokeShutdown() 的 MSDN 页面

看起来这只是术语的冲突。 BeginInvokeShutdown 关闭了那个 dispatcher,你的应用程序理论上可以继续存在(尽管没有 dispatcher,它会非常有限)。然而,Shutdown 实际上退出了你的应用程序,这正是你想要的。


那正是文档中没有回答的问题:关闭应用程序的调度程序是否也会关闭应用程序? - Daniel Rose
我为此构建了一个简单的WPF测试应用程序。为了模拟您的代码,我执行了以下操作:Thread t = new Thread(new ThreadStart(delegate() { Thread.Sleep(50000); })); t.Start(); Application.Current.Dispatcher .BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Normal);。Dispatcher关闭了它的所有者线程并关闭了窗口,但没有终止后台线程。 - JustABill
两个小区别:1)我在第二个线程中调用了shutdown(尽管通过测试,我可以看到它没有任何影响)。2)我将第二个线程设置为后台线程(IsBackground = true)。这样,如果主线程退出,它也会被终止。 - Daniel Rose

0

顺便说一下,丹尼尔 - 我们的应用程序是以相同的方式构建的 - WPF前端到运行独立的Win32 COM(Delphi)应用程序。交流和比较我们的方法会很有趣。

但我为什么会遇到你的问题是因为我们的应用程序曾经调用Dispatcher.BeginInvokeShutdown,它在大多数情况下都可以正常工作,但也有一些情况下无法正确终止。当我最终拿到一个可以重现这个问题的机器时,切换到Application.Current.Shutdown()解决了这个问题。我仍然不明白问题出在哪里。


我猜这是因为调用Dispatcher.BeginInvokeShutdown()会中止/清除任何挂起的消息。在我的情况下,我还在Window.Closing/Closed情况和Application.Exit中进行了一些清理(以关闭Win32部分)。 - Daniel Rose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接