МегаПредмет

ПОЗНАВАТЕЛЬНОЕ

Оси и плоскости тела человека Оси и плоскости тела человека - Тело человека состоит из определенных топографических частей и участков, в которых расположены органы, мышцы, сосуды, нервы и т.д.


Отёска стен и прирубка косяков Отёска стен и прирубка косяков - Когда на доме не достаёт окон и дверей, красивое высокое крыльцо ещё только в воображении, приходится подниматься с улицы в дом по трапу.


Дифференциальные уравнения второго порядка (модель рынка с прогнозируемыми ценами) Дифференциальные уравнения второго порядка (модель рынка с прогнозируемыми ценами) - В простых моделях рынка спрос и предложение обычно полагают зависящими только от текущей цены на товар.

Простые свойства и конвертеры типов





Как вы уже видели, атрибуты элемента устанавливают свойства соответствующего объекта. Например, текстовые поля в примере автоответчика устанавливают выравнивание поля и шрифт:

<TextBox Name="txtQuestion"

VerticalAlignment="Stretch" HorizontalAlignment="Stretch"

FontFamily="Verdana" FontSize="4" Foreground="Green" ... >

Чтобы это заработало, класс System.Windows.Controls.TextBox должен предоставить следующие свойства: VerticalAlignment, HorizontalAlignment, FontFamily, FontSize и Foreground. Для того, чтобы заставить эту систему работать, анализатор XAML-текста должен выполнить некоторую дополнительную работу. Обратим внимание на то, что значение в атрибуте XAML-текста всегда представлено простой строкой. Однако свойства объекта могут быть любого (произвольного) типа .NET.

В предыдущем примере было два свойства, использующих перечисления (VerticalAlignment и HorizontalAlignment), одна строка (FontFamily), одно целое число (FontSize) и один объект типа Brush (Foreground). Для того, чтобы преодолеть различие между строковыми значениями и не строковыми свойствами, анализатору XAML-текста необходимо выполнить соответствующее преобразование. Это преобразование осуществляется конвертерами типов, которые являются базовой частью инфраструктуры .NET.

По сути дела, конвертер типов предназначен только для предоставления специальных методов, которые могут преобразовывать определенный тип данных .NET в любой другой тип .NET. Например, такой как строчный тип данных. Для того чтобы найти нужный конвертер типа, анализатор XAML-текста выполняет следующие действия:

1. Проверяет объявление свойства в поисках атрибута TypeConverter. В нашем примере атрибут TypeConverter указывает на класс, выполняющий преобразование. Например, когда используете такое свойство, как Foreground, то .NET проверяет объявление свойства Foreground.

2. Если в объявлении свойства отсутствует атрибут TypeConverter, то анализатор XAML-текста проверяет наличие объявления класса соответствующего типа данных. Например, свойство Foreground использует объект Brush. Класс Brush (и его наследники) используют свойство BrushConverter, потому что он оснащен объявлением атрибута TypeConverter(typeof(BrushConverter)).

Если в объявлении свойства или объявлении класса не оказывается соответствующего конвертера типа, то анализатор XAML генерирует ошибку.

Такая система проста и гибка. Если конвертер типа устанавливается на уровне класса, то он применяется к каждому свойству, использующему этот класс. С другой стороны, если необходимо обеспечить более тонкую настройку работы конвертера типа для конкретного свойства, то вместо этого можно применять атрибут TypeConverter в объявлении свойства.

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

Конечно, прежде чем установить свойства в элементе WPF, нужно узнать немного больше о базовых свойствах WPF и типах данных.

Сложные свойства.

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

К счастью, XAML предусматривает другой выбор, основанный на таком понятии синтаксиса, как "свойство-элемент". С помощью этого синтаксиса вы можете добавлять дочерний элемент с именем в форме Родитель.ИмяСвойства. Например, у объекта типа Grid есть свойство Background, которое позволяет применять кисть, используемую для рисования области, находящейся под элементами управления. Если необходимо использовать более сложную кисть, то нужно добавить дочерний дескриптор по имени Grid.Background следующим образом:

<Grid Name="grid1">

<Grid.Background>

</Grid.Background>

</Grid>

