Ответ 1
Вы пробуете Environment.Exit(0);
Он убивает процесс с заданным кодом выхода. Код выхода 0 указывает, что приложение успешно завершено. Это может быть более "грубо" или "не сделано", но, возможно, это то, что вы ищете.
Я только начал новый С#/приложение WPF и использую NotifyIcon из WPF Contrib проект. Я могу запустить программу, добавить элемент меню "Выход" в 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() в другой метод и вызову вместо этого, добавив слой косвенности, кнопка все еще работает, а значок не будет.
Решение найдено?
Только что нашел эту ветку, решение которой здесь работает. Я не совсем понимаю, что происходит, поэтому, если кто-то хочет объяснить, я буду признателен.
Вы пробуете Environment.Exit(0);
Он убивает процесс с заданным кодом выхода. Код выхода 0 указывает, что приложение успешно завершено. Это может быть более "грубо" или "не сделано", но, возможно, это то, что вы ищете.
Я обнаружил, что если я создаю потоки, не настроенные на "фон", основное окно /etc будет закрыто, но потоки будут продолжать выполнять.
Другими словами, только потоки фона закрываются, когда заканчивается основной поток. Регулярные потоки, также называемые Thread.IsBackground = false, будут продолжать работать.
Попробуйте использовать thread.IsBackground = true;
P.S. Я предположил, что вы где-то использовали темы.
У меня была такая же проблема в моем приложении. В моем стартовом модуле (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);
}
}
Это происходит непосредственно в процессе, вызывающем зависание. Нет необходимости перебирать несколько процессов.
Woooow! вам не нужно это делать! просто просто переопределите метод 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);
. он выдает одно и то же исключение.
Он может жить в процессах. Вот пример того, как я проверяю/убиваю процесс
const string str = "MRS_Admin";
foreach (Process process in Process.GetProcesses())
{
if (process.ProcessName.StartsWith(str))
{
Console.WriteLine(@"Killing process " + str);
process.Kill();
}
}
Убедитесь, что вы не создаете никаких объектов 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, который принимает 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();
Итак, когда viewModel
был DogModel
, я создал объекты TWO DogWindow
, поэтому Application.Windows.Count
было 3, когда я ожидал, что оно равно 2. Поскольку Application.Shutdown
ожидал закрытия всех окон, он так и не получил активирован - хотя я даже не открыл окно!
Я всегда предполагал, что для активации окна требуется Show()
, но это было неправильное предположение - поэтому мое приложение никогда не выходило.
Я думаю, что ответ автора самый лучший здесь, но на самом деле его не вызывали. Application.Shutdown()
, похоже, требуется выполнить в потоке диспетчера для работы. Попробуйте, если вы столкнулись с проблемой:
Application.Current.Dispatcher.Invoke(Application.Current.Shutdown);