Visual Studio Application.Current.Shutdown()不会终止我的应用程序

lqfhib0f  于 2023-04-07  发布在  其他
关注(0)|答案(8)|浏览(195)

我刚刚启动了一个新的C#/WPF应用程序,并且正在使用WPF Contrib project中的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()移到另一个方法中并调用它,添加一层间接寻址,按钮仍然可以工作,而图标不能。

找到解决方案?

刚刚找到this thread,谁的解决方案在这里工作。我不完全理解发生了什么,所以如果有人愿意解释我会很感激。

bnlyeluc

bnlyeluc1#

你可以试试Environment.Exit(0);它用给定的退出代码杀死进程。退出代码0表示应用程序成功终止。它可能更“粗鲁”或“未完成”,但也许这就是你要找的。

nnt7mjpx

nnt7mjpx2#

我发现如果我创建的线程没有设置为“后台”,主窗口/etc将关闭,但线程将保持运行。
换句话说,只有后台线程在主线程结束时才会关闭自己。常规线程,也就是Thread.IsBackground = false,将保持进程运行。
Thread.IsBackground = true;
P.S.我假设你在某个地方使用了线程。

muk1a3rh

muk1a3rh3#

我认为作者的答案是这里最好的一个,但还没有真正被调用。Application.Shutdown()似乎需要在调度器线程上执行才能工作。如果你遇到这个问题,请尝试以下操作:

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

muk1a3rh4#

我在我的应用程序中遇到了同样的问题。在我的启动模块(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);
    }
    }

这将直接指向导致挂起的进程。不需要遍历多个进程。

5kgi1eie

5kgi1eie5#

你不需要这样做!只需在主窗口中覆盖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);方法,它会抛出同样的异常。

kyks70gy

kyks70gy6#

绝对确保您没有创建任何从未使用Show()的Window对象

由于一些疯狂的原因,WPF在CREATION上将窗口添加到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()之前,你会看到应用程序。Windows现在显示2。应用程序只会在Windows计数为零时关闭。

  • 我的情况:*

我有一个WindowFactory,它接受一个视图模型并为传入的模型创建一个窗口。
不知何故,多年来我的复制和粘贴产生了这个:

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()来激活窗口,但这是一个错误的假设-所以我的应用程序从未退出。

ctrmrzij

ctrmrzij7#

它可能存在于进程中。

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

zfciruhq8#

这对我来说很有用。我想在一个类中杀死应用程序
Application.Current.Dispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Send);

相关问题