C# Application.Current.Shutdown()与Application.Current.Dispatcher.BeginInvokeShutdown()的比较

C# Application.Current.Shutdown()与Application.Current.Dispatcher.BeginInvokeShutdown()的比较,c#,wpf,multithreading,shutdown,dispatcher,C#,Wpf,Multithreading,Shutdown,Dispatcher,首先介绍一下背景:我有一个WPF应用程序,它是一个遗留Win32应用程序的GUI前端。旧版应用程序作为DLL在单独的线程中运行。用户在UI中选择的命令将在该“旧线程”上调用 如果“遗留线程”完成,GUI前端将无法再做任何有用的事情,因此我需要关闭WPF应用程序。因此,在线程方法的末尾,我调用Application.Current.Shutdown() 由于我不在主线程上,因此需要调用此命令。但是,随后我注意到,Dispatcher还具有BeginInvokeShutdown()来关闭Dispat

首先介绍一下背景:我有一个WPF应用程序,它是一个遗留Win32应用程序的GUI前端。旧版应用程序作为DLL在单独的线程中运行。用户在UI中选择的命令将在该“旧线程”上调用

如果“遗留线程”完成,GUI前端将无法再做任何有用的事情,因此我需要关闭WPF应用程序。因此,在线程方法的末尾,我调用
Application.Current.Shutdown()

由于我不在主线程上,因此需要调用此命令。但是,随后我注意到,Dispatcher还具有
BeginInvokeShutdown()
来关闭Dispatcher。所以我的问题是:调用

Application.Current.Shutdown();
和呼唤

Application.Current.Dispatcher.BeginInvokeShutdown();


这似乎只是术语上的冲突
BeginInvokeShutdown
关闭该调度器,理论上,您的应用程序可以在之后继续运行(尽管没有调度器,它将非常有限)<代码>关闭但实际上退出了应用程序,这正是您所需要的。

我做了更多的测试,现在我想我知道了区别:

1) 如MSDN页面中所述,
BeginInvokeShutdown
,除了关闭调度程序外,还清除/中止其队列<代码>关机首先处理调度程序队列中的所有项目

一旦关闭过程开始,队列中所有挂起的工作项都将中止

2) 在应用程序中,我可以处理事件。此事件在我调用Shutdown时触发,但在我调用BeginInvokeShutdown时未触发!这同样适用于和

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

下面是我的测试代码。在应用程序启动时注释一个或另一个方法调用:

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");
    }
}

顺便说一句,Daniel—我们的应用程序也是以同样的方式构建的—WPF前端是一个单独运行的Win32 COM(Delphi)应用程序。讨论和比较我们的方法会很有趣


但我偶然发现您的问题的原因是,我们的应用程序曾经调用Dispatcher.BeginInvokeShutdown,它工作正常,只有少数情况下没有正确终止。当我最终在一台机器上得到了这一点是可以复制的,切换到Application.Current.Shutdown()解决了这个问题。我仍然不明白问题出在哪里。

这正是文档中没有回答的问题:关闭应用程序的dispatcher是否也会关闭应用程序?我为此构建了一个简单的WPF测试应用程序。为了模拟您的代码,我做了:
threadt=newthread(newthreadstart(delegate(){Thread.Sleep(50000);}));t、 Start();Application.Current.Dispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Normal)。Dispatcher shutdown杀死了它的所有者线程并关闭了窗口,但没有杀死后台线程。两个小区别:1)我在第二个线程中调用shutdown(尽管通过测试我可以看到它没有任何区别)。2) 我将第二个线程设置为背景线程(IsBackground=true)。这样,如果主线程退出,它也会被杀死。我猜这是因为调用Dispatcher.BeginInvokeShutdown()会中止/清除任何挂起的消息。在我的例子中,我还对Window.Closing/Closed cases和Application.Exit(关闭Win32部件)进行了大量清理。