Ключевая деталь, которая заставляет это работать заключается в точке (.) после имени элемента управления. Этот прием позволяет отличать сложное свойство от других типов. Для того чтобы настроить сложное свойство, необходимо внутри вложенного элемента добавить другой дескриптор для того, чтобы создать экземпляр определенного класса. Вспомним, что в примере с автоответчиком, фон заливается градиентом. Однако, чтобы задать нужный градиент, следует создать объект LinearGradientBrush. Для этого, в соответствие с правилами XAML, можно создать объект LinearGradientBrush, используя элемент по имени LinearGradientBrush:

<Grid Name="grid1">

<Grid.Background>

<LinearGradientBrush> </LinearGradientBrush>

</Grid.Background>

</Grid>

Поскольку элемент LinearGradientBrush является частью пространств имен для WPF, то можно использовать пространство имен XML по умолчанию для ваших дескрипторов. Однако недостаточно просто создать LinearGradientBrush. Необходимо также задать цвета градиента. Это делается путем заполнения свойства LinearGradientBrush.GradientStops коллекцией объектов GradientStop. Например:

<Grid Name="grid1">

<Grid.Background>

<LinearGradientBrush>

<GradientStop Offset="0.00" Color="Red" />

<GradientStop Offset="0.50" Color="Indigo" />

<GradientStop Offset="1.00" Color="Violet" />

</LinearGradientBrush>

</Grid.Background>

</Grid>

На заметку! Использовать синтаксис "свойство-элемент" можно для любого свойства. Но обычно, если свойство имеет подходящий конвертер типа, то используют более простой подход, основанный на использовании синтаксиса "свойство-атрибут". Это позволяет получить более компактный код.

Следует отметить тот факт, что любой набор дескрипторов XAML-языка может быть заменен набором операторов кода, решающих ту же самую задачу. Приведенные дескрипторы, которые заполняют фон градиентом по вашему выбору, эквивалентны следующему коду на языке С#:

LinearGradientBrush brush = new LinearGradientBrush();

GradientStop gradientStopl = new GradientStop();

gradientStop1.Offset = 0;

gradientStop1.Color = Colors.Red;

brush.GradientStops.Add(gradientStop1);

GradientStop gradientStop2 = new GradientStop();

gradientStop2.0ffset = 0.5;

gradientStop2.Color = Colors.Indigo;

brush.GradientStops.Add(gradientStop2);

GradientStop gradientStop3 = new GradientStop();

gradientStop3.0ffset = 1;

gradientStop3.Color = Colors.Violet;

brush.GradientStops.Add(gradientStop3);

grid1.Background = brush;

Расширения разметки.

Для большинства свойств синтаксис свойств XAML работает исключительно хорошо. Но в некоторых случаях оказывается невозможным жестко закодировать значение свойства. Например, когда нужно установить значение свойства в уже существующий объект. Или же нужно устанавливать значение свойства динамически, привязывая его к свойству в другом элементе управления. В таких случаях вам нужно использовать расширение разметки (markup extension), представляющее собой специализированный синтаксис, устанавливающий свойство нестандартным образом.

Расширения разметки могут применяться во вложенных дескрипторах или атрибутах XML что встречается чаще. Когда они используются в атрибутах, то всегда окружаются фигурными скобками {}. Например, вот как вы можете использовать StaticExtension, позволяющее сослаться на статическое свойство другого класса:

<Button ... Foreground»"{x:Static SystemColors.ActiveCaptionBrush}" >

Расширения разметки используют синтаксис { КлассРасширенияРазметки Аргумент }. В этом случае расширением разметки служит класс StaticExtension. (По принятому соглашению можно пропускать последнее слово Extension, ссылаясь на класс расширения.) Префикс х: указывает на то. что StaticExtension находится в одном из пространств имен XAML. Также можно встретить расширения разметки, являющиеся частью пространств имен WPF, но не имеющие префикса х:.

Все расширения разметки реализованы классами, производными от System.Windows.Markup.MarkupExtension. Базовый класс MarkupExtension содержит единственный метод ProvideValue(), получающий значение, которое требуется установить. Другими словами, когда анализатор XAML встречает этот оператор, то он создает экземпляр класса StaticExtension (передавая строку "SystemColors.ActiveCaptionBrush" в качестве аргумента его конструктору), а затем вызывает метод ProvideValue(), чтобы получить объект, возвращенный статическим свойством SystemColors.ActiveCaption.Brush. После чего свойство Foreground кнопки cmdAnswer устанавливается равным извлеченному объекту.

