Создание и останов приложения

74

В WPF приложение проходит через простой жизненный цикл. Вскоре после запуска приложения создается объект Application. Во время его выполнения возникают различные события приложения, которые можно отслеживать. И, наконец, когда объект приложения освобождается, приложение завершается.

WPF позволяет создавать полноценные приложения, создающие иллюзию работы в веб-браузере. Эти приложения называются XBAP. Относительно XBAP-приложений следует отметить, что в них применяется тот же класс Application, генерируются те же события жизненного цикла и используются ресурсы сборки таким же способом, что и в стандартных приложениях на основе WPF.

Создание объекта Application

Простейший способ использования класса Application предусматривает его создание вручную. В следующем примере демонстрируется абсолютный минимум: точка входа в приложение (метод Main()), которая создает окно по имени Window1 и запускает новое приложение:

using System;
using System.Windows;
public class Startup
{
   [STAThread()]
   static void Main()
   {
      // Создание приложения
      Application app = new Application();
      // Создание главного окна.
      Window1 win = new Window1();
      // Запуск приложения и отображение главного окна,
      app.Run(win);
}

Передача окна методу Application.Run() приводит к тому, что это окно устанавливается в качестве главного и доступно во всем приложении через свойство Application.MainWindow. Метод Run() затем инициирует событие Application.Startup и отображает главное окно.

Запущенное подобным образом приложение продолжает работу до тех пор, пока главное окно и все его прочие окна не будут закрыты. В этот момент метод Run() вернет управление и, прежде чем завершится приложение, будет выполнен любой дополнительный код в Main().

Чтобы запустить приложение с использованием метода Main(), необходимо определить класс, который содержит метод Main() в качестве стартового объекта в Visual Studio. Чтобы сделать это, дважды щелкните на узле Properties (Свойства) в Solution Explorer и измените выбор в списке Startup Object (Стартовый объект). Обычно это делать не понадобится, потому что Visual Studio создает метод Main() автоматически на основе шаблона приложения XAML.

Наследование специального класса приложения

Хотя подход, описанный в предыдущем разделе (с созданием экземпляра базового класса Application и вызовом Run()), работает вполне удовлетворительно, при создании нового приложения WPF этот вариант в Visual Studio не используется.

Вместо этого Visual Studio создает специальный класс, унаследованный от Application. В простом приложении такой подход не дает существенного эффекта. Однако если планируется обработка событий приложения, он предоставляет более изящную модель, потому что код обработки событий может быть помещен в класс, производный от Application.

Модель, реализованная в Visual Studio в отношении класса Application, по сути, та же, что и модель, применяемая для окон. Начальная точка — шаблон XAML, по умолчанию называемый App.xaml. Ниже показано, как примерно он выглядит:

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

Атрибут Class используется в XAML для создания класса, унаследованного от элемента. Таким образом, создается класс, унаследованный от Application, по имени WpfApplication1.App. (WpfApplication1 — название проекта, совпадающее с пространством имен, в котором определен класс, а App — имя, используемое Visual Studio для специального класса, унаследованного от Application. При желании это имя класса можно заменить более выразительным.)

Дескриптор Application не только создает специальный класс приложения, но также устанавливает свойство StartupUri для идентификации документа XAML, представляющего главное окно. В результате не понадобится явно создавать экземпляр этого окна в коде — анализатор XAML сделает это сам.

Как и с окном, класс приложения определен в двух отдельных частях, которые объединяются вместе во время компиляции. Автоматически сгенерированная часть в проекте невидима, но она содержит точку входа Main() и код для запуска приложения. Выглядит это примерно так, как показано ниже:

#pragma checksum "..\..\..\App.xaml" "{406ea660-64cf-4c82-b6f0-42d48172a799}" "BA8CBEA9C2EFABD90D53B616FB80A081"
//------------------------------------------------------------------------------
// <auto-generated>
//     Этот код создан программой.
//     Исполняемая версия:4.0.30319.1
//
//     Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
//     повторной генерации кода.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;


namespace WpfApplication1 {
    
    
    /// <summary>
    /// App
    /// </summary>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
    public partial class App : System.Windows.Application {
        
        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public void InitializeComponent() {
            
            #line 4 "..\..\..\App.xaml"
            this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);
            
            #line default
            #line hidden
        }
        
        /// <summary>
        /// Application Entry Point.
        /// </summary>
        [System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public static void Main() {
            WpfApplication1.App app = new WpfApplication1.App();
            app.InitializeComponent();
            app.Run();
        }
    }
}

Если вы действительно заинтересованы в том, чтобы увидеть специальный класс приложения, созданный шаблоном XAML, загляните в файл App.g.cs в папке obj --> Debug внутри каталога проекта.

Единственное отличие между автоматически сгенерированным кодом, показанным здесь, и специальным классом приложения, который вы можете создать самостоятельно, состоит в том, что автоматически сгенерированный класс использует свойство StartupUri вместо установки свойства MainWindow или передачи главного окна в качестве параметра методу Run(). Применяя тот же самый формат URI, можно создать специальный класс приложения, использующий этот подход.

Понадобится создать объект относительного URI, который именует документ XAML, находящийся в проекте. (Этот документ XAML компилируется и встраивается в сборку приложения в виде ресурса BAML. Именем ресурса является имя исходного файла XAML.)

Останов приложения

Обычно класс Application оставляет приложение активным до тех пор, пока открыто хотя бы одно окно. Если такое поведение не нужно, можно изменить значение свойства Application.ShutdownMode. При создании объекта Application вручную, свойство ShutdownMode должно быть установлено перед запуском Run(). Если используется файл App.xaml, можно просто установить свойство ShutdownMode в коде разметки XAML.

Режим останова приложения может принимать три значения:

OnLastWindowClose

Поведение по умолчанию — приложение выполняется до тех пор, пока существует хотя бы одно открытое окно. После закрытия главного окна свойство Application.MainWindow по-прежнему ссылается на объект, представляющий закрытое окно. (Дополнительно можно использовать код для переназначения свойства MainWindow, чтобы оно указывало на другое окно.)

OnMainWindowClose

Это традиционный подход — приложение остается активным только пока открыто главное окно

OnExplicitShutdown

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

Независимо от того, какой способ останова используется, всегда есть возможность с помощью метода Application.Shutdown() немедленно завершить приложение. (Разумеется, после вызова метода Shutdown() приложение не обязательно сразу завершится. Вызов Application.Shutdown() заставляет метод Application.Run() немедленно вернуть управление, но может существовать дополнительный код, который выполняется в методе Main() или реагирует на событие Application.Exit.)

Когда ShutdownMode равно OnMainWindowClose, и закрывается главное окно, объект Application автоматически закроет все прочие окна перед тем, как метод Run() вернет управление. То же самое верно, если вызывается Application.Shutdown(). Это важно, потому что окна могут иметь код обработки событий, который инициируется при их закрытии.

Пройди тесты
Лучший чат для C# программистов