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

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

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

  • Обработчики XAML и расширения разметки
  • Базовый синтаксис расширения разметки
  • Расширения разметки, определенные XAML
  • Расширения разметки, характерные для WPF
  • Классы *Extension
  • Escape-последовательности и расширения разметки
  • Использование вложенных расширений разметки в языке XAML
  • Расширения разметки и синтаксис элементов свойств
  • Связанные разделы

Обработчики XAML и расширения разметки

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

Базовый синтаксис расширения разметки

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

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

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

Расширения разметки, определенные XAML

Существует несколько расширений разметки, не относящихся к реализации WPF языка XAML, которые, тем не менее, являются реализациями функций языка XAML. Эти расширения разметки реализованы в сборке System.Xaml как часть общих служб XAML платформы .NET Framework, и они находятся в пространстве имен XAML языка XAML. В обычном синтаксисе разметки эти расширения обычно распознаются по префиксу x:. Базовый класс MarkupExtension (также определенный в сборке System.Xaml) содержит шаблон, который должны использовать все расширения разметки, чтобы быть поддерживаемыми средствами чтения и записи XAML, в том числе WPF XAML.

  • Сопоставление x:Type предоставляет объект Type для именованного типа. Это средство наиболее часто используется в стилях и шаблонах. Дополнительные сведения см. в разделе Расширение разметки x:Type.

  • Расширение x:Static создает статические значения. Эти значения поступают из сущностей кода типа значения, которые непосредственно не принадлежат к типу значения целевого свойства, но могут быть приведены к этому типу. Дополнительные сведения см. в разделе Расширение разметки x:Static.

  • Расширение x:Null задает null в качестве значения свойства, которое можно использовать для значений атрибутов или элементов свойств. Дополнительные сведения см. в разделе Расширение разметки x:NULL.

  • Расширение x:Array обеспечивает поддержку создания общих массивов в синтаксисе XAML для случаев, когда поддержка коллекций, предоставляемая базовыми элементами WPF и моделями элементов управления, намеренно не используется. Дополнительные сведения см. в разделе Расширение разметки x:Array.

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

Префикс x: используется для обычного сопоставления пространства имен XAML встроенных функций языка XAML в корневом элементе файла или производственного приложения XAML.Например, шаблоны Visual Studio для приложений WPF инициируют файл XAML с помощью сопоставления x:.Можно выбрать другой токен префикса в собственном сопоставлении пространства имен XAML, но в этой документации предполагается использование сопоставления x: по умолчанию как средство идентификации сущностей, которые являются определенной частью пространства имен XAML, в отличие от пространства имен WPF по умолчанию или других пространств имен XAML, не связанных с определенной платформой.

Расширения разметки, характерные для WPF

Наиболее распространенными расширениями разметки, используемыми при программировании WPF, являются расширения, которые поддерживают ссылки на ресурсы (StaticResource и DynamicResource) и расширения, поддерживающие привязку к данным (Binding).

  • StaticResource предоставляет значение свойства, замещая значение уже определенного ресурса. В конечном итоге обработка ресурса StaticResource выполняется во время загрузки XAML, и она не имеет доступа к графу объектов во время выполнения. Дополнительные сведения см. в разделе Расширение разметки StaticResource.

  • DynamicResource предоставляет значение свойства в виде ссылки на ресурс, отложенной до времени выполнения. Ссылка на динамический ресурс принудительно инициирует новый поиск при каждом случае доступа к такому ресурсу и обладает доступом к графу объектов во время выполнения. Чтобы обеспечить этот доступ, реализована поддержка понятия DynamicResource свойствами зависимостей в системе свойств WPF и обрабатываемых выражений. Поэтому DynamicResource можно использовать только для целевого объекта свойства зависимостей. Дополнительные сведения см. в разделе Расширение разметки DynamicResource.

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

  • RelativeSource предоставляет сведения об источнике объекта Binding, который может использовать несколько возможных связей в дереве объектов среды выполнения. Это обеспечивает специализированные источники для привязок, которые создаются в шаблонах для повторного использования или в коде без полных сведений об окружающем дереве объектов. Дополнительные сведения см. в разделе Расширение разметки RelativeSource.

  • TemplateBinding позволяет шаблону элемента управления использовать значения шаблонных свойств, получаемых из определенных объектной моделью свойств класса, который будет использовать шаблон. Другими словами, свойства в определении шаблона может получить доступ к контексту, которые существует только после применения шаблона. Дополнительные сведения см. в разделе Расширение разметки TemplateBinding. Дополнительные сведения об использовании TemplateBinding на практике см. в разделе Пример "Styling with ControlTemplates".

  • ColorConvertedBitmap поддерживает сравнительно сложный вариант обработки изображений. Дополнительные сведения см. в разделе Расширение разметки ColorConvertedBitmap.

  • ComponentResourceKey и ThemeDictionary поддерживают некоторые аспекты поиска ресурсов, особенно в отношении ресурсов и тем, упакованных в пользовательские элементы управления. Дополнительные сведения см. разделе Расширение разметки ComponentResourceKey, Расширение разметки ThemeDictionary или Общие сведения о разработке управления.

Классы *Extension

Как для общих расширений языка XAML, так и для расширений WPF, поведение каждого расширения разметки распознается обработчиком XAML с помощью класса *Extension, который наследует от класса MarkupExtension и обеспечивает реализацию метода ProvideValue. Этот метод в каждом расширении предоставляет объект, который возвращается при вычислении расширения разметки. Возвращаемый объект обычно вычисляется на основе различных токенов строк, передаваемых в расширение разметки.

Например, класс StaticResourceExtension предоставляет поверхностную реализацию фактического поиска ресурса, чтобы реализация его метода ProvideValue возвращала запрошенный объект. При этом в входными данными этой конкретной реализации является строка, используемая для поиска ресурса по его сопоставлению x:Key. Большая часть подробностей этой реализации неважна при использовании существующего расширения разметки.

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

Шаблон именования *Extension призван обеспечить удобство и однородность. Для того чтобы обработчик XAML распознал класс как поддерживающий расширения разметки, не обязательно использовать этот шаблон именования. Если база кода включает сборку System.Xaml и использует реализации служб XAML платформы .NET Framework, для распознавания расширения разметки XAML достаточно обеспечить наследование от класса MarkupExtension и поддержку синтаксиса конструктора. В WPF определены классы, обеспечивающие поддержку расширений разметки, которые не соответствуют шаблону именования *Extension, например Binding. Причина этого, как правило, состоит в том, что такие классы поддерживают более широкие сценарии, чем только поддержка расширений разметки. В частности, класс Binding поддерживает доступ к методам и свойствам объекта во время выполнения для сценариев, которые не имеют ничего общего с XAML.

Интерпретация текста инициализации класса Extension

Токены строки, следующие за именем расширения разметки и по-прежнему заключенные в фигурные скобки, интерпретируются обработчиком XAML одним из указанных ниже способов.

  • Запятая всегда представляет разделитель отдельных лексем.

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

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

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

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

  • Если имеется параллельный результат между поведением конструктора и поведением установки свойства в расширении разметки, не имеет значения, какое поведение использовать. Обычно пары свойство=значение используются для расширений разметки, которые имеют несколько устанавливаемых свойств, поскольку это делает разметку более продуманной и уменьшает вероятность случайной перестановки мест параметров конструктора (когда указываются пары "свойство=значение", эти свойства могут быть в любом порядке). Кроме того, нет никакой гарантии, что расширение разметки предоставляет параметр конструктора, который задает каждое из его устанавливаемых свойств. Например, Binding является расширением разметки с несколькими свойствами, которые задаются с помощью расширения в форме свойство=значение, однако Binding поддерживает только два конструктора: конструктор по умолчанию и конструктор, который задает начальный путь.

  • Знак запятой нельзя передать расширению разметки, не преобразовав его в escape-последовательность.

Escape-последовательности и расширения разметки

Средства обработки атрибутов в обработчике XAML расценивают фигурные скобки как указание на последовательность расширения разметки. Также, возможно, понадобится создать значение атрибута, содержащее литеральную фигурную скобку. Для этого необходимо ввести escape-последовательность, которая представляет собой пустую пару фигурных скобок, следующую за литеральной фигурной скобкой. См. раздел Escape-последовательность/расширение разметки {}.

Использование вложенных расширений разметки в языке XAML

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

  <Setter Property="Background"
    Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />

В этом коде сначала вычисляется оператор x:Static, который возвращает строку. Затем эта строка используется в качестве аргумента для оператора DynamicResource.

Расширения разметки и синтаксис элементов свойств

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

Большинство расширений разметки при использовании в синтаксисе элемента объекта для заполнения элемента свойства не будет иметь содержимого или какого-либо последующего синтаксиса элемента свойства. Таким образом, будет закрыт тег элемента объекта, и дочерние элементы не будут предоставлены. Всякий раз, когда обработчик XAML обнаруживает элемент объекта, вызывается конструктор класса для создания экземпляра объекта, созданного из проанализированного элемента. Класс расширения разметки не отличается: при необходимости использования расширения разметки в синтаксисе элемента объекта нужно предоставить конструктор по умолчанию. Некоторые существующие расширения разметки имеют по крайней мере одно обязательное значение свойства, которое должно быть указано для действительной инициализации. В таком случае это значение обычно передается в качестве атрибута свойства элемента объекта. На страницах Возможности пространства имен языка XAML (x:) и Расширения XAML WPF описаны расширения разметки, имеющие обязательные свойства (и имена обязательных свойств). На этих страницах также указано, разрешен ли для конкретных расширений разметки синтаксис элемента объекта или синтаксис атрибута. Важным случаем является расширение Расширение разметки x:Array, которое не поддерживает синтаксис атрибута, так как содержимое этого массива должно быть указано в качестве содержимого внутри тегов. Содержимое массива обрабатывается как общие объекты, поэтому не существует реального преобразователя типа по умолчанию для атрибута. Кроме того, для Расширение разметки x:Array требуется параметр type.

См. также

Ссылки

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

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

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

Расширение разметки x:Type

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

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

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

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

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