Язык программирования C#9 и платформа .NET5
#line 20 "..\..\MainWindow.xaml"this.MyCalendar.SelectedDatesChanged += newSystem.EventHandler<System.Windows.Controls.SelectionChangedEventArgs>(this.MyCalendar_OnSelectedDatesChanged);Он сообщает инфраструктуре о том, что элементу управления в строке 20 файла XAML назначен обработчик события
, как показано в предыдущем коде.SelectedDatesChangedНаконец, класс
определяет и реализует метод по имениMainWindow. Вы могли бы ожидать, что данный метод содержит код, который настраивает внешний вид и поведение каждого элемента управления, устанавливая его разнообразные свойства (InitializeComponent(),Height,Widthи т.д.). Однако это совсем не так! Как тогда элементы управления получают корректный пользовательский интерфейс? Логика в методеContentвыясняет местоположение встроенного в сборку ресурса, который именован идентично исходному файлуInitializeComponent():*.xamlpublic void InitializeComponent() {if (_contentLoaded) {return;}_contentLoaded = true;System.Uri resourceLocater =new System.Uri("/WpfTesterApp;component/mainwindow.xaml",System.UriKind.Relative);#line 1 "..\..\MainWindow.xaml"System.Windows.Application.LoadComponent(this, resourceLocater);#line default#line hidden}Здесь возникает вопрос: что собой представляет этот встроенный ресурс?
Роль BAML
Как и можно было предположить, формат BAML является компактным двоичным представлением исходных данных XAML. Файл
встраивается в виде ресурса (через сгенерированный файл*.baml) в скомпилированную сборку. Ресурс BAML содержит все данные, необходимые для настройки внешнего вида и поведения виджетов пользовательского интерфейса (т.е. свойств вроде*.g.resourcesиHeight).WidthЗдесь важно понимать, что приложение WPF содержит внутри себя двоичное представление (BAML) разметки. Во время выполнения ресурс BAML извлекается из контейнера ресурсов и применяется для настройки внешнего вида и поведения всех окон и элементов управления.
Вдобавок запомните, что имена таких двоичных ресурсов идентичны именам написанных автономных файлов
. Тем не менее, отсюда вовсе не следует необходимость распространения файлов*.xamlвместе со скомпилированной программой WPF. Если только не строится приложение WPF, которое должно динамически загружать и анализировать файлы*.xamlво время выполнения, то поставлять исходную разметку никогда не придется.*.xamlРазгадывание загадки Main()
Теперь, когда известно, как работает процесс
, откройте файлmsbuild.exe. В нем обнаружится автоматически сгенерированный методАрр.g.cs, который инициализирует и запускает ваш объект приложения:Main()public static void Main() {WpfTesterApp.App app = new WpfTesterApp.App();app.InitializeComponent();app.Run();}Метод
конфигурирует свойства приложения, включаяInitializeComponent()и обработчики событийStartupUriиStartup:Exitpublic void InitializeComponent() {#line 5 "..\..\App.xaml"this.Startup += new System.Windows.StartupEventHandler(this.App_OnStartup);#line default#line hidden#line 5 "..\..\App.xaml"this.Exit += new System.Windows.ExitEventHandler(this.App_OnExit);#line default#line hidden#line 5 "..\..\App.xaml"this.StartupUri =new System.Uri("MainWindow.xaml", System.UriKind.Relative);#line default#line hidden}Взаимодействие с данными уровня приложения
Вспомните, что в классе
имеется свойство по имениApplication, которое позволяет определить коллекцию пар "имя/значение" посредством индексатора типа. Поскольку этот индексатор предназначен для оперирования на типеProperties, в коллекцию можно сохранять элементы любого вида (в том числе экземпляры специальных классов) с целью последующего извлечения по дружественному имени. С использованием такого подхода легко разделять данные между всеми окнами в приложении WPF.System.ObjectВ целях иллюстрации вы обновите текущий обработчик события
, чтобы он проверял входящие аргументы командной строки на присутствие значенияStartup(распространенный мошеннический код во многих играх). Если оно найдено, тогда значение/GODMODEпо имениboolвнутри коллекции свойств устанавливается вGodMode(в противном случае оно устанавливается вtrue).falseЗвучит достаточно просто, но как передать обработчику события
входные аргументы командной строки (обычно получаемые методомStartup)? Один из подходов предусматривает вызов статического методаMain(). Однако те же самые аргументы автоматически добавляются во входной параметрEnvironment.GetCommandLineArgs()и доступны через свойствоStartupEventArgs. Ниже приведена первая модификация текущей кодовой базы:Args