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

В 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. Ниже показано, как примерно он выглядит:
Атрибут Class используется в XAML для создания класса, унаследованного от элемента. Таким образом, создается класс, унаследованный от Application, по имени WpfApplication1.App. (WpfApplication1 — название проекта, совпадающее с пространством имен, в котором определен класс, а App — имя, используемое Visual Studio для специального класса, унаследованного от Application. При желании это имя класса можно заменить более выразительным.)
Дескриптор Application не только создает специальный класс приложения, но также устанавливает свойство StartupUri для идентификации документа XAML, представляющего главное окно. В результате не понадобится явно создавать экземпляр этого окна в коде — анализатор XAML сделает это сам.
Как и с окном, класс приложения определен в двух отдельных частях, которые объединяются вместе во время компиляции. Автоматически сгенерированная часть в проекте невидима, но она содержит точку входа Main() и код для запуска приложения. Выглядит это примерно так, как показано ниже:
#pragma checksum "..\..\..\App.xaml" "" "BA8CBEA9C2EFABD90D53B616FB80A081" //------------------------------------------------------------------------------ // // Этот код создан программой. // Исполняемая версия:4.0.30319.1 // // Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае // повторной генерации кода. // //------------------------------------------------------------------------------ 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 < /// /// App /// [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] public partial class App : System.Windows.Application < /// /// InitializeComponent /// [System.Diagnostics.DebuggerNonUserCodeAttribute()] public void InitializeComponent() < #line 4 "..\..\..\App.xaml" this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative); #line default #line hidden >/// /// Application Entry Point. /// [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(). Это важно, потому что окна могут иметь код обработки событий, который инициируется при их закрытии.
Как запустить wpf приложение
Для создания приложений с помощью технологии WPF мы можем ограничиться текстовым редактором и .NET CLI. Тем не менее мы также можем использовать среду разработки Visual Studio, которая в некоторых аспектах упрощает написание приложения. Например, возьмем ее бесплатную и полнофункциональную версию — Visual Studio Community 2022 , которую можно загрузить по следующему адресу: https://visualstudio.microsoft.com/ru/downloads/.

Чтобы добавить в Visual Studio поддержку проектов для WPF и C# и .NET 7, в программе установки среди рабочих нагрузок нужно выбрать только пункт Разработка классических приложений .NET . Можно выбрать и больше опций или вообще все опции, однако стоит учитывать свободный размер на жестком диске — чем больше опций будет выбрано, соответственно тем больше места на диске будет занято.

После установки среды и всех ее компонентов, запустим Visual Studio и создадим проект графического приложения. На стартовом экране выберем Create a new project (Создать новый проект)

На следующем окне в качестве типа проекта выберем WPF Application :

Далее на следующем этапе нам будет предложено указать имя проекта и каталог, где будет располагаться проект.

В поле Project Name дадим проекту какое-либо название. В моем случае это HelloApp .
На следующем окне Visual Studio предложит нам выбрать версию .NET, которая будет использоваться для проекта. По умолчанию здесь выбрана последняя на данный момент версия — .NET 7.0. Оставим и нажмен на кнопку Create (Создать) для создания проекта.

После этого Visual Studio откроет наш проект с созданными по умолчанию файлами:

Структура проекта
Справа находится окно Solution Explorer, в котором можно увидеть структуру нашего проекта. В данном случае у нас сгенерированная по умолчанию структура, которая аналогична той, что создается с помощью .NET CLI:
- Dependencies — это узел содержит сборки dll, которые добавлены в проект по умолчанию. Эти сборки как раз содержат классы библиотеки .NET, которые будет использовать C#
- App.xaml задает ресурсы приложения и ряд конфигурационных настроек в виде кода XAML. В частности, в файле App.xaml задается файл окна программы, которое будет открываться при запуске приложения. Если вы откроете этот файл, то можете найти в нем строку StartupUri=»MainWindow.xaml» — то есть в данном случае, когда мы запустим приложение, будет создаваться интерфейс из файла MainWindow.xaml . App.xaml.cs — это файл кода на C#, связанный с файл App.xaml , который также позволяет задать ряд общих ресурсов и общую логику для приложения, но в вид кода C#.
- AssemblyInfo.cs содержит информацию о создаваемой в процессе компиляции сборке
- MainWindow.xaml представляет визуальный интерфейс окна приложения в виде кода XAML. MainWindow.xaml.cs — это файл логики кода на C#, связанный с окном MainWindow.xaml . По умолчанию эти файлы открыты в текстовом редакторе Visual Studio. Причем файл MainWindow.xaml имеет два представления: визуальное — в режиме WYSIWIG отображает весь графический интерфейс данного окна приложения, и под ним декларативное объявление интерфейса в XAML. Если мы изменим декларативную разметку, например, определим там кнопку, то эти изменения отображаться в визуальном представлении. Таким образом, мы сможем сразу же получить представление об интерфейсе окна приложения.
Запуск проекта
Чтобы запустить приложение в режиме отладки, нажмем на клавишу F5 или на зеленую стрелочку на панели Visual Studio. И после этого запустится пустое окно по умолчанию.

После запуска приложения студия компилирует его в файл с расширением exe. Найти данный файл можно, зайдя в папку проекта и далее в каталог \bin\Debug\net7.0-windows
Приложение и класс Application
В предыдущих главах мы работали непосредственно с окном приложения, которое представлено классом Window, его разметкой, добавляли в нее элементы, создавали для него код на C#. Однако само приложение начинается не с класса Window , а с класса Application . По умолчанию при создании проекта WPF создается файл App.xaml и класс связанного кода App.xaml.cs :

Файл App.xaml выглядит примерно так:
С помощью атрибута x:Class элемент Application задает полное название производного класса приложения. По умолчанию класс называется App , с указанием названия проекта, то есть в данном случае HelloApp.App
Как правило, основная задача данного файла состоит в определении ресурсов, общих для приложения. Поэтому тут по умолчанию определен пустой элемент Application.Resources , в который, собственно, и помещаются ресурсы.
Также здесь декларативным путем можно прикрепить к событиям приложения обработчики.
С помощью атрибута StartupUri устанавливается путь к разметке xaml, с которого начинается выполнение приложения. По умолчанию это разметка окна MainWindow, определенного в файле MainWindow.xaml . Если у нас в приложении несколько окон, тут мы можем указать то, которое будет запускаться при вызове приложения.
файл App.xaml.cs также содержит определение класса App. По умолчанию этот класс совершенно пустой:
public partial class App : Application
В нем мы можем задать обработчики событий приложения, либо какую-то другую глобальную для всего приложения логику.
Таким образом, у нас получается, что оба файла App.xaml и App.xaml.cs содержат определение одного и того же класса App. Однако в конечном счете они будут компилироваться в один файл приложения App.g.cs , который вы можете найти после компиляции приложения в каталоге проекта obj/Debug/netX.0-windows

Данный класс будет выглядеть примерно так:
public partial class App : System.Windows.Application < [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "7.0.3.0")] public void InitializeComponent() < #line 5 "..\..\..\App.xaml" this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative); #line default #line hidden >[System.STAThreadAttribute()] [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "7.0.3.0")] public static void Main() < HelloApp.App app = new HelloApp.App(); app.InitializeComponent(); app.Run(); >>
Входной точкой в программу (как и в любое другое приложение на C#) является метод Main, в котором создается экземпляр приложения и производится начальная инициализация и вызов главного окна программы.
Так как WPF требует, чтобы главный поток работал в однопоточном подразделении (Single-threaded apartment), то метод Main помечается атрибутом STAThreadAttribute . Однопоточное подразделение содержит один поток, в данном случае главный. Это означает, что к элементам, созданным в этом потоке можно обратиться только из этого же потока. В то же время WPF предлагает эффективный способ взаимодействия между потоками, о котором мы позже поговорим.
С помощью метода InitializeComponent происходит инициализация приложение: установка главного окна для запуска. И далее само приложение запускается через вызов app.Run() .
Также в той же папке можно найти файл App.g.i.cs , который имеет идентичное содержимое, но применяется различными службами Visual Studion, например, Intellisense.
Однако это не жестко заданная организация файлов приложения, и мы ее можем переопределить и установить точку входа в приложение сами. Для этого, во-первых, удалим файл App.g.cs . И во-вторых, изменим код App.xaml.cs :
using System; using System.Windows; using HelloApp; public partial class App : Application < [STAThread] static void Main() < App app = new App(); MainWindow window = new MainWindow(); window.Title = "Hello METANIT.COM"; app.Run(window); >>
Фактически файл App.xaml.cs стал похож на компилируемый файл App.g.cs . Здесь мы сразу определяем метод Main, создаем главное окно — объект класса MainWindows, устанавливаем его заголовок и запускаем ее.
И после запуска нам отобразится главное окно приложения с измененным заголовком.
Сборка и запуск WPF приложения из консоли
Вопрос вроде простой, но я так не понял, как сделать: хочу сделать тоже самое, что делается при запуске/сборке приложения из visual studio , но только при помощи консоли.
Отслеживать
415 2 2 серебряных знака 9 9 бронзовых знаков
задан 11 янв 2020 в 17:49
1,298 13 13 серебряных знаков 21 21 бронзовый знак
То есть Вы хотите собрать WPF из консоли? Попробуйте MSBuild . Примерно что-то наподобие MSBuild project.csproj /p:configuration=Release .
11 янв 2020 в 18:46
– user206435
11 янв 2020 в 22:31
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
В сборке WPF-приложения нет ничего особенного: его можно собрать точно так же, как любое приложение .NET, вызовом MSBuild.
MSBuild MySolution.sln
Основная сложность, из какого каталога брать MSBuild?
Первый вариант: %WINDIR%\Microsoft.NET\Framework\v4.0.30319 . В этом каталоге MSBuild существует всегда, даже если не установлена Visual Studio (поставляется в составе .NET Framework), но версия позволяет собирать проекты только до C# 5.0.
Второй вариант: из каталога Visual Studio
VS 2017: %ProgramFiles(x86)%\Microsoft Visual Studio\2017\\MSBuild\15.0\Bin
VS 2019: %ProgramFiles(x86)%\Microsoft Visual Studio\2019\\MSBuild\Current\Bin\»
где — редакция: Community, Professional или Enterpise
В данном случае будет поддерживаться версия языка на уровне используемой версии студии.