Програма WPF не вимикається, закриваючи головне вікно


82

Я звик до програмування WinForms у Visual Studio, але я хотів спробувати WPF.

Я додав ще одне вікно до свого проекту, яке називається Window01. Головне вікно називається MainWindow. Перед public MainWindow()конструктором я оголошую Window01:

Window01 w1;

Зараз я створюю це вікно у:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    w1 = new Window01();            
}

У мене є кнопка , де відображається вікно: w1.ShowDialog();.

«Смішним» тут є той факт, що якщо я запускаю програму (з налагодженням) і виходжу з неї через кілька секунд після (я нічого не роблю в програмі), Visual Studio не припиняє налагодження, ніби додаток є все ще працює.

Якщо я переміщую рядок w1 = new Window01();до методу натискання кнопки, тобто трохи вище ShowDialog(), Visual Studio поводиться належним чином - тобто налагодження припиняється, коли я виходжу з програми.

Чому ця дивна поведінка?

Відповіді:


138

У вашому MainWindow.xaml.cs, спробуйте зробити це:

protected override void OnClosed(EventArgs e)
{
    base.OnClosed(e);

    Application.Current.Shutdown();
}

За цим посиланням ви також можете встановити ShutdownModeв XAML:

http://msdn.microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml"
    ShutdownMode="OnExplicitShutdown"
    >
</Application>

Програми зупиняються, лише коли викликається Shutdownметод Application. Вимкнення може відбуватися неявно або явно, як зазначено у значенні ShutdownModeвластивості.

Якщо встановлено ShutdownModeзначення OnLastWindowClose, Windows Presentation Foundation (WPF) неявно викликає вимкнення, коли закривається останнє вікно програми, навіть якщо будь-яке з встановлених на даний момент вікон встановлено як головне вікно (див. MainWindow).

ShutdownModeЗ OnMainWindowCloseпричин WPF неявно називають Shutdown , коли MainWindow закривається, навіть якщо інші вікна відкриті в даний момент.

Термін служби деяких програм може не залежати від того, коли закрито головне вікно або останнє вікно, або взагалі не залежати від вікон. Для цих сценаріїв потрібно встановити для ShutdownModeвластивості значення OnExplicitShutdown, яке вимагає явного Shutdownвиклику методу для зупинки програми. В іншому випадку програма продовжує працювати у фоновому режимі.

ShutdownMode може бути налаштовано декларативно з XAML або програмно з коду.

Ця властивість доступна лише з потоку, який створив Applicationоб'єкт.


У вашому випадку програма не закривається, оскільки ви, мабуть, використовуєте за замовчуванням OnLastWindowClose:

Якщо встановити ShutdownModeзначення OnLastWindowClose, WPF неявно викликає вимкнення, коли закривається останнє вікно у програмі, навіть якщо будь-яке з встановлених на даний момент вікон встановлено як головне вікно (див. MainWindow).

Оскільки ви відкриваєте нове вікно, а не закриваєте його, вимкнення не викликається.


1
Важливо зазначити, що функція заміни найкраща, якщо ви створили інстанцію будь-яких інших потоків для виконання певних завдань. Зупиніть нитки у функції OnClosed перед тим, як завершити роботу. В іншому випадку потоки залишаються живими, і програма ніколи не виходить із програми.
weezma2004

Я не впевнений, що якщо це гарна ідея закрити програму, лише тому, що MainWindow закрито. Можливо також, що фоновий процес намагається зробити щось на зразок збереження в БД, запису в журнали, кешування речей, відключення пристроїв тощо ... На цьому етапі я знайшов би проблему, яка блокує програму, і закрила її. Завжди організовуйте життєвий цикл своїх програм. Application.Current.Shutdown()вимкне програму відразу, як закінчення процесу на панелі завдань. Це як застрілити когось, перш ніж він скаже своє останнє слово :) .. Я б не рекомендував.
Вурал

35

Я радий, що ви отримали свою відповідь, але заради інших я також відповім на ваше запитання, щоб додати деяку інформацію.


Крок 1

По-перше, якщо ви хочете, щоб ваша програма вийшла при закритті головного вікна, вам потрібно вказати, оскільки це не WinForms, де ця поведінка є за замовчуванням.

(За замовчуванням у WPF - це коли закривається останнє вікно)

У Кодексі

Перейдіть до екземпляра вашого додатка у вашій точці входу (у програмі WPF VS 2012 за замовчуванням вкладено всередині App.xaml, тому заходьте всередину його та перейдіть до App.xaml.cs& створіть конструктор).

У конструкторі вказати , що ваші Application«s ShutdownModeмає бути ShutdownMode. OnLastWindowClose.

    public App()
    {
        ShutdownMode = ShutdownMode.OnLastWindowClose;
    }

У XAML

Перейдіть до App.xamlфайлу , який VS 2012 , створений за замовчуванням (або створити його самостійно) Корінь є Applicationвказати всередині , що ваші Application«s ShutdownModeмає бути ShutdownMode. OnLastWindowClose.

<Application x:Class="WpfApplication27.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         StartupUri="MainWindow.xaml"
         ShutdownMode="OnMainWindowClose">

Якщо це працює, ви закінчили; ти можеш перестати читати.


Крок 2

Якщо вищезазначене не спрацювало (я думаю, ви писали програму WPF з нуля), головне вікно, ймовірно, не відоме програмі як головне вікно. Тож вкажіть це як добре.

У Кодексі

Перейдіть до конструктора програми, як це було зроблено на кроці 1, і вкажіть це Application. MainWindowзначення Вашого Window:

MainWindow = mainWindow;

У XAML

Перейдіть до ApplicationXAML, як це було зроблено на кроці 1, і вкажіть це Application. MainWindowзначення Вашого Window:

MainWindow = "mainWindow";

Альтернатива

Я не думаю , що це найкращий підхід, просто тому , що WPF не хоче , щоб ви це зробити (так він має Application«s ShutdownMode), але ви можете просто використовувати подію / перевизначити метод події (OnEventHappened).

Перейдіть до файлу коду MainWindow і додайте:

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);

        App.Current.Shutdown();
    }

3
Ваша відповідь краще, ніж відповідна, яка позначена.
Seekeer

Зазвичай я роблю це так: встановлюю MainWindowекземпляр головного вікна, встановлюю ShutdownModeзначення ShutdownMode.OnMainWindowClose, MainWindow.Show()зворотний дзвінок до Startupподії App. Це найбільш мінімальне рішення, яке я придумав, яке працює, як очікувалося, принаймні в .NET Core 3 з WPF.
TorbenJ

11

Оскільки за замовчуванням режим вимкнення у програмі WPF - OnLastWindowClose, що означає, що програма зупиняється, коли закривається останнє вікно.

Коли ви створюєте екземпляр нового об'єкта Window, він автоматично додається до списку вікон у програмі. Отже, проблема полягала в тому, що ваш додаток створював два вікна, коли він запускався - MainWindow і ще не показане Window01 - і якби ви лише закрили MainWindow, Window01 продовжував би працювати вашу програму.

Зазвичай ви створюєте віконний об'єкт тим самим методом, який збирається викликати його ShowDialog, і створюватимете новий віконний об'єкт кожного разу, коли відображається діалогове вікно.


2

Я натрапив на це Питання, шукаючи щось інше, і був здивований тим, що не міг побачити жодної із запропонованих відповідей, де згадується про Window.Owner.

    {
       var newWindow = new AdditionalWindow();
       newWindow.Owner = Window.GetWindow(this);

       // then later on show the window with Show() or ShowDialog()
    }

Виклик Window.GetWindow(this)є вельми корисним з точки зору програми MVVM , коли ви далеко вниз по візуальному дереву , не знаючи , де ти був створений екземпляр, він може бути викликаний шляхом подачі будь-якого FrameWorkелементу (наприклад UserContol, Button, Page). Очевидно, якщо у вас є пряме посилання на вікно, використовуйте це або навіть Application.Current.MainWindow.

Це досить потужні відносини, що мають ряд корисних переваг, про які ви, можливо, не усвідомлюєте (припускаючи, що ви спеціально не закодували окремі вікна, щоб уникнути цих відносин).

Якщо ми називаємо ваше головне вікно MainWindowта друге вікно як AdditionalWindowтоді ....

  1. Мінімізація MainWindowволі також мінімізуєAdditionalWindow
  2. Відновлення MainWindowтакож відновитьAdditionalWindow
  3. Закриття MainWindowзакриється AdditionalWindow, але закриття AdditionalWindowне закриєтьсяMainWindow
  4. AdditioanlWindowніколи не "загубиться" під MainWindow, тобто AddditionalWindowзавжди відображається вище MainWindowв z-порядку, якщо раніше ви Show()його відображали (цілком корисно!)

Хоча слід зазначити одне, якщо у вас є такі зв’язки, то Closingподія на AdditionalWindowне викликається, тому вам доведеться перебирати OwnedWindowsколекцію вручну . наприклад, створити спосіб викликати кожне вікно за допомогою нового інтерфейсу або методу базового класу.

    private void MainWindow_OnClosing(object sender, CancelEventArgs e)
    {
        foreach (var window in OwnedWindows)
        {
            var win = window as ICanCancelClosing;  // a new interface you have to create
            e.Cancel |= win.DoYouWantToCancelClosing();
        }        
    }

1

Жодне з перерахованого не працювало для мене, можливо, тому, що наш проект використовує Prism. Тому в кінцевому підсумку використали це в App.XAML.cs

    protected override void OnExit(ExitEventArgs e)
    {
        base.OnExit(e);
        Process.GetCurrentProcess().Kill();
    }

0

Це схоже на те, на що я зіткнувся, коли створював друге вікно, яке діяло як діалогове вікно. Коли друге вікно було відкрито, а потім закрито, а потім закрито головне вікно, програма продовжувала працювати (у фоновому режимі). Я додав (або підтвердив) у своєму App.xaml наступне:

<Application x:Class="XXXXXXX.App"
             ...  
             StartupUri="MainWindow.xaml"
             ShutdownMode="OnMainWindowClose">
    <Application.MainWindow >
        <NavigationWindow Source="MainWindow.xaml" Visibility="Visible" />
    </Application.MainWindow>

Ніякої радості.

Отже, я нарешті зайшов у свій "MainWindow.xaml" та додав до вікна властивість "Closed", яке перейшло до методу "MainWind_Closed", який виглядає так:

 private void MainWind_Closed(object sender, EventArgs e)
        {
            foreach ( Window w in App.Current.Windows )
            {
                if (w.DataContext != this)
                    w.Close();
            }
        }

Запускаючи налагоджувач, здається, що єдиним вікном, яке з’являється, є вікно, яке я створив як діалогове вікно - іншими словами, цикл foreach знаходить лише одне вікно - діалогове, а не головне.

У мене було "this.Close ()", що працює в методі, який закрив діалогове вікно, і у мене був "dlgwin.Close ()", який прийшов після "dlgwin.ShowDialog ()", і це не спрацювало. Навіть "dlgwin = null".

То чому б це діалогове вікно не закрилося без цієї зайвої речі? Що ж, добре. Це працює.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.