Общие сведения о расширениях разметки для XAML
Расширения разметки — это технология языка XAML для получения значения, которое не является ни примитивом, ни конкретным типом XAML. Для употребления расширений разметки в качестве атрибутов используется известная последовательность символов из открывающей фигурной скобки { для входа в область расширения разметки и закрывающей фигурной скобки } для выхода из этой области. При использовании служб XAML платформы .NET Framework можно использовать некоторые предопределенные расширения разметки языка XAML из сборки System.Xaml. Можно также создать класс, производный от класса MarkupExtension, определенного в System.Xaml, и определить собственные расширения разметки. Также можно использовать расширения разметки, определенные конкретной платформой, если в проекте уже существуют ссылки на эту платформу.
При доступе к употреблению расширения разметки средство записи объектов XAML может предоставить службы пользовательскому классу MarkupExtension с помощью точки подключения службы в методе, переопределяющем метод MarkupExtension.ProvideValue. Эти службы могут использоваться для получения контекста употребления, конкретных возможностей средства записи объектов, контекста схемы XAML и т. д.
В этом разделе содержатся следующие подразделы.
- Расширения разметки, определенные XAML
- Базовый класс MarkupExtension
- Определение типа поддержки для пользовательского расширения разметки
- Шаблоны конструктора и позиционные аргументы для пользовательского расширения разметки
- Именованные аргументы для пользовательского расширения разметки
- Доступ к контексту поставщика услуг из реализации расширения разметки
- Употребление расширения разметки в качестве элемента свойства
- Присвоение атрибутов для пользовательского расширения разметки
- Сериализация употреблений расширения разметки
- Расширения разметки в потоке узлов XAML
- Связанные разделы
Расширения разметки, определенные XAML
Несколько расширений разметки реализованы в службах XAML платформы .NET Framework для поддержки языка XAML. Эти расширения разметки соответствуют частям спецификации XAML как языка. В синтаксисе они обычно распознаются по префиксу x:, как показано в общем использовании. Все реализации этих элементов языка XAML в службах XAML платформы .NET Framework являются производными от базового класса MarkupExtension.
Примечание |
---|
Префикс x: используется для типичного сопоставления пространства имен в XAML — пространства имен языка XAML — в корневом элементе производства XAML.Например, шаблоны проектов и страниц Visual Studio для различных конкретных платформ начинают формирование файла XAML, используя это сопоставление x:.Разработчик может выбрать другую лексему префикса в своем сопоставлении пространства имен XAML, но в данной документации по умолчанию предполагается использование сопоставления x: в качестве средства идентификации сущностей, являющихся определенной частью пространства имен XAML языка XAML, в отличие от пространства имен XAML по умолчанию конкретной платформы или других произвольных пространств имен CLR или XML. |
x:Type
Расширение разметки x:Type предоставляет объект Type для именованного типа. Эта функциональная возможность чаще всего используется в механизмах задержки, использующих базовый тип CLR и производность типов в качестве разновидности моникера или идентификатора группы. Конкретным примером будут стили и шаблоны WPF и использование в них свойств TargetType. Дополнительные сведения см. в разделе Расширение разметки x:Type.
x:Static
Сопоставление x:Static создает статические значения из сущностей кода типа значения, которые непосредственно не принадлежат к типу значения свойства, но могут быть приведены к этому типу. Это полезно для задания значений, уже существующих в качестве известных констант в определении типа. Дополнительные сведения см. в разделе Расширение разметки x:Static.
x:Null
Расширение разметки x:Null задает null в качестве значения для члена XAML. В зависимости от конструкции отдельных типов или от более крупных понятий платформы, null не всегда является значением свойства по умолчанию или неявным значением атрибута пустой строки. Дополнительные сведения см. в разделе Расширение разметки x:NULL.
x:Array
Расширение разметки x:Array обеспечивает поддержку создания общих массивов в синтаксисе XAML для случаев, когда поддержка коллекций, предоставляемая базовыми элементами и моделями элементов управления, намеренно не используется. Дополнительные сведения см. в разделе Расширение разметки x:Array. В XAML 2009 доступ к массивам осуществляется как к примитивам языка, а не как к расширению. Дополнительные сведения см. в разделе Возможности языка XAML 2009.
x:Reference
Расширение разметки x:Reference является частью XAML 2009, расширения исходного набора языка (2006). x:Reference представляет собой ссылку на другой существующий объект графа объектов. Этот объект определяется своим параметром x:Name. Дополнительные сведения см. в разделе Расширение разметки x:Reference.
Другие конструкции x:
Существуют и другие конструкции x:, поддерживающие возможности языка XAML, но они не реализованы как расширения разметки. Дополнительные сведения см. в разделе Возможности пространства имен языка XAML (x:);
Базовый класс MarkupExtension
Чтобы определить пользовательское расширение разметки, которое может взаимодействовать с реализациями средств чтения и записи XAML по умолчанию в System.Xaml, можно создать класс, производный от абстрактного класса MarkupExtension. В этом классе нужно переопределить один метод, ProvideValue. Также может понадобиться определить дополнительные конструкторы, поддерживающие аргументы для употребления расширения разметки, и соответствующие устанавливаемые свойства.
Метод ProvideValue предоставляет пользовательскому расширению разметки доступ к контексту службы, сообщающему среде, где фактически обработчик XAML вызывает расширение разметки. В пути загрузки это обычно XamlObjectWriter. В пути сохранения это обычно XamlXmlWriter. Каждый контекст службы передается как внутренний класс контекста поставщика службы XAML, реализующий шаблон поставщика службы. Дополнительные сведения о доступных службах и о том, что они представляют, см. в разделе Преобразователи типов или расширения разметки для XAML.
Созданный класс расширения разметки должен использовать открытый уровень доступа — у обработчиков XAML всегда должна быть возможность создать экземпляр класса поддержки расширения разметки для использования его служб.
Определение типа поддержки для пользовательского расширения разметки
При использовании служб XAML платформы .NET Framework или платформ на основе служб XAML платформы .NET Framework, существует два варианта именования типов поддержки расширения разметки. Имя типа соответствует тому, как средства записи объектов 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 Framework преобразовывает имена констант перечисления в перечисленные значения на собственном уровне.
При обработке текстового синтаксиса позиционного параметра расширения разметки также может использоваться преобразователь типа, связанный с типом в аргументе создания.
Аргументы называются позиционными, так как порядок обнаружения лексем в употреблении соответствует порядковой позиции параметра конструктора, которому эти лексемы назначаются. Например, рассмотрим следующую сигнатуру конструктора:
public Collate(CollationMode collationMode, object collateThis) {...}
Обработчик XAML ожидает, что для этого расширения разметки будет передано два позиционных аргумента. При употреблении {Collate AlphaUp,{x:Reference circularFile}} лексема AlphaUp передается первому параметру и оценивается как именованная константа перечисления CollationMode. Результат внутреннего x:Reference передается во второй параметр и оценивается как объект.
В правилах для синтаксиса и обработки расширений разметки, согласно спецификации XAML, разделителем аргументов служит запятая, независимо от того, являются ли аргументы позиционными или именованными.
Дублирующая арность позиционных аргументов
Когда средство записи объектов XAML обнаруживает употребление расширения разметки с позиционными аргументами и существует несколько аргументов конструктора, принимающих такое же количество аргументов (дублирующая арность), это не всегда является ошибкой. Такое поведение зависит от настройки пользовательского контекста схемы XAML, SupportMarkupExtensionsWithDuplicateArity. Если свойство SupportMarkupExtensionsWithDuplicateArity имеет значение true, средство записи объектов XAML не должно создавать исключение только лишь по причине дублирующей арности. Последующее поведение строго не определено. Основным конструктивным предположением является то, что контекст схемы располагает информацией о типе для отдельных параметров и может попытаться выполнить явные приведения, которые соответствуют дублированным кандидатам, чтобы увидеть, какая сигнатура подойдет лучше всего. Исключение все равно может быть создано, если ни одна сигнатура не пройдет тесты, проводимые этим конкретным контекстом схемы, работающим на средстве записи объектов XAML.
По умолчанию свойство SupportMarkupExtensionsWithDuplicateArity имеет значение false в основанном на среде CLR классе XamlSchemaContext для служб XAML платформы .NET Framework. Таким образом, средство записи XamlObjectWriter по умолчанию создает исключения, если обнаруживает употребление расширения разметки, в котором существует дублированная арность в конструкторах резервного типа.
Именованные аргументы для пользовательского расширения разметки
Расширения разметки, заданные XAML, также могут употребляться с именованными аргументами. На первом уровне разбора синтаксис текста разбивается на аргументы. Наличие знака равенства (=) в любом из аргументов определяет этот аргумент как именованный. Такой аргумент также размечается в пару "имя=значение". Имя в этом случае именует открытое устанавливаемое свойство для типа поддержки расширения разметки. Если предполагается поддержка использования именованных аргументов, следует предоставить эти открытые устанавливаемые свойства. Эти свойства являются наследуемыми при условии, что они остаются открытыми.
Доступ к контексту поставщика услуг из реализации расширения разметки
Доступные службы одинаковы для всех преобразователей значений. Разница состоит только в том, как преобразователь значения получает контекст службы. Доступ к службам и доступные службы описаны в разделе Преобразователи типов или расширения разметки для 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 Framework по умолчанию, состоит в том, что часть пути загрузки, соответствующая средству чтения, зачастую не располагает необходимым контекстом схемы XAML.
При работе с потоком узлов XAML в пути сохранения в представлении графа объектов обычно нет ничего, что могло бы сообщить, что сериализуемый объект был изначально предоставлен употреблением расширения разметки и результатом метода ProvideValue. В сценариях, требующих сохранения употреблений расширения разметки для циклической обработки при одновременном сохранении других изменений графа объектов, необходимо разрабатывать собственные методики сохранения информации об употреблении расширения разметки из исходных входных данных XAML. Например, для восстановления употреблений расширения разметки может потребоваться работа с потоком узлов в пути сохранения для восстановления употреблений расширения разметки или выполнения своего рода слияния исходного кода XAML и кода XAML из цикла обработки. В некоторых реализующих XAML платформах, таких как WPF, используются промежуточные типы (выражения) для упрощения представления случаев, где значения предоставлены употреблениями расширений разметки.
См. также
Ссылки
Основные понятия
Расширения разметки и XAML WPF