Общие сведения о расширениях разметки для XAML

Расширения разметки — это методика языка XAML для получения значения, которое не является ни примитивом, ни определенным типом XAML. Для использования атрибутов расширения разметки используют известную последовательность символов из открывающей фигурной скобки { для входа в область расширения разметки и закрывающей фигурной скобки } для выхода из нее. При использовании служб XAML .NET можно применять некоторые предопределенные расширения разметки языка XAML из сборки System.Xaml. Можно также создать подкласс из класса MarkupExtension , определенного в System.Xaml, и определить собственные расширения разметки. Или же можно использовать расширения разметки, определенные конкретной платформой, если вы уже ссылаетесь на нее.

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

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

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

Примечание.

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

x:Type

x:Type предоставляет объект Type для именованного типа. Эта функция чаще всего используется в механизмах задержки, применяющих базовый тип CLR и наследование типов в качестве моникера группирования или идентификатора. Стили и шаблоны WPF и использование ими свойств TargetType — один из примеров. Для получения дополнительной информации см. x:Type Markup Extension.

x:Static

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

x:Null

x:Null указывает null как значение для элемента XAML. В зависимости от структуры определенных типов или от более масштабных понятий платформы null не всегда является значением свойства по умолчанию или неявным значением атрибута пустой строки. Для получения дополнительной информации см. x:Null Markup Extension.

x:Array

x:Array поддерживает создание общих массивов в синтаксисе XAML, когда поддержка коллекций, предоставляемая базовыми элементами и моделями элементов управления, намеренно не используется. Для получения дополнительной информации см. x:Array Markup Extension. В частности, в XAML 2009 доступ к массивам осуществляется как к языковым примитивы, а не как к расширению. Дополнительные сведения см. в разделе XAML 2009 Language Features.

x:Reference

x:Reference — это часть XAML 2009, расширение исходного набора языков (2006). x:Reference представляет ссылку на другой существующий объект в графе объектов. Этот объект идентифицируется по x:Name. Дополнительные сведения см. в разделе x:Reference Markup Extension.

Другие конструкции x:

Существуют другие конструкции x: для поддержки возможностей языка XAML, но они не реализованы как расширения разметки. Для получения дополнительной информации см. XAML Namespace (x:) Language Features.

Базовый класс MarkupExtension

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

С помощью ProvideValue пользовательское расширение разметки получает доступ к контексту службы, который сообщает среде, где расширение разметки вызывается обработчиком XAML. В пути загрузки это обычно XamlObjectWriter. В пути сохранения это обычно XamlXmlWriter. Контекст службы передается как внутренний класс контекста поставщика службы XAML, реализующий шаблон поставщика службы. Дополнительные сведения о доступных службах и о том, что они представляют, см. в разделе Type Converters and Markup Extensions for XAML.

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

Определение типа поддержки для пользовательского расширения разметки

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

  • Имя типа должно точно соответствовать маркеру использования разметки XAML. Например, для поддержки использование расширения {Collate ...} , назовите тип поддержки Collate.
  • Имя типа должно состоять из маркера строки использования и суффикса Extension. Например, для поддержки использование расширения {Collate ...} , назовите тип поддержки CollateExtension.

Порядок поиска следующий: выполняется поиск имени класса с суффиксом Extension, а затем имени класса без суффикса Extension .

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

Конструктор без параметров

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

Если использование расширения разметки не имеет аргументов, конструктор без параметров необходим для поддержки использования.

Шаблоны конструктора и позиционные аргументы для пользовательского расширения разметки

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

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

public Collate(CollationMode collationMode) {...}

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

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

  • Как отмечалось ранее, у типа поддержки расширения разметки необязательно должен быть конструктор без параметров, чтобы можно было создать его экземпляр в XAML. Создание соответствующего объекта откладывается, пока его возможные аргументы в текстовом синтаксисе не преобразуются в маркеры как позиционные или именованные аргументы, а в это время вызывается соответствующий конструктор.
  • Использования расширения разметки могут быть вложенными. Сначала вычисляется внутреннее расширение разметки. Поэтому можно предположить такое использование и объявить один из параметров создания как тип, для создания которого требуется преобразователь значений (например, расширение разметки).

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

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

Аргументы называются позиционными, поскольку порядок, в котором маркеры указываются в использовании, соответствует позиции параметра конструктора, которому они назначены. Например, рассмотрим следующую сигнатуру конструктора:

public Collate(CollationMode collationMode, object collateThis) {...}

Обработчик XAML ожидает два позиционных аргумента для данного расширения разметки. Если применялось использование {Collate AlphaUp,{x:Reference circularFile}}, маркер AlphaUp отправляется в первый параметр и вычисляется как именованная константа перечисления CollationMode . Результат внутреннего x:Reference передается во второй параметр и вычисляется как объект.

В указанных правилах синтаксиса расширения разметки и обработки XAML запятая — это разделитель как позиционных, так и именованных аргументов.

Дублирующая арность позиционных аргументов

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

По умолчанию SupportMarkupExtensionsWithDuplicateArity имеет значение false в XamlSchemaContext на основе CLR для служб XAML .NET. Поэтому XamlObjectWriter по умолчанию создает исключения, если обнаруживает использование расширения разметки с дублирующей арностью в конструкторах резервного типа.

Именованные аргументы для пользовательского расширения разметки

Расширения разметки, заданные XAML, также могут использовать форму именованных аргументов. На первом уровне разметки текстовый синтаксис делится на аргументы. Наличие знака равенства (=) в каком-либо из аргументов определяет его как именованный. Такой аргумент также размечается в виде пары имени и значения. Имя в этом случае определяет открытое устанавливаемое свойство типа поддержки расширения разметки. Если планируется поддержка использования именованных аргументов, следует предоставить эти открытые устанавливаемые свойства. Свойства могут быть наследуемыми, пока они открытые.

Доступ к контексту поставщика службы из реализации расширения разметки

Доступные службы одинаковы для всех преобразователей значений. Разница заключается в том, как преобразователь значения получает контекст службы. Доступ к службам и предоставляемые службы описаны в разделе Type Converters and Markup Extensions for XAML.

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

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

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

Атрибуты для пользовательского расширения разметки

Для поддержки сред разработки и определенных сценариев средства записи объектов XAML необходимо пометить тип поддержки расширения разметки несколькими атрибутами среды CLR. Они сообщают предполагаемое использование расширения разметки.

MarkupExtensionReturnTypeAttribute предоставляет информацию о Type для типа объекта, который возвращает ProvideValue . По чистой сигнатуре ProvideValue возвращает Object. Но различным пользователям может потребоваться более точная информация о типе возвращаемого значения. В том числе:

  • Конструкторы и среды разработки, которые могут предоставлять поддержку с учетом типа для использования расширения разметки.
  • Расширенные реализации обработчиков SetMarkupExtension в целевых классах, которые могут применять отражение для определения возвращаемого типа расширения разметки вместо ветвления на конкретных известных реализациях MarkupExtension по имени.

Сериализация использований расширения разметки

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

Расширения разметки в потоке узлов XAML

При работе с потоком узлов XAML в пути загрузки использование расширения разметки отображается в потоке узлов как объект.

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

StartObject (XamlType — это тип определения расширения разметки, а не возвращаемый тип)

StartMember (имя XamlMember_InitializationText)

Value (значение — это позиционные аргументы в виде строки, включая используемые разделители)

EndMember

EndObject

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

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

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

См. также