Подробное описание синтаксиса XAML

В этом разделе определяются термины, которые используются для описания элементов синтаксиса XAML. Эти термины часто используются в данном документе, в особенности в документации по WPF, но также и по другим платформам, в которых используются язык XAML и базовые понятия XAML, поддержка которых реализована за счет поддержки языка XAML на уровне System.Xaml. Этот раздел расширяет базовую терминологию, представленную в разделе Общие сведения о языке XAML (WPF).

В этом разделе содержатся следующие подразделы.

  • Спецификация XAML (общеязыковая спецификация)
  • Язык XAML и среда CLR
  • Синтаксис объектного элемента
  • Свойства элементов объекта
  • Синтаксис атрибутов (свойства)
  • Синтаксис элемента свойства
  • Синтаксис коллекции
  • Свойства содержимого XAML
  • Объединение свойств содержимого и синтаксиса коллекции
  • Пространства имен XAML
  • Расширения разметки
  • Вложенные свойства
  • Вложенные события
  • Составляющие корневого элемента XAML
  • Необязательное и не рекомендуемое использование XAML
  • Связанные разделы

Спецификация XAML (общеязыковая спецификация)

Терминология синтаксиса XAML, определенная здесь, также определяется или упоминается в разделе об общеязыковой спецификации XAML. Язык XAML основан на XML и следует структурным правилам XML или расширяет их. Часть терминологии является общей или базируется на терминологии, обычно используемой при описании языка XML или модели объектов документов XML.

Дополнительные сведения об общеязыковой спецификации XAML см. в документе [MS-XAML], который можно скачать в Центре загрузки Майкрософт.

Язык XAML и среда CLR

XAML является языком разметки. common language runtime (CLR), как следует из названия, обеспечивает выполнение среды выполнения. XAML сам по себе не является одним из общих языков, который напрямую используется средой выполнения CLR. Вместо этого язык XAML можно представить себе поддерживающим свою собственную систему типов. Особая система анализа XAML, используемая WPF, построена на среде CLR и системе типов среды CLR. Типы XAML сопоставляются с типами среды CLR для создания представления времени выполнения, когда язык XAML анализируется для WPF. Поэтому оставшаяся часть обсуждения синтаксиса в этом документе будет содержать отсылки к системе типов среды CLR, несмотря на то что такие же обсуждения синтаксиса в разделе об общеязыковой спецификации XAML их не содержат. (Согласно уровню общеязыковой спецификации XAML, типы XAML могут быть сопоставлены с любой другой системой типов, которая не обязательно является системой CLR, но для которой требуется создание и использование другого средства синтаксического анализа XAML.)

Члены типов и наследование классов

Свойства и события, отображающиеся как XAML-члены типа WPF, часто наследуются от базовых типов. Рассмотрим, например, следующий фрагмент кода: <Button Background="Blue" .../>. Если вы посмотрите на определение класса, результаты отражения или документацию, вы увидите, что свойство Background не является непосредственно объявленным свойством класса Button. Вместо этого класс Background наследуется от базового класса Control.

Поведение наследования классов XAML-элементов в WPF является серьезным отступлением от основанной на схеме интерпретации разметки XML. Механизм наследования классов может быть довольно сложным, в особенности если промежуточные базовые классы являются абстрактными и в случаях с интерфейсами. Это одна из причин того, что набор элементов XAML и их допустимых атрибутов очень сложно точно и полно представить с помощью типов схемы, которые обычно используются в программировании XML, как, например, форматы DTD и XSD. Другая причина заключается в том, что функции расширяемости и сопоставления типов языка XAML препятствуют полноте представления допустимых типов и членов.

Синтаксис объектного элемента

Object element syntax является синтаксисом разметки XAML, который создает класс или структуру CLR, объявляя элемент XML. Этот синтаксис похож на синтаксис элементов других языков разметки, например HTML. Синтаксис элемента объекта начинается с левой угловой скобки (<), за которой следует непосредственно имя типа создаваемого класса или структуры. После имени типа может следовать несколько пробелов, а также может быть объявлено несколько атрибутов для элемента объекта с одним или несколькими пробелами, отделяющими каждую пару "имя="значение"". Наконец, должно выполняться одно из следующих условий.

  • Элемент и тег должны быть закрыты косой чертой (/), стоящей непосредственно перед правой угловой скобкой (>).

  • Открывающий тег должен быть закрыт правой угловой скобкой (>). За открывающим тегом могут следовать другие элемента объектов, элементы свойств или внутренний текст. Содержимое, которое может здесь размещаться, обычно ограничивается объектной моделью элемента. Также для элемента объекта обязательно должен присутствовать эквивалентный закрывающий тег при правильном вложении и балансе с другими открывающими и закрывающими парами тегов.