Конечный результат этого фрагмента XAML-кода соответствует тому, как если бы вы написали следующее:

cmdAnswer.Foreground = SystemColors.ActiveCaptionBrush;

Поскольку расширения разметки отображаются на классы, то они могут также применяться и в виде вложенных свойств. Например, можно использовать объект StaticExtension со свойством Button.Foreground следующим образом:

<Button ... >

<Button.Foreground>

<х:Static Member="SystemColors.ActiveCaptionBrush"></x:Static>

</Button.Foreground>

</Button>

В зависимости от сложности расширения разметки и количества свойств, которые требуется установить в нужные значения, синтаксис может оказаться более простым.

Как и большинство других расширений разметки, StaticExtension должен вычисляться во время выполнения, потому что только тогда можно определить текущие системные цвета. Некоторые расширения разметки могут определяться во время компиляции. К ним относятся NullExtension (представляющее значение null) и TypeExtension (конструирующее объект, представляющий тип .NET).

Прикрепленные свойства

Наряду с обычными свойствами XAML также включает концепцию прикрепленных свойств, т.е. таких свойств, которые могут применяться одновременно к нескольким элементам управления, но определенных в другом классе. В WPF прикрепленные свойства часто применяются для управления компоновкой.

Это работает следующим образом. Каждый элемент управления имеет свой собственный набор внутренних свойств. Например, текстовое поле имеет специфический шрифт, цвет текста и текстовое содержимое. Все это определено такими свойствами, как Font Family, Foreground и Text. Когда элемент управления помещается внутри контейнера, то, в зависимости от типа контейнера, он может получить дополнительные свойства. Например, если поместить текстовое поле внутрь экранной сетки (grid), то возникает необходимость в том, чтобы указать ячейку этой сетки для его размещения. Эти дополнительные детали как раз и устанавливаются с использованием прикрепленных свойств.

Прикрепленные свойства всегда используют имя из двух частей в форме ОпределяемыйТип.ИмяСвойства. Этот синтаксис позволяет анализатору XAML различать обычное и прикрепленное свойство. В примере с автоответчиком прикрепленные свойства позволяют индивидуальным элементам управления размещать себя в разных строках (невидимой) сетки.

<TextBox ... Grid.Row="0">

[Place question here.]

</TextBox>

<Button ... Grid.Row="l">

Ask the Eight Ball

</Button>

<TextBox ... Grid.Row="2">

[Answer will appear here.]

</TextBox>

Следует отметить тот факт, что в действительности прикрепленные свойства вообще свойствами не являются. На самом деле они транслируются в вызовы методов. Анализатор XAML вызывает статический метод, имеющий форму ОпределяемыйТип.SetИмяСвойства(). Например, в предыдущем фрагменте XAML определяемым типом является класс Grid, а свойство - Row, поэтому анализатор вызывает Grid.SetRow().

При вызове метода SetИмяСвойства() анализатор принимает два параметра: модифицируемый объект и значение свойства. Например, когда устанавливается свойство строки (Grid.Row) на элементе управления TextBox, то анализатор XAML выполняет следующий код:

Grid.SetRow(txtQuestion, 0);

Этот шаблон (с вызовом статического метода определенного типа) удобен тем, что скрывает то, что происходит на самом деле. На первый взгляд этот код выглядит так, будто номер строки сохраняется в объекте Grid. Однако номер строки в действительности сохраняется в объекте, которого он касается, в данном случае — в TextBox.

Эта манипуляция удается потому, что TextBox наследуется от базового класса DependencyObject, как и все элементы управления WPF. А этот класс предназначен для хранения практически неограниченной коллекции свойств зависимости. Следует отметить, что прикрепленные свойства как раз и являются специальным тип свойства зависимости.

Фактически метод Grid.SetRow() на самом деле представляет собой некоторую сокращенную форму его представления, эквивалентную вызову метода DependencyObject.SetValue():

txtQuestion.SetValue(Grid.RowProperty, 0) ;

