Главная » WPF » Краткое знакомство с моделью программирования XAML

0

Одна  из основных  и часто  неправильно понимаемых  особенностей  каркаса

.NET 3.0 – новая модель программирования XAML. Язык XAML обладает допол# нительной по сравнению с XML семантикой,  которая допускает единую интерп# ретацию. Слегка упрощая, можно сказать, что XAML – это основанный на XML сценарный язык для создания объектов CLR. Имеется соответствие межу XML# тегами и типами CLR, а также между XML#атрибутами и свойствами  и события# ми CLR. В следующем примере показано, как создать объект и присвоить  значе# ние его свойству на языках XAML и C#:

<!— версия на XAML —>

<MyObject

SomeProperty=’1’ />

// версия на C#

MyObject obj = new MyObject();

obj.SomeProperty = 1;

XML#теги всегда определяются в контексте  некоторого  пространства имен, которое и описывает, какие теги являются допустимыми. В XAML пространства имен в смысле XML отображаются на наборы пространств имен и сборок в смыс# ле CLR. Чтобы приведенный выше простой пример заработал, необходимо уста# новить соответствие  между требуемыми  пространствами имен. В XML для опре# деления новых пространств имен применяется атрибут xmlns:

<!— версия для XAML —>

<MyObject

xmlns=’clr namespace:Samples’ SomeProperty=’1’ />

// версия для C#

using Samples;

MyObject obj = new MyObject();

obj.SomeProperty = 1;

В C# перечень сборок, в которых находятся  используемые типы, всегда зада# ется в файле проекта или с помощью аргументов  командной  строки для запуска компилятора csc.exe. В XAML можно определить  местоположение исходной сборки для каждого пространства имен:

<!— версия для XAML —>

<MyObject

xmlns=’clr namespace:Samples;assembly=samples.dll’ SomeProperty=’1’ />

// версия для C#

csc /r:samples.dll test.cs using Samples;

MyObject obj = new MyObject();

obj.SomeProperty = 1;

В XML мир разбит на две половины: элементы и атрибуты. Модель XAML бо# лее тесно связана с CLR, поскольку  апеллирует  к объектам, свойствам и событи# ям. Значения свойств  можно представлять в виде атрибутов  или дочерних  эле# ментов. Предыдущий пример допустимо записать и так:

<MyObject

xmlns=’clr namespace:Samples;assembly=samples.dll’>

<MyObject.SomeProperty>

1

</MyObject.SomeProperty>

</MyObject>

Каждый  элемент, соответствующий свойству, квалифицируется типом, кото# рому это свойство принадлежит. Предположим, например, что есть еще одно свойство, значением  которого является объект типа Person со свойствами FirstName и LastName. На XAML можно было бы легко выразить  это соотноше# ние, воспользовавшись элементами для описания  свойств:

<MyObject

xmlns=’clr namespace:Samples;assembly=samples.dll’>

<MyObject.Owner>

<Person FirstName=’Chris’ LastName=’Anderson’ />

</MyObject.Owner>

</MyObject>

XAML проектировался как язык  разметки,  тесно интегрированный с CLR и обеспеченный развитой  инструментальной поддержкой.  Дополнительно стави# лась цель  создать  такой  формат,  который  было бы легко  читать  и записывать. Может  показаться,  что проектировать свойство  платформы, которое  оптимизи# ровано  прежде  всего для  инструментов, а лишь  потом  для  людей, не слишком вежливо,  но команда WPF полагала, что приложения для WPF как правило  бу# дут  создавать  с помощью  таких  программ  визуального конструирования, как Microsoft Visual Studio или Microsoft Expression. Чтобы граница между инстру# ментами  и людьми не была непроходимой, WPF позволяет  автору типу опреде# лить одно свойство как контентное.2

В примере  выше, если сделать свойство  Owner  типа MyObject контентным3, то в разметке можно будет опустить тег элемента, соответствующего этому свой# ству:

<MyObject

xmlns=’clr namespace:Samples;assembly=samples.dll’>

<Person FirstName=’Megan’ LastName=’Anderson’ />

</MyObject>

Чтобы воспринимать текст было еще удобнее, в XAML есть возможность расширения разметки.  Это общий способ расширить  синтаксический анализа# тор языка  с целью создания  более простой  разметки.  Расширения реализуют# ся в виде типов CLR и работают почти так же, как атрибуты  CLR. Они заклю# чаются в фигурные  скобки { }. Например, чтобы присвоить  свойству специаль# ное значение  null, можно воспользоваться встроенным  расширением разметки Null:

2 Это аналог «свойства по умолчанию» в Visual Basic.

3 Для этого следует добавить атрибут System.Windows.Markup.ContentPropertyAttribute в определение типа.

<MyObject

xmlns=’clr namespace:Samples;assembly=samples.dll’>

<Person FirstName=’Megan’ LastName=’{x:Null}’ />

</MyObject>

В таблице 1.1 перечислены  все встроенные  расширения XAML.

Таблица 1.1. Встроенные расширения XAML

Пространство имен XAML

Назначение

Пример

x:Array

Создает массив CLR

<x:Array Type=’{x:Type

Button}’>

<Button />

<Button />

</x:Array>

x:Class

Задает имя определяемого типа (используется только при компиляции

разметки)

<Window x:Class=’MyNamespace.MyClass

’>…

</Window>

X:ClassModifier

Задает  модификаторы определяемого типа («public» «internal» и т.д.) (используется только при компиляции разметки)

<Window x:Class=’…’

x:ClassModifier=’Public’>

</Window>

x:Code

Ограничивает блок встроенного  кода (используется только при компиляции разметки)

<Window x:Class=’…’>

<x:Code>

public void DoSomething()

{

}

</x:Code>

</Window>

x:Key

Задает  ключ элемента (поддерживается только для элементов, содержащихся в словарях)

<Button>

<Button.Resources>

<Style x:Key=’Hi’>…</Style>

</Button.Resources>

</Button>

x:Name

Задает  имя элемента для ссылки на него в программе (обычно используется, когда у элемента нет встроенного свойства name)

<<sys:Int32

xmlns:sys=’clr namespace: System;…’

x:Name=’_myIntegerValue’>

5</sys:Int32>

x:Null

Создает значение

null. <Button

Content=’{x:Null}’ />

x:Static

Создает значение путем доступа к статическому полю или свойству типа.

<Button

Command=’{x:Static

ApplicationCommands.Close}’ />

x:Subclass

Предоставляет базовый тип для компиляции разметки  на язык, в котором не поддерживаются частичные типы.

x:Type

Предоставляет тип CLR (эквивалент Type.GetType).

<ControlTemplate

TargetType=’{x:Type

Button}’>

</ControlTemplate>

x:TypeArguments

Задает  обобщенные аргументы типа для создания  экземпляра обобщенного типа.

<gc:List xmlns:gc=’clrnamespace: System.Collections. Generic;…’

x:TypeArguments

=’{x:Type Button}’ /> x:XData

Ограничивает блок встроенного  XML; может использоваться только для свойств типа IXmlSerializable.

<XmlDataSource>

<x:XData>

<Book xmlns=’’ Title=’…’

/>

</x:XData>

</XmlDataSource>

Расширения разметки ищутся точно так же, как теги объектов, то есть необходи# мо объявить  XML#префикс «x», иначе синтаксический анализатор выдаст ошибку. В языке XAML определено специальное пространство  имен для встроенных типов:

<MyObject xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’ xmlns=’clr namespace:Samples;assembly=samples.dll’>

<Person FirstName=’Megan’ LastName=’{x:Null}’ />

</MyObject>

Кроме того, для любой сборки CLR (или набора таких сборок) можно опреде# лить имя, построенное по принципу  URI и соответствующее  пространствам имен и сборок CLR. Это можно считать  эквивалентом старого доброго предложения

#include ‘windows.h’, которое хорошо известно программистам на C/C++. В сбор# ках WPF этот механизм  применяется, поэтому для импорта WPF в XAML#файл можно использовать любой формат:

<!— вариант 1: импорт по пространству имен CLR —>

<Window xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’ xmlns=

namespace:System.Windows;assembly=presentationframework.dll’>

</Window>

‘clr

<!— вариант 2: импорт по URI —>

<Window xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’ xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’>

</Window>

Метод с применением синтаксиса  URI  хорош тем, что импортируются сразу несколько  пространств имен и сборок CLR, а, значит, разметка получается  более компактной и работать с ней проще.

И последнее, что я хотел сказать о XAML, – это возможность расширять типы за счет свойств, предоставляемых другими типами. Такие присоединенные свой# ства – это просто безопасный  относительно типов вариант  добавленных  свойств (expando  properties) в языке  JavaScript. В версии  XAML, предназначенной для WPF,  присоединенные свойства работают только, если и тип, в котором свойство определено, и тип, к которому оно присоединяется, наследуют классу DependencyObject. Однако в общей спецификации XAML такого требования нет.

В следующем примере  свойство Dock определено  в типе DockPanel. Присое# диненному  свойству  всегда предшествует  имя предоставляющего его типа, даже если такое свойство употребляется в качестве атрибута:

<Window xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’ xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’>

<DockPanel>

<Button DockPanel.Dock=’Top’>Top</Button>

<Button>

<DockPanel.Dock>Left</DockPanel.Dock> Left

</Button>

<Button>Fill</Button>

</DockPanel>

</Window>

XAML – довольно простой язык, в нем не очень много правил. В версии, ко# торая поставляется в составе .NET Framework 3.0, все определения тегов XAML реализованы в виде типов CLR. Поэтому все, что можно сделать с помощью раз# метки, можно написать и в виде компилируемой программы. В этой книге я буду иногда пользоваться разметкой4,  а иногда кодом в зависимости от того, как про# ще проиллюстрировать ту или иную идею.

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

Источник: К. Андерсон  Основы  Windows Presentation Foundation. Пер. с англ. А. Слинкина — М.: ДМК Пресс, 2008 — 432 с.: ил.

По теме:

  • Комментарии