Литмир - Электронная Библиотека
A
A

#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
во время выполнения, то поставлять исходную разметку никогда не придется.

Разгадывание загадки 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
. Ниже приведена первая модификация текущей кодовой базы:

487
{"b":"847442","o":1}