Прикрепленные свойства являются одной из основных составляющих WPR Они действуют как система расширения общего назначения. Например, определяя свойство Row как прикрепленное, вы гарантируете его применимость с любым элементом управления.

На заметку! Прикрепленные свойства очень похожи на поставщики расширений в приложении Windows Forms. И те, и другие позволяют вам добавлять "виртуальные" свойства для расширения другого класса. Отличие состоит в том, что, перед тем, как использовать его, необходимо создавать экземпляр поставщика расширений и значение расширенного свойства сохраняется в поставщике расширений, а не в расширяемом элементе управления. Дизайн прикрепленного свойства позволяет избежать проблем управления жизненным циклом (например, решая, когда следует уничтожать поставщика расширений).

Вложенные элементы.

Как мы успели убедиться, тексты, написанные на языке XAML, представляют собой дерево элементов с высокой степенью вложенности. В рассмотренном примере элемент Window содержит элемент Grid, который, в свою очередь, содержит элементы TextBox и Button.

XAML позволяет каждому элементу решать, как ему следует поступать с вложенными элементами. Это взаимодействие осуществляется при посредничестве одного из четырех механизмов, запускаемых в следующем порядке.

• Если родитель реализует IList, то анализатор вызывает метод IList. Add(), передавая ему дочерний элемент.

• Если родитель реализует IDictionary, то анализатор вызывает метод IDictionary.Add () и передает ему дочерний элемент. Кроме того, для того, чтобы при использовании коллекции-словаря дать ключевое имя каждому ее элементу, необходимо также устанавливать атрибут х: Key.

• Если родитель оснащен атрибутом ContentProperty, то анализатор использует дочерний элемент, чтобы установить это свойство.

Например, было показано, что LinearGradientBrush может содержать коллекцию объектов GradientStop, используя следующий синтаксис:

<LinearGradientBrush>

<LinearGradientBrush.GradientStops>

<GradientStop Offset="0.00" Color="Red" />

<GradientStop Offset="0.50" Color="Indigo" />

<GradientStop Offset="1.00" Color="Violet" />

</LinearGradientBrush.GradientStops>

</LinearGradientBrush>

Анализатор XAML распознает элемент LinearGradientBrush.GradientStops как сложное свойство, потому что оно содержит внутри себя точку. Однако, внутренние дескрипторы (три элемента GradientStop) ему нужно обработать немного по-другому. В этом случае анализатор распознает, что свойство GradientStops возвращает объект GradientstopСollection, реализующий интерфейс IList. Поэтому он предварительно предполагает, что каждый экземпляр типа GradientStop должен быть добавлен к коллекции с использованием метода IList.Add():

GradientStop gradientStop1 = new GradientStop() ;

gradientStop1.offset = 0;

gradientStop1.Color = Colors.Red;

IList list = brush.GradientStops;

list.Add(gradientStop1);

Некоторые свойства могут поддерживать более одного типа коллекций. Тогда необходимо будет добавить дескриптор, специфицирующий класс коллекции:

<LinearGradientBrush>

<LinearGradientBrush.GradientStops>

<GradientStopCollection>

<GradientStop Offset="0.00" Color="Red" />

<Gradientstop Offset="0.50" Color="Indigo" />

<GradientStop Offset="1.00" Color="Violet" />

</GradientStopCollection>

</LinearGradientBrush.Gradientstops>

</LinearGradientBrush>

На заметку! Если по умолчанию коллекция установлена в null, вы должны включить дескриптор, специфицирующий класс коллекции, тем самым создавая объект коллекции. Если имеется экземпляр коллекции по умолчанию, и вы должны просто заполнить ее, то можете опустить эту часть.

Вложенное содержимое не всегда обозначает коллекцию. Например, рассмотрим элемент Grid, который содержит несколько других элементов управления:

<Grid Name="grid1">

<TextBox Name="txtQuestion" ... >

</TextBox>

<Button Name="cmdAnswer" . . . >

</Button>

<TextBox Name="txtAnswer" ... >

</TextBox>

</Grid>

Эти вложенные дескрипторы не соответствуют сложным свойствам, поскольку не включают точки. Более того, элемент Grid не является коллекцией и потому не реализует IList или IDictionary. Что Grid действительно поддерживает — так это атрибут ContentProperty, указывающий на свойство, которое должно принимать любое вложенное содержимое. Технически атрибут ContentProperty применяется к классу Panel, от которого унаследован Grid, и выглядит он таким образом:

[ContentPropertyAttribute("Children")]

public abstract class Panel {}

Это указывает на то, что любые вложенные элементы должны использоваться для установки свойства Children. Анализатор XAML трактует свойство содержимого по-разному в зависимости от того, является ли оно свойством-коллекцией (и в этом случае реализует интерфейс IList или IDictionary). Поскольку свойство Panel.Children возвращает UIElementCollection и поскольку UIElementCollection реализует IList, то анализатор использует метод IList.Add() для добавления в сетку вложенного содержимого.

Другими словами, когда анализатор XAML встречает приведенную выше разметку, то он создает экземпляр каждого элемента и передает его Grid, используя метод Grid.Children.Add():

txtQuestion = new TextBox();

grid1.Children.Add(txtQuestion);

cmdAnswer = new Button();

grid1.Children.Add(cmdAnswer);

txtAnswer = new TextBox();

grid1.Children.Add(txtAnswer);

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

Атрибут ContentProperty часто используется в WPF. Он применяется не только для контейнерных элементов управления (вроде Grid) и элементов, содержащих коллекцию визуальных элементов (таких как ListBox и TreeView), но также используется для элементов управления, содержащих одиночное содержимое. Например, TextBox и Button способны содержать только один элемент или фрагмент текста, но они оба используют свойство содержимого, чтобы обращаться с вложенным содержимым. Например, следующим образом:

<TextBox Name="txtQuestion" ... >

[Place question here.]

</TextBox>

<Button Name="cmdAnswer" ... >

Ask the Eight Ball

</Button>

<TextBox Name="txtAnswer" . . . >

[Answer will appear here. ]

</TextBox>

Класс TextBox использует атрибут ContentProperty для пометки свойства TextBox.Text. Класс Button использует атрибут ContentProperty для пометки свойства Button.Content. Анализатор XAML использует примененный текст для установки этих свойств.

Свойство TextBox.Text принимает только строковые значения. Однако Button.Content более интересно. Свойство Content принимает любой элемент. Например, так выглядит кнопка, содержащая объект-фигуру:

<Button Name = "cmdAnswer" ... >

<Rectangle Fill="Blue" Height="10" Width="100" />

</Button>

Поскольку свойства Text и Content не используют коллекций, то это не позволяет включать в него более одной части содержимого. Например, если вы попытаетесь вложить несколько элементов внутрь Button, то анализатор XAML сгенерирует исключение. Анализатор

также сгенерирует исключение, если применить нетекстовое содержимое. Например, такое как

Rectangle.

На заметку! Как правило, все элементы управления, унаследованные от ContentControl,

допускают единственный вложенный элемент. Все элементы, унаследованные от ItemsControl, допускают использование коллекции элементов, отображаемых на элемент управления некоторого типа, например окна списка или дерева. Все элементы, унаследованные от Panel, являются контейнерами, используемыми для организации групп элементов управления. Базовые классы ContentControl, ItemsControl и Panel используют атрибут ContentProperty.

События

До сих пор все атрибуты, которые вы видели, отображались на свойства. Однако атрибуты также могут быть использованы для прикрепления обработчиков событий. Синтаксис при этом выглядит следующим образом:

ИмяСобытия=="ИмяМетодаОбработчикаСобытий"

Например, элемент управления типа Button предоставляет событие Click. Тогда можно

прикрепить обработчик событий следующим образом:

<Button Click="cmdAnswer_Click">

Это предполагает наличие метода по имени cmdAnswer_Click в классе отделенного кода. Обработчик событий должен иметь правильную сигнатуру. То есть он должен соответствовать делегату для события Click. Например:

private void cmdAnswer_Click(object sender, RoutedEventArgs e)

{

this.Cursor = Cursors.Wait;

// Значительная задержка...

System.Threading.Thread.Sleep(TimeSpan.FromSeconds (3)) ;

AnswerGenerator generator = new AnswerGenerator ();

txtAnswer.Text = generator.GetRandomAnswer(txtQuestion.Text) ;

this.Cursor = null;

}

По сигнатуре этого обработчика событий можно легко заметить, что модель событий в WPF несколько отличается от ранних версий .NET. Теперь она поддерживает новую модель, основанную на маршрутизации событий.

Часто, для одного и того же элемента управления, используются атрибуты для установки его свойств и прикрепления соответствующих обработчиков событий. WPF всегда делает эту работу в следующей последовательности: сначала устанавливается свойство Name (если оно есть), а затем прикрепляются любые обработчики событий и, наконец, устанавливаются свойства. Это означает, что любые обработчики событий, реагирующие на изменения свойств, будут запущены при первоначальной установке свойства.

Visual Studio облегчает этот процесс путем предоставления специальных средств IntelliSense при добавлении атрибут для обработчика события. Например, как только вводится символ равенства после набора Click= в элементе <Button>, то сразу же отображается раскрывающийся список со всеми подходящими обработчиками событий в вашем классе отделенного кода. Если вам нужно создать новый обработчик для данного события, просто выбирается пункт <Новый обработчик событий> (<New Event Handler>), расположенный в вершине этого списка.


1.5.11. Полный пример автоответчика

Теперь, когда вы познакомились с основами XAML. вы знаете достаточно, чтобы пройтись по определению окна, показанного на рис. 2.1. Вот полный код разметки XAML:

<Window x:Class="EightBall.Windowl"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="Eight Ball Answer" Height="300" Width="300" >

<Grid Name="gridl">

<Grid.RowDefinitions>

<RowDefinition Height="34" />

<RowDefinition Height="98" />

<RowDefinition Height="130" />

</Grid.RowDefinitions>

<TextBox VerticalAlignment="Stretch" HorizontalAlignment="Stretch"

Margin="10,10,13,10" Name="txtQuestion"

TextWrapping="Wrap" FontFamily="Verdana" FontSize="24" Grid.Row="0">

[Place question here.]

</TextBox>

<Button VerticalAlignment="Top" HorizontalAlignment="Left"

Margin "10,10,10,20 " Width="127" Height="23" Name="cmdAnswer"

Click="cmdAnswer_Click" Grid.Row="l">

Ask the Eight Ball

</Button>

<TextBox VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >

Margin="10,10,13,10" Name="txtAnswer" TextWrapping=" Wrap"

IsReadOnly="True" FontFamily=Verdana" FontSize="24" Foreground="Green"

Grid.Row="2">

[Answer will appear here.]

</TextBox>

<Grid.Background>

<LinearGradientBrush>

<GradientStop Offset="0.00" Color="Red" />

<GradientStop Offset="0.50" Color="Indigo" />

<GradientStop Offset="1.00" Color="Violet" />

</LinearGradientBrush>

</Grid.Background>

</Grid>

</Window>

Совершенно ясно, что писать вручную тексты на языке XAML для пользовательского интерфейса достаточно утомительно. Но иногда это бывает необходимо, например, когда в дизайнере трудно отредактировать код XAML так, как это необходимо или он вообще не позволяет этого сделать необходимые изменения.

1.5.12. Загрузка и компиляция XAML

Как вам стало известно, XAML и WPF- это две разные, хотя и взаимодополняющие технологии. В результате вполне возможно создать приложение WPF, которое может не использовать слабой части XAML.

Существуют три разных стиля кодирования, которые вы можете использовать для создания приложения WPF.

• Только программный код на языке С#. Это традиционный подход, используемый в Visual Studio для создания приложений Windows Forms. Он генерирует пользовательский интерфейс в виде соответствующих операторов кода.

• Программный код и не компилированная разметка (XAML). Это специализированный подход, который имеет смысл в определенных ситуациях, когда необходимы высокодинамичные пользовательские интерфейсы. При этом часть пользовательского интерфейса загружается из файла XAML во время выполнения с помощью класса System.Windows.Markup.XamlReader

• Программный код и компилированная разметка (BAML). Это предпочтительный подход для WPF, поддерживаемый в Visual Studio. В этом случае для каждого окна создается шаблон XAML, который компилируется в BAML. После чего результат встраивается в конечную сборку. Во время выполнения скомпилированный BAML извлекается и используется для регенерации пользовательского интерфейса.

 





©2015 www.megapredmet.ru Все права принадлежат авторам размещенных материалов.