В языке XAML, реализованном в .NET, есть набор правил, которые сопоставляют элементы объекта с типами, атрибуты со свойствами или событиями, а пространства имен XAML — с пространствами имен среды CLR и сборкой. В случае с WPF и .NET Framework, элементы объекта XAML сопоставляются с типами Microsoft .NET, как указано в ссылочных сборках, а атрибуты — с членами этих типов. Если вы ссылаетесь на тип среды CLR в XAML, вы также получаете доступ к унаследованным членам этого типа.

В следующем примере показан синтаксис элемента объекта, который создает новый экземпляр класса Button, а также определяет атрибут Name и значение этого атрибута:

<Button Name="CheckoutButton"/>

В следующем примере показан синтаксис элемента объекта, который также включает синтаксис свойства содержимого языка XAML. Содержащийся внутри текст будет использоваться для задания свойства содержимого XAML TextBox, Text.

<TextBox>This is a Text Box</TextBox>

Модели содержимого

Класс может поддерживать использование в качестве элемента объекта XAML в рамках синтаксиса, но этот элемент будет работать должным образом в приложении или на странице только при его помещении в ожидаемое положение в общей модели содержимого или в дереве элементов. Например, MenuItem обычно может быть помещен только в качестве дочернего элемента класса, производного от MenuBase, например, Menu. Модели содержимого для определенных элементов описаны в документации как часть примечаний на страницах класса для элементов управления и других классов WPF, которые могут использоваться как элементы XAML.

Свойства элементов объекта

Свойства в XAML задаются набором возможных синтаксисов. Какой именно синтаксис может быть использован для данного свойства, определяется в зависимости от системных характеристик задаваемого свойства базового типа.

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

Синтаксис атрибутов (свойства)

Синтаксис атрибутов является синтаксисом разметки XAML, который задает значение свойства посредством объявления атрибута в элементе существующего объекта. Имя атрибута должно соответствовать имени члена среды CLR, принадлежащего свойству класса, который поддерживает значимый элемент объекта. Имя атрибута находится перед оператором присвоения (=). Значение атрибута должно быть строкой, заключенной в двойные кавычки ('').

ПримечаниеПримечание

Вы можете использовать разные кавычки, чтобы поместить литеральные кавычки внутрь атрибута.Например, вы можете использовать одинарные кавычки для объявления строки, которая содержит знак двойных кавычек.Независимо от того, используете вы одинарные или двойные кавычки, следует использовать одинаковые кавычки для открытия и закрытия строки значения атрибута.Также можно использовать escape-последовательности и другие методы, позволяющие обойти ограничения, обусловленные особенностями синтаксиса XAML.Дополнительные сведения см. в разделе Сущности знаков XML и XAML.

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

Что касается событий WPF XAML, если событие указано как имя атрибута, оно должно быть открытым и иметь открытый делегат.

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

Обработка значений атрибутов

Строковое значение, содержащееся в открывающих и закрывающих кавычках, обрабатывается обработчиком XAML. Поведение обработчика по умолчанию для свойств определяется типом базового свойства среды CLR.

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

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

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

  3. Если преобразователь TypeConverter не существует, выполняется попытка прямого преобразования в тип свойства. Последним уровнем является прямое преобразование между примитивными типами языка XAML при собственном значении синтаксического анализатора или проверка имен именованных констант в перечислении (после которой синтаксический анализатор обращается к значениям, для которых обнаружено соответствие).

Значения атрибутов перечисления

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

Для значений перечисления nonflag собственное поведение состоит в обработке строки значения атрибута и разрешении его в одно из значений перечисления. Не задавайте перечисление в формате Перечисление.Значение, как в коде. Вместо этого укажите только Значение, а Перечисление неявно определяется типом задаваемого свойства. Если указать атрибут в форме Перечисление.Значение, он будет разрешен неправильно.

Для перечислений flagwise поведение основано на методе Enum.Parse. Можно указать несколько значений для перечисления flagwise, разделяя каждое значение запятой. Однако нельзя объединять значения перечисления, которые не являются flagwise. Например, нельзя использовать синтаксис с запятой, чтобы попытаться создать объект Trigger, обрабатывающий несколько условий перечисления nonflag:

<!--This will not compile, because Visibility is not a flagwise enumeration.-->
...
<Trigger Property="Visibility" Value="Collapsed,Hidden">
  <Setter ... />
</Trigger>
...

Перечисления flagwise, которые поддерживают атрибуты, устанавливаемые в XAML, очень редко встречаются в приложении WPF. Однако одним таким перечислением является StyleSimulations. Можно, например, использовать синтаксис атрибутов flagwise, разделенных запятой, чтобы изменить пример из раздела "Примечания" для класса Glyphs; атрибут StyleSimulations = "BoldSimulation" может стать свойством StyleSimulations = "BoldSimulation,ItalicSimulation" . KeyBinding.Modifiers является другим свойством, где можно указать несколько значений перечисления. Однако это свойство является особым случаем, поскольку перечисление ModifierKeys поддерживает свой собственный преобразователь типов. В качестве разделителя преобразователь типов использует знак плюс (+) вместо запятой (,). Это преобразование поддерживает традиционный синтаксис обозначения сочетаний клавиш, используемый в программировании под Microsoft Windows, например "Ctrl+Alt".

Ссылки на имя члена свойства и события

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

Можно также ссылаться на вложенное свойство или событие, независимо от содержащего элемента объекта. (Вложенные свойства обсуждаются в следующем разделе.)

Кроме того, можно задать имя любого события из любого объекта, доступного через пространство имен по умолчанию, используя частично полное имя typeName.event; этот синтаксис поддерживает присоединение обработчиков для перенаправленных событий, где обработчик предназначен для обработки перенаправления событий из дочерних элементов, но родительский элемент не имеет это событие в своей таблице элементов. Этот синтаксис напоминает синтаксис вложенного события, но в данном случае событие не является истинным вложенным событием. Вместо этого осуществляется ссылка на событие с полным именем. Дополнительные сведения см. в разделе Общие сведения о перенаправленных событиях.

В некоторых случаях имена свойств предоставляются как значение по умолчанию для атрибута, а не как имя атрибута. Такое имя свойства также может содержать квалификаторы, например свойства, указанные в формате ownerType.dependencyPropertyName. Этот сценарий является наиболее распространенным при написании стилей или шаблонов на языке XAML. Правила обработки имен свойств, предоставленных в виде значения атрибута, различны; они регулируются типом свойства, задаваемого поведением определенных подсистем WPF. Дополнительные сведения см. в разделе Стилизация и использование шаблонов.

Другим использованием имен свойств является описание значением атрибута отношения "свойство-свойство". Эта функция используется для привязки данных и раскадровки целей и активируется классом PropertyPath и его преобразователем типов. Более полное описание семантики поиска см. в разделе Синтаксис PropertyPath XAML.

Синтаксис элемента свойства

Синтаксис элемента свойства является синтаксисом, который несколько отличается от правил для элементов в базовом синтаксисе XML. В XML значение атрибута фактически является строкой, где единственно возможной переменной является используемый формат кодировки строки. В XAML можно назначить другие элементы объектов, которые будут значениями свойства. Эта возможность поддерживается синтаксисом элемента свойства. Вместо свойства, указанного как атрибут в теге элемента, свойство задается с помощью открывающего тега элемента в форме elementTypeName.PropertyName, в ней указывается значение свойства и затем закрывается элемент свойства.

Этот синтаксис начинается с левой угловой скобки (<), за которой непосредственно следует имя типа класса или структуры, в котором содержится синтаксис элемента свойства. Затем следует одна точка (.), следом имя свойства и закрывающая угловая скобка (>). Как и в случае с синтаксисом атрибута, это свойство должно существовать среди объявленных открытых членов указанного типа. Значение, присваиваемое свойству, содержится в элементе свойства. Обычно значение дается в качестве одного или нескольких элементов объекта, поскольку указание объектов как значений является скриптом, для которого в первую очередь предназначен синтаксис элемента свойства. Наконец, должен присутствовать эквивалентный закрывающий тег, определяющий то же сочетание elementTypeName.propertyName, при правильном вложении и балансе с другими тегами элемента.

Например, ниже приведен синтаксис элемента свойства ContextMenu объекта Button.

<Button>
  <Button.ContextMenu>
    <ContextMenu>
      <MenuItem Header="1">First item</MenuItem>
      <MenuItem Header="2">Second item</MenuItem>
    </ContextMenu>
  </Button.ContextMenu>
  Right-click me!</Button>

Значение внутри элемента свойства также может быть задано как внутренний текст там, где тип свойства указывается как примитивный тип значения, такой как String, или как перечисление, в котором указано имя. Эти два варианта использования довольно редки, так как в каждом из этих случаев может использоваться более простой синтаксис атрибута. Один сценарий заполнения элемента свойства строкой предназначен для свойств, которые не являются свойствами содержимого XAML, но по-прежнему используются для представления текста пользовательского интерфейса и отдельных элементов пробелов, таких как символов перевода строк, необходимых в тексте пользовательского интерфейса. Синтаксис атрибута не может сохранять символы переноса строк, но синтаксис элемента свойства — может, если активно сохранение значимых пробелов (подробные сведения содержатся в разделе Обработка пробелов в XAML). Другой возможный вариант заключается в том, что Директива x:Uid можно применить к элементу свойства, отметив таким образом содержащееся в нем значение как локализуемое в выходных данных WPF на языке BAML или с помощью других методов.

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

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

Синтаксис коллекции

Спецификация XAML требует реализаций обработчиков XAML для возможности определения свойств, где типом значения является коллекция. Реализация общего обработчика XAML в платформе .NET основана на управляемом коде и среде CLR. Этот обработчик определяет типы коллекций одним из следующих способов.

Если тип свойства является коллекцией, тогда неявно определяемый тип коллекции не требуется указывать в разметке как элемент объекта. Вместо этого элементы, которые должны стать единицами коллекции, указываются в виде одного или нескольких дочерних элементов элемента свойства. Каждый такой элемент во время загрузки приводится к объекту и добавляется в коллекцию с помощью вызова метода Add неявной коллекции. Например, свойство Triggers объекта Style получает специализированный тип коллекции TriggerCollection, который реализует IList. Однако не обязательно создавать элемент объекта TriggerCollection в разметке. Вместо этого укажите один или несколько элементов Trigger в качестве элементов в элементе свойства Style.Triggers, где Trigger (или производный класс) является ожидаемым типом элемента для типобезопасного и неявного класса TriggerCollection.

<Style x:Key="SpecialButton" TargetType="{x:Type Button}">
  <Style.Triggers>
    <Trigger Property="Button.IsMouseOver" Value="true">
      <Setter Property = "Background" Value="Red"/>
    </Trigger>
    <Trigger Property="Button.IsPressed" Value="true">
      <Setter Property = "Foreground" Value="Green"/>
    </Trigger>
  </Style.Triggers>
</Style>

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

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

ПримечаниеПримечание

Определение коллекций с помощью универсальных интерфейсов списка и словаря (IList<T> и IDictionary<TKey, TValue>) не поддерживается.Тем не менее можно использовать класс List<T> как базовый класс, так как он непосредственно реализует IList или Dictionary<TKey, TValue> как базовый класс, потому что он непосредственно реализует IDictionary.

В ссылочных страницах .NET для типов коллекции этот синтаксис с намеренным опущением элемента объекта для коллекции иногда отмечен в разделах синтаксиса XAML как синтаксис неявных коллекций.

За исключением корневого элемента, каждый элемент объекта в файле XAML, вложенный как дочерний элемент другого элемента, на самом деле является элементом одной из следующих категорий: член неявного свойства коллекции для родительского элемента или элемент, указывающий значение свойства содержимого XAML для родительского элемента (свойства содержимого XAML рассмотрены в следующем разделе). Другими словами, связь родительских и дочерних элементов на странице разметки является одним объектом в корне, и каждый объектный элемент ниже корня является одним экземпляром, предоставляющим значение свойства родительского элемента, или одним из элементов в коллекции, также являющейся значением свойства типа коллекции для родительского элемента. Этот принцип единого корня повсеместно используется в XML-коде, и зачастую он принудительно обеспечивается в интерфейсах API, загружающих XAML-код, таких как Load.

Следующий пример является синтаксисом с явно заданным элементом объекта для (GradientStopCollection).

<LinearGradientBrush>
  <LinearGradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Offset="0.0" Color="Red" />
      <GradientStop Offset="1.0" Color="Blue" />
    </GradientStopCollection>
  </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

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

Свойства содержимого XAML

Синтаксис содержимого XAML является синтаксисом, который возможен только для классов, для которых задан ContentPropertyAttribute в качестве их объявления класса. ContentPropertyAttribute дает ссылку на имя свойства, которое является свойством содержимого для этого типа элементов (включая производные классы). При обработке обработчиком XAML все дочерние элементы или внутренний текст, найденные между открывающим и закрывающим тегами элемента объекта, будут заданы как значение свойства содержимого XAML для этого объекта. Вы можете задать явные элементы свойства для свойства содержимого, но это использования обычно не показано в разделах о синтаксисе XAML в справочном материале .NET. Явный/словесный метод имеет случайное значение, чтобы внести ясность в разметку или указать ее стиль, но обычно целью свойства содержимого является упрощение разметки, чтобы можно было непосредственно вложить элементы, интуитивно связанные отношением "родительский-дочерний". Теги элемента свойства для других свойств в элементе не заданы как "содержимое" согласно строгому определению в языке XAML; они в первую очередь обрабатываются в рабочем потоке синтаксического анализатора XAML и не рассматриваются как "содержимое".

Значения свойств содержимого XAML должны быть непрерывными

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

<Button>I am a 
  <Button.Background>Blue</Button.Background>
  blue button</Button>

Это неверно, поскольку если бы этот синтаксис был явным с использованием синтаксиса элементов свойств для свойства содержимого, то свойство содержимого было бы задано дважды:

<Button>
  <Button.Content>I am a </Button.Content>
  <Button.Background>Blue</Button.Background>
  <Button.Content> blue button</Button.Content>
</Button>

Аналогично неверным примером является случай, когда свойство содержимого представляет собой коллекцию, и дочерние элементы перемежаются элементами свойств:

<StackPanel>
  <Button>This example</Button>
  <StackPanel.Resources>
    <SolidColorBrush x:Key="BlueBrush" Color="Blue"/>
  </StackPanel.Resources>
  <Button>... is illegal XAML</Button>
</StackPanel>

Объединение свойств содержимого и синтаксиса коллекции

Чтобы принимать несколько элементов объекта в качестве содержимого, тип свойства содержимого обязательно должен быть типом коллекции. Аналогично синтаксису элемента свойства для типов коллекций, обработчик XAML должен идентифицировать типы, которые являются типами коллекций. Если элемент имеет свойство содержимого XAML и тип свойства содержимого XAML в коллекции, тогда предполагаемый тип коллекции не требуется указывать в разметке в качестве элемента объекта, а свойство содержимого XAML не требуется указывать в качестве элемента свойства. Поэтому видимая модель содержимого в разметке теперь может иметь несколько дочерних элементов, назначенных в качестве содержимого. Ниже приведен синтаксис содержимого производного класса Panel. Все классы, производные от Panel, определяют свойство содержимого XAML как Children, что требует значение типа UIElementCollection.

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel>
    <Button>Button 1</Button>
    <Button>Button 2</Button>
    <Button>Button 3</Button>
  </StackPanel>
</Page>

Обратите внимание, что ни элемент свойства для Children, ни элемент для UIElementCollection не являются обязательными в разметке. Эта возможность специально предусмотрена в XAML, чтобы рекурсивно содержащиеся элементы, которые определяют UI, были более понятно представлены в виде дерева вложенных элементов с прямыми связями между родительскими и дочерними элементами без лишних промежуточных тегов элемента свойства или объектов коллекции. В действительности, указание объекта UIElementCollection в разметке в качестве элемента объекта намеренно запрещено. Так как объект UIElementCollection предназначен для использования только в качестве неявной коллекции, он не предоставляет открытый конструктор по умолчанию и, таким образом, не может быть создан в качестве элемента объекта.

Смешивание элементов свойств и элементов объектов в объекте со свойством содержимого

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

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

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

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

Ни в одном из предыдущих примеров синтаксиса не указано пространство имен XAML, отличное от пространства имен XAML по умолчанию. В обычных приложениях WPF по умолчанию задано пространство имен WPF. Можно задавать другие пространства имен XAML, помимо пространства имен XAML по умолчанию, и при этом использовать аналогичный синтаксис. Впрочем, если именованный класс недоступен в пространстве имен XAML по умолчанию, перед именем этого класса должен указываться префикс пространства имен XAML, сопоставленный с соответствующим пространством имен CLR. Например, <custom:Example/> представляет собой синтаксис элемента объекта для создания экземпляра класса Example, где пространство имен CLR, содержащее этот класс (и, возможно, информация о внешней сборке, содержащей резервные типы) было предварительно сопоставлено с префиксом custom.

Дополнительные сведения о пространствах имен XAML см. в разделе Пространства имен XAML и сопоставление пространств имен для WPF XAML.

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

XAML определяет программную сущность расширения разметки, которая позволяет выйти за рамки обычной обработки строковых атрибутов или элементов объектов процессором XAML и переложить обработку на вспомогательный класс. Знаком, указывающим обработчику XAML расширение разметки при использовании синтаксиса атрибута, является открывающая фигурная скобка ({), за которой следует любой знак, отличный от закрывающей фигурной скобки (}). Первая строка, следующая за открывающей фигурной скобкой, должна ссылаться на класс, который обеспечивает отдельное поведение расширения, и в этой ссылке можно пропустить подстроку "Extension", если эта подстрока является частью истинного имени класса. После этого может использоваться один пробел, и затем каждый последующий знак используется в качестве входных данных реализации расширения, вплоть до закрывающей фигурной скобки.

В реализации языка XAML в платформе .NET абстрактный класс MarkupExtension используется как базовый класс для всех расширений разметки, поддерживаемых в WPF, а также других платформах и технологиях. Расширения разметки, реализованные в WPF, часто предназначаются для создания ссылок на другие существующие объекты или для предоставления отложенных ссылок на объекты, обрабатываемые во время выполнения. Например, простая привязка данных WPF выполняется путем указания расширения разметки {Binding} вместо типа значения, которое обычно принимает определенное свойство. Большинство расширений разметки WPF обеспечивают поддержку синтаксиса атрибута для свойств, в которых синтаксис атрибута иначе был бы невозможен. Например, объект Style представляет собой сравнительно сложный тип, содержащий серию вложенных объектов и свойств. Стили в WPF обычно определяются как ресурсы в ResourceDictionary, а затем указываются с помощью одного из двух расширений разметки WPF, запрашивающих ресурс. Расширение разметки откладывает вычисление значения свойства до выполнения поиска ресурса и включает предоставление значения свойства Style, принимающего объект типа Style, в синтаксисе атрибута следующим образом:

<Button Style="{StaticResource MyStyle}">My button</Button>

Здесь элемент StaticResource определяет класс StaticResourceExtension, предоставляющий реализацию расширения разметки. Следующая строка MyStyle используется в качестве входных данных для конструктора StaticResourceExtension, не являющегося конструктором по умолчанию, где параметр, принимаемый из строки расширения, объявляет запрашиваемый объект ResourceKey. Ожидается, что MyStyle примет значение x:Key свойства Style, объявленного ресурсом. Использование Расширение разметки StaticResource требует, чтобы ресурс использовался для предоставления значения свойства Style через логику поиска статических ресурсов во время загрузки.

Дополнительные сведения о расширениях разметки см. в разделе Расширения разметки и XAML WPF. Сведения о расширениях разметки и других функциях программирования XAML, доступных в общей реализации .NET XAML, см. в разделе Возможности пространства имен языка XAML (x:). Сведения о расширениях разметки WPF см. в разделе Расширения XAML WPF.

Вложенные свойства

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

Вложенные свойства используют синтаксис, который внешне напоминает синтаксис элемента свойства, в котором также указывается сочетание TypeName.PropertyName. Существуют два важных различия:

  • Можно использовать сочетание TypeName.propertyName даже при задании вложенного свойства через синтаксис атрибута. Если уточнение имени свойства является обязательным в синтаксисе атрибута, это можно осуществить только с помощью присоединенных свойств.

  • Можно также использовать синтаксис элемента свойства для вложенных свойств. Однако для обычного синтаксиса элемента свойства указываемое имя TypeName является элементом объекта, содержащим элемент свойства. Если указывается вложенное свойство, тогда TypeName является классом, который определяет присоединенное свойство, а не содержащий его элемент объекта.

Вложенные события

Вложенные события представляют собой другое понятие программирования, представленное в XAML. В данном случае события могут определяться конкретным типом, но обработчики могут быть присоединены к любому элементу объекта. Часто при применении WOF тип, определяющий вложенное событие, является статическим типом, определяющим службу, и иногда эти присоединенные события предоставляются с помощью псевдонимов перенаправленных событий в типах, которые предоставляют службу. Обработчики присоединенных событий задаются через синтаксис атрибута. Как и с вложенными событиями, синтаксис атрибута расширен для присоединенных событий, чтобы разрешить использование формата typeName.eventName, где typeName является классом, предоставляющим методы доступа обработчика событий Add и Remove для инфраструктуры вложенных событий, а eventName является именем события.

Составляющие корневого элемента XAML

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

<Page

Открытие объектного элемента корневого элемента

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

Пространство имен XAML по умолчанию (WPF)

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

Пространство имен языка XAML.

x:Class="ExampleNamespace.ExampleCode"

Объявление разделяемого класса, связывающее разметку с кодом программной части, определенным для этого разделяемого класса

>

Элемент окончания объекта для корневого элемента. Объект еще не закрыт, поскольку элемент содержит дочерние элементы

Необязательное и не рекомендуемое использование XAML

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

Необязательное использование элемента свойства

К необязательному использованию элементов свойств относится явное объявление свойств содержимого элементов, которые обработчик XAML рассматривает как неявные. Например, при объявлении содержимого Menu можно явно объявить коллекцию Items, относящуюся к Menu в качестве тега элемента свойства <Menu.Items> и поместить каждый элемент MenuItem в <Menu.Items>, вместо того чтобы использовать неявное поведение обработчика XAML, постулирующее, что все дочерние элементы Menu должны относиться к MenuItem и находиться в коллекции Items. Иногда необязательное использование помогает визуально уточнить объектную структуру, представленную в разметке. Или иногда использование явного элемента свойства может помочь избежать технически функциональной, но визуально непонятной разметки, например — вложенные расширения разметки в значении атрибута.

Атрибуты с указанием полного имени typeName.memberName

На самом деле формат атрибута typeName.memberName можно использовать и в более общих случаях, а не только при перенаправлении события. Однако в некоторых случаях этот формат излишен и его следует избегать (для поддержания стиля и читабельности разметки). В следующем примере каждая из трех ссылок на атрибут Background полностью эквивалентна:

<Button Background="Blue">Background</Button>
<Button Button.Background="Blue">Button.Background</Button>
<Button Control.Background="Blue">Control.Background</Button>

Ссылка Button.Background работает, поскольку полный поиск этого свойства в Button является успешным (Background был унаследован от Control) и Button является классом элемента объекта или базовым классом. Ссылка Control.Background работает, потому что класс Control на самом деле определяет Background, а Control является базовым классом Button.

Однако следующий пример формы typeName.memberName не работает, и поэтому помечен маркерами комментария:

<!--<Button Label.Background="Blue">Does not work</Button> -->

Label является другим классом, производным от Control, и если бы свойство Label.Background было указано внутри элемента объекта Label, то это использование могло бы работать. Однако, поскольку Label не является классом или базовым классом для Button, заданное поведение обработчика XAML заключается в том, чтобы обработать Label.Background как вложенное свойство. Label.Background не является доступным вложенным свойством, и такое ее применение приводит к сбою.

Элементы свойства baseTypeName.memberName

Точно так же, как форма typeName.memberName работает для синтаксиса атрибута, синтаксис baseTypeName.memberName работает для синтаксиса элемента свойства. Например, следующий синтаксис работает:

<Button>Control.Background PE
  <Control.Background>
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
    </Control.Background>
</Button>

Здесь элемент свойства задан как Control.Background, даже если элемент свойства содержится в Button.

Но так же, как форма typeName.memberName для атрибутов, форма baseTypeName.memberName является неудовлетворительным стилем в разметке, и по этой причине ее следует избегать.

См. также

Основные понятия

Общие сведения о языке XAML (WPF)

Общие сведения о свойствах зависимости

TypeConverters и XAML

Код XAML и пользовательские классы для WPF

Другие ресурсы

Возможности пространства имен языка XAML (x:)

Расширения XAML WPF