Application.Current.Shutdown()无法终止我的应用程序。

29

我刚刚开始使用 C#/WPF 应用程序,从 WPF Contrib 项目 中使用 NotifyIcon。我可以启动程序,将 "Exit" MenuItem 添加到 NotifyIcon 的 ContextMenu,并将该项链接到一个简单运行 Application.Current.Shutdown() 方法的方法中。

这会关闭主窗口和 NotifyIcon,但仍有某些东西在运行 - 在 VS 中运行时,它不会离开调试模式。仍在运行什么?或者我如何检查?

编辑

我刚刚尝试添加一个按钮来调用 Application.Current.Shutdown(),并且它能够正常退出。只有从 NotifyIcon 调用时才会出现问题。为什么会这样呢?

澄清一下,我有以下 XAML:

<Window x:Class="VirtualBoxManager.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:av="http://schemas.codeplex.com/wpfcontrib/xaml/presentation"
    Title="VirtualBox Manager" Height="350" Width="525"
    ShowInTaskbar="False" WindowStyle="None">
<Grid>
    <av:NotifyIcon Icon="/icon/path"
                   Text="Virtual Machine Manager"
                   Name="notifyIcon">
        <FrameworkElement.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Exit" Click="MenuItemExit_Click" />
            </ContextMenu>
        </FrameworkElement.ContextMenu>
    </av:NotifyIcon>
    <Button Content="Button" Click="button1_Click" />
</Grid>

button1_Click和MenuItemExit_Click是相同的,但前者能够成功退出应用程序,而后者则不能。

进一步尝试:即使我将Application.Current.Shutdown()移到另一个方法中并调用该方法,增加了一层间接性,按钮仍然有效,而图标则不起作用。

找到解决方案?

刚刚在这个线程中发现了解决方法,在这里可以工作。我不完全理解正在发生的事情,因此如果有人愿意解释,我会非常感激。


如果有一种简便的方法可以“注释掉”应用程序中的NotifyIcon部分,你可以试着这样做,看看是否能够让进程退出。 - Software.Developer
8个回答

30

您可以尝试使用Environment.Exit(0);。它可以以给定的退出代码来终止该进程。退出代码0表示应用程序成功终止。这可能更加'粗鲁'或'不合适',但也许这正是您要寻找的。


2
这确实会强制关闭应用程序,但在执行此操作之前,整个应用程序会冻结一秒钟。 - tsvallender

11

我认为作者的答案是最好的,但实际上还没有被点出来。 Application.Shutdown() 似乎需要在调度程序线程上执行才能正常工作。如果遇到问题,请尝试以下方法:

Application.Current.Dispatcher.Invoke(Application.Current.Shutdown);

11

我发现如果创建的线程不设置为“后台”,主窗口等会关闭,但是线程会继续运行。

换句话说,只有后台线程在主线程结束时才会自动关闭。常规线程,即 Thread.IsBackground = false,将使进程继续运行。

尝试使用 thread.IsBackground = true;

注:我假设您在某个地方使用了线程。


你可能正在使用第三方库,这些库“隐式”地使用前台线程... - Erwin Mayer
我也遇到了同样的情况。谢谢 :) - Redplane
太棒了。救了我。 - Erçin Dedeoğlu

5

我在我的应用程序中也遇到了同样的问题。在我的启动模块(Startup.cs)中,我发现以下方法对我有效:

Process.GetCurrentProcess().Kill();

以下是代码内容:
class StartUp
{
    [STAThread]
    public static void Main()
    {

    try
    {
        Process[] processes = new Process[6];
        App app = new App();
        app.InitializeComponent();
        app.Run();
        Process.GetCurrentProcess().Kill(); //Must add this line after app.Run!!!
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
    }
    }

这直接指向导致卡顿的进程,无需迭代多个进程。


3
真的吗?你认为解决问题的方法就是让应用程序自行终止进程... 这个想法很糟糕! - Ade Miller
因为当用户按下关闭按钮杀死进程时,您不知道应用程序的状态。例如,如果您的应用程序正在写入文件,会发生什么? - Ade Miller
无论如何,拥有一个崩溃安全的设计是个好主意。虽然不符合直觉,但更加健壮。 - Erwin Mayer
可以说,将此作为备份解决方案可能更好。调用Application.Current.Shutdown();,然后在一定时间后,如果进程仍在运行,则使用Process.Kill()终止它。如果您希望确保长时间运行的进程在退出时完成,可以添加使用Process.WaitForExit和预定义的最大时间限制。 - user3265613

4

您不需要这样做!只需在主窗口中简单地重写OnClosing方法即可,如下所示:

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                // If you try to dispose it from ViewModel, you might get a CrossThreadException.
                notifyIcon.Dispatcher.Invoke(new Action(delegate
                {
                    notifyIcon.Dispose();
                }));
            }
            catch { }
            base.OnClosing(e);
        }

然后在你的主应用程序代码的任何地方,无论你是在View还是ViewModel或其他任何地方,都可以像这样调用它:

Application.Current.MainWindow.Close();

我遇到了同样的问题,但我是这样修复它的。
更新:你不应该使用 Environment.Exit(0); 方法,它会抛出相同的异常。

Application.Current.MainWindow.Close() 具有额外的优势,它不像 Application.Current.Shutdown() 那样忽略 CancelEventArgs.Cancel 属性。 - kmote

2
请务必确保您不会创建任何未调用Show()方法的Window对象。
由于某些疯狂的原因,WPF在创建时添加窗口到Application.Windows,而不是在首次调用Show()时添加。如果您将Application.Current.Shutdown设置为ShutdownMode.OnLastWindowClose,则这些从未显示的窗口将阻止应用程序关闭。
假设您像这样打开主窗口的子窗口:
Console.WriteLine("Window count : " + Application.Windows.Count);
var window = new OrderDetailsWindow();
Console.WriteLine("Window count : " + Application.Windows.Count);
window.Show();

在调用 Show() 之前,您会发现 Applications.Windows 现在显示为 2。只有当 Windows.Count 为零时,应用程序才会关闭。

我的情况:

我有一个WindowFactory,它接受一个viewmodel并为传入的模型创建一个窗口。

不知怎么地,在这些年里,我的复制和粘贴产生了这个:

 if (viewModel is DogModel)
 {
     window = new DogWindow();
 }
 else if (viewModel is CatViewModel) 
 {
      window = new CatWindow();
 }
 if (viewModel is DogModel)          
 {
     window = new DogWindow();    
 }

 window.DataContext = viewModel;
 window.Show();

所以当viewModelDogModel时,我最终创建了两个DogWindow对象,因此Application.Windows.Count为3,而我期望它为2。由于Application.Shutdown在等待所有窗口关闭,因此它从未被激活 - 即使我从未打开过该窗口!我一直认为需要Show()来激活窗口,但这是错误的假设 - 所以我的应用程序从未退出。

0

可能是存在于进程中。这里是我检查/杀死进程的示例

       const string str = "MRS_Admin";
        foreach (Process process in Process.GetProcesses())
        {
            if (process.ProcessName.StartsWith(str))
            {
                Console.WriteLine(@"Killing process " + str);
                process.Kill();
            }
        }

0

这对我来说解决了问题。 我想从一个类内部终止应用程序
Application.Current.Dispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Send);


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