#line 20 "....MainWindow.xaml"
this.MyCalendar.SelectedDatesChanged += new
System.EventHandler<System.Windows.Controls.SelectionChangedEventArgs>(
this.MyCalendar_OnSelectedDatesChanged);
Он сообщает инфраструктуре о том, что элементу управления в строке 20 файла XAML назначен обработчик события SelectedDatesChanged, как показано в предыдущем коде.
Наконец, класс MainWindow определяет и реализует метод по имени InitializeComponent(). Вы могли бы ожидать, что данный метод содержит код, который настраивает внешний вид и поведение каждого элемента управления, устанавливая его разнообразные свойства (Height, Width, Content и т.д.). Однако это совсем не так! Как тогда элементы управления получают корректный пользовательский интерфейс? Логика в методе InitializeComponent() выясняет местоположение встроенного в сборку ресурса, который именован идентично исходному файлу *.xaml:
public 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 встраивается в виде ресурса (через сгенерированный файл *.g.resources) в скомпилированную сборку. Ресурс BAML содержит все данные, необходимые для настройки внешнего вида и поведения виджетов пользовательского интерфейса (т.е. свойств вроде Height и Width).
Здесь важно понимать, что приложение WPF содержит внутри себя двоичное представление (BAML) разметки. Во время выполнения ресурс BAML извлекается из контейнера ресурсов и применяется для настройки внешнего вида и поведения всех окон и элементов управления.
Вдобавок запомните, что имена таких двоичных ресурсов идентичны именам написанных автономных файлов *.xaml. Тем не менее, отсюда вовсе не следует необходимость распространения файлов *.xaml вместе со скомпилированной программой WPF. Если только не строится приложение WPF, которое должно динамически загружать и анализировать файлы *.xaml во время выполнения, то поставлять исходную разметку никогда не придется.
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})
Разгадывание загадки Main()
Теперь, когда известно, как работает процесс msbuild.exe, откройте файл Арр.g.cs. В нем обнаружится автоматически сгенерированный метод Main(), который инициализирует и запускает ваш объект приложения:
public static void Main() {
WpfTesterApp.App app = new WpfTesterApp.App();
app.InitializeComponent();
app.Run();
}
Метод InitializeComponent() конфигурирует свойства приложения, включая StartupUri и обработчики событий Startup и Exit:
public 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, которое позволяет определить коллекцию пар "имя/значение" посредством индексатора типа. Поскольку этот индексатор предназначен для оперирования на типе System.Object, в коллекцию можно сохранять элементы любого вида (в том числе экземпляры специальных классов) с целью последующего извлечения по дружественному имени. С использованием такого подхода легко разделять данные между всеми окнами в приложении WPF.
В целях иллюстрации вы обновите текущий обработчик события Startup, чтобы он проверял входящие аргументы командной строки на присутствие значения /GODMODE (распространенный мошеннический код во многих играх). Если оно найдено, тогда значение bool по имени GodMode внутри коллекции свойств устанавливается в true (в противном случае оно устанавливается в false).
Звучит достаточно просто, но как передать обработчику события Startup входные аргументы командной строки (обычно получаемые методом Main())? Один из подходов предусматривает вызов статического метода Environment.GetCommandLineArgs(). Однако те же самые аргументы автоматически добавляются во входной параметр StartupEventArgs и доступны через свойство Args. Ниже приведена первая модификация текущей кодовой базы: