Application.Current.Shutdown () не убивает мое приложение - PullRequest
25 голосов
/ 21 февраля 2011

Я только что запустил новое приложение на C # / WPF и использую NotifyIcon из проекта WPF Contrib . Я могу запустить программу, добавить элемент «Выход» MenuItem в ContextMenu NotifyIcon и связать этот элемент с методом, который просто запускает Application.Current.Shutdown ().

Это закрывает главное окно и NotifyIcon, но что-то продолжает работать - при запуске из VS, оно не выходит из режима отладки. Что еще работает? Или как я могу проверить?

EDIT

Я только что попытался добавить кнопку, которая вызывает 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 () в другой метод и вызову его, добавив слой косвенности, кнопка все равно будет работать, а значок - нет.

Решение найдено?

Только что нашел эту ветку , чье решение здесь работает. Я не совсем понимаю, что происходит, поэтому, если кто-нибудь захочет объяснить, я буду признателен.

Ответы [ 7 ]

18 голосов
/ 21 февраля 2011

Вы можете попробовать Environment.Exit(0); Это убивает процесс с указанным кодом выхода. Код выхода 0 указывает, что приложение успешно завершено. Это может быть более «грубо» или «не сделано», но, возможно, это то, что вы ищете.

8 голосов
/ 22 февраля 2011

Я обнаружил, что если я создаю потоки, для которых не задано значение "background", главное окно / etc будет закрыто, но потоки будут продолжать работать.

Другими словами, только фоновые потоки закрываются, когдаосновная нить заканчивается.Обычные потоки, иначе Thread.IsBackground = false, будут поддерживать процесс в рабочем состоянии.

Попробуйте использовать thread.IsBackground = true;

PS Я предположил, что вы где-то использовали потоки.

4 голосов
/ 27 июня 2011

У меня была такая же проблема в моем приложении. В моем модуле запуска (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 голосов
/ 06 июня 2012

Вам не нужно этого делать!просто переопределите метод OnClosing внутри главного окна следующим образом:

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                // there is a bug (throw CrossThreadException) in notifyIcon when disposing from ViewModel.
                notifyIcon.Dispatcher.Invoke(new Action(delegate
                {
                    notifyIcon.Dispose();
                }));
            }
            catch { }
            base.OnClosing(e);
        }

, а затем повсюду в коде основного приложения, независимо от того, находитесь ли вы в View, ViewModel или где-либо еще, просто вызовите его так:

Application.Current.MainWindow.Close();

У меня была такая же проблема, но я так и исправляю.

Обновление: Не следует использовать метод Environment.Exit(0);.выдает то же исключение.

0 голосов
/ 08 февраля 2016

Я думаю, что авторский ответ здесь самый лучший, но на самом деле не был вызван.Application.Shutdown(), кажется, требует выполнения в потоке диспетчера для работы.Попробуйте это, если столкнетесь с проблемой:

Application.Current.Dispatcher.Invoke(Application.Current.Shutdown);
0 голосов
/ 06 декабря 2014

Убедитесь, что вы не создаете объекты Window, которые вы никогда не показываете ()

По какой-то безумной причине WPF добавляет окна к Application.Windows при CREATION, а не при первом вызове 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, которая берет модель представления и создает окно для переданной модели.

Каким-то образом за эти годы моя копия и склейка дали следующее:

 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();

Поэтому, когда viewModel равнялся DogModel, я заканчивал тем, что создавал ДВУХ DogWindow объектов, поэтому Application.Windows.Count равнялся 3, когда я ожидал, что будет 2. Поскольку Application.Shutdown ждал закрытия всех окон, он никогда не получал активировано - хотя я никогда даже не открывал окно!

Я бы всегда предполагал, что Show() был необходим для активации окна, но это было неверное предположение - поэтому мое приложение никогда не закрывалось.

0 голосов
/ 22 февраля 2011

Это может быть жизнь в процессах. Вот пример того, как я проверяю / убиваю процесс

       const string str = "MRS_Admin";
        foreach (Process process in Process.GetProcesses())
        {
            if (process.ProcessName.StartsWith(str))
            {
                Console.WriteLine(@"Killing process " + str);
                process.Kill();
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...