Определение пользовательских типов для использования со службами XAML .NET Framework
При определении пользовательских типов, которые являются бизнес-объектами или типами, не имеющими зависимостей от конкретной платформы, существуют некоторые рекомендации для XAML. При выполнении этих рекомендаций службы XAML платформы .NET Framework и соответствующие средства чтения и записи XAML могут выяснить характеристики XAML пользовательского типа и предоставить ему соответствующее представление в потоке узлов XAML при помощи системы типов XAML. В данном разделе приводятся рекомендации по определениям типов, определениям членов и присвоению атрибутов CLR типов и членов.
Шаблоны конструктора и определения типов для XAML
Чтобы создаваться в качестве объектного элемента в XAML, пользовательский класс должен удовлетворять следующим требованиям.
Пользовательский класс должен быть открытым и должен предоставлять открытый конструктор по умолчанию (без параметров). (Примечания о структурах см. в следующем разделе.)
Пользовательский класс не должен быть вложенным классом. Лишняя точка в пути полного имени вызывает неоднозначность разделения класс-пространство имен, и препятствует другим возможностям XAML, таким как вложенные свойства.
Если для объекта может быть создан экземпляр в виде объектного элемента, созданный объект может заполнить форму элемента свойства всех свойств, которые используют этот объект как базовый тип.
Сохраняется возможность предоставления значений объектов типам, которые не соответствуют данным критериям, путем включения преобразователя значений. Дополнительные сведения см. в разделе Преобразователи типов или расширения разметки для XAML.
Структуры
По определению среды CLR в XAML всегда можно создать структуры. Это обусловлено тем, что компилятор CLR неявно создает конструктор по умолчанию для структуры. Этот конструктор инициализирует значения свойств согласно их значениям по умолчанию.
В некоторых случаях поведение конструктора по умолчанию для структуры является нежелательным. Это может быть вызвано тем, что эта структура предназначена для функционирования и заполнения значений в качестве объединения. Объединение означает, что хранимые в структуре значения могут обладать взаимоисключающими интерпретациями, и поэтому ни одному из свойств нельзя присвоить значение. Примером такой структуры в словаре WPF является GridLength. В таких структурах необходимо реализовывать преобразователь типов, чтобы значения можно было представить в виде атрибутов, используя преобразования строк для создания различных интерпретаций или режимов значений структуры. Структура также должна реализовывать аналогичное поведение для конструкции кода с помощью конструктора, не являющегося конструктором по умолчанию.
Интерфейсы
Интерфейсы могут использоваться как базовые типы членов. Система типов XAML проверяет список значений, которые можно присвоить, и ожидает, что объект, предоставленный в качестве значения, может быть присвоен интерфейсу. Концепция представления интерфейса как типа XAML отсутствует, при условии, что соответствующий присваиваемый тип поддерживает требования к созданию XAML.
Фабричные методы
Фабричные методы являются возможностью XAML 2009. Они модифицируют принцип XAML, что объекты должны иметь конструкторы по умолчанию. В данном разделе фабричные методы не рассматриваются. См. раздел Директива x:FactoryMethod.
Перечисления
Перечисления обладают поведением встроенного преобразования типов XAML. Имена констант перечисления, указанные в XAML, разрешаются по типу базового перечисления и возвращают значение перечисления средству записи объектов XAML.
XAML поддерживает использование перечислений с примененным атрибутом FlagsAttribute подобно флагам. Дополнительные сведения см. в разделе Подробное описание синтаксиса XAML. (Раздел Подробное описание синтаксиса XAML адресован пользователям WPF, но большая часть информации этого раздела имеет отношение к XAML в части, не относящейся к какой-либо конкретной платформе реализации.)
Определения членов
Для использования XAML типы могут определять члены. Такая возможность существует у типов, определяющих члены, которые могут использоваться в XAML, даже если этот отдельный тип не пригоден для использования в XAML. Это возможно благодаря наследованию CLR. При условии что какой-либо тип, наследующий член, поддерживает использование XAML в качестве типа, а этот тип поддерживает использование XAML для своего базового типа, или доступен его собственный синтаксис XAML, этот член может использоваться в XAML.
Свойства
При определении свойств в качестве открытого свойства среды CLR с использованием обычных шаблонов методов доступа get и set среды CLR и соответствующих языку ключевых слов система типов XAML может сообщать о свойстве как о члене с предоставлением соответствующей информации для свойств объекта XamlMember, таких как IsReadPublic и IsWritePublic.
Некоторые свойства могут включать текстовый синтаксис путем применения атрибута TypeConverterAttribute. Дополнительные сведения см. в разделе Преобразователи типов или расширения разметки для XAML.
В отсутствие текстового синтаксиса или собственного преобразования XAML и в отсутствие дальнейшей косвенности, такой как употребление расширения разметки, тип свойства (TargetType в системе типов XAML) должен обладать возможностью возврата экземпляра средству записи объектов XAML путем обработки целевого типа в качестве типа CLR.
При использовании XAML 2009 расширение Расширение разметки x:Reference можно использовать для предоставления значений, если не выполняются указанные выше требования, но это скорее вопрос употребления, чем определения типа.
События
При определении событий в качестве открытого события CLR система типов XAML может сообщать о событии как о члене, причем свойство IsEvent будет иметь значение true. Привязка обработчиков событий не входит в число возможностей служб XAML платформы .NET Framework; это отводится отдельным платформам и реализациям.
Методы
Встроенный код для методов не входит в число возможностей XAML по умолчанию. В большинстве случаев из XAML не дается прямая ссылка на члены методов, а методы в XAML лишь оказывают поддержку для отдельных шаблонов XAML. Директива x:FactoryMethod является исключением.
Поля
В рекомендациях по проектированию CLR не поощряется использование нестатических полей. Что касается статических полей, то доступ к значениям статических полей можно получить лишь через Расширение разметки x:Static; в таком случае в определении CLR не производится ничего особенного, чтобы открыть поле для использований x:Static.
Присоединяемые члены
Присоединяемые члены открываются для XAML при помощи шаблона метода доступа на определяющем типе. Сам определяющий тип может не иметь возможность использования в XAML в качестве объекта. Фактически, распространенным шаблоном является объявление класса службы, который будет содержать присоединяемый член и реализовывать соответствующие поведения, не выполняя при этом никаких других функций, таких как представление пользовательского интерфейса. В следующих разделах заполнитель PropertyName представляет имя пользовательского присоединяемого члена. Это имя должно быть допустимо в Грамматика XamlName.
Будьте внимательны к конфликтам имен между этими шаблонами и другими методами типа. Если существует член, который соответствует одному из шаблонов, он может быть интерпретирован обработчиком XAML как путь использования присоединяемого члена, даже если пользователь этого не желает.
Метод доступа GetИмяСвойства
Сигнатура для метода доступа GetИмяСвойства должна быть следующей:
public static object GetИмяСвойства(object target)
Объект target может быть задан в реализации как более конкретный тип. Это можно использовать для определения границ использования присоединяемого члена; использование за пределами этих границ будет создавать исключения недопустимого приведения, которые затем отображаются как ошибки анализа XAML. Имя параметра target не является требованием, он именуется target по соглашению во многих реализациях.
Возвращаемое значение может быть задано в реализации как более конкретный тип.
Для поддержки включенного текстового синтаксиса TypeConverter для употребления присоединяемого члена в качестве атрибута примените атрибут TypeConverterAttribute к методу доступа GetИмяСвойства. Применение атрибута к get вместо set может показаться неинтуитивным, однако это соглашение поддерживает концепцию доступных только для чтения присоединяемых членов, которые могут быть сериализованы, что удобно в сценариях конструктора.
Метод доступа SetИмяСвойства
Сигнатура для метода доступа SetИмяСвойства должна быть следующей:
public static void SetИмяСвойства(object target, object value)
Объект target может быть задан в реализации как более конкретный тип, логика и последствия этого будут такими же, как описанные в предыдущем разделе.
Объект value может быть задан в реализации как более конкретный тип.
Помните, что значением для данного метода являются входные данные, поступающие от использования XAML, обычно в виде атрибута. Для текстового синтаксиса должна быть предусмотрена поддержка преобразователя значения из формы атрибута, и атрибут присваивается методу доступа GetИмяСвойства.
Хранилища присоединяемых членов
Методов доступа обычно недостаточно для предоставления механизма помещения значений присоединяемого члена в граф объектов или извлечения значений из графа объектов и надлежащей их сериализации. Для обеспечения этой функциональной возможности объекты target в приведенных выше сигнатурах метода доступа должны быть способны хранить значения. Механизмы хранения должны быть согласованы с принципом присоединяемых членов о том, что член может быть присоединен к целевым объектам, у которых присоединяемый член не входит в список членов. Службы XAML платформы .NET Framework предоставляют методику реализации хранилищ присоединяемых членов через API-интерфейсы IAttachedPropertyStore и AttachablePropertyServices. Интерфейс IAttachedPropertyStore используется средствами записи XAML для обнаружения реализации хранилища и должен быть реализован в типе, который является объектом target методов доступа. Статические API-интерфейсы AttachablePropertyServices используются внутри тела методов доступа и ссылаются на присоединяемый член по его идентификатору AttachableMemberIdentifier.
Атрибуты CLR, связанные с XAML
Правильное присвоение атрибутов типам, членам и сборкам является очень важным для передачи информации системы типов XAML службам XAML платформы .NET Framework. Это имеет значение, если типы предназначены для использования с системами XAML, основанными непосредственно на средствах чтения и записи XAML служб XAML платформы .NET Framework, либо если определяется или используется платформа, использующая XAML, основанная на этих средствах записи и чтения XAML.
Список всех связанных с XAML атрибутов, имеющих отношение к поддержке XAML для пользовательских типов, см. в разделе Относящиеся к XAML атрибуты среды CLR для пользовательских типов и библиотек.
Использование
Использование пользовательских типов требует того, что автор разметки должен выполнить сопоставление префикса для сборки и пространства имен CLR, где содержится пользовательский тип. Данная процедура не рассматривается в этом разделе.
Уровень доступа
XAML предоставляет механизм для загрузки и создания экземпляров типов, имеющих уровень доступа internal. Эта возможность позволяет пользовательскому коду определять собственные типы, а затем создавать экземпляры этих классов из разметки, также входящей в ту же область пользовательского кода.
Пример из WPF — всякий раз, когда пользовательский код определяет класс UserControl, который предназначен для рефакторинга поведения пользовательского интерфейса, но не должен входить в состав какого-либо возможного механизма расширения, что могло бы подразумевать объявление поддерживающего класса с уровнем доступа public. Такой класс UserControl может быть объявлен с доступом internal, если резервный код скомпилирован в ту же сборку, из которой на него указывает ссылка как на тип XAML.
Для приложения, которое загружает XAML-код в режиме полного доверия и предполагает использование XamlObjectWriter, загрузка классов с уровнем доступа internal разрешена всегда.
Для приложения, которое загружает XAML-код в режиме частичного доверия, управлять характеристиками уровня доступа можно с помощью API-интерфейса XamlAccessLevel. Кроме того, механизмы отсрочки (такие как система шаблонов WPF) должны быть способны распространять все разрешения уровня доступа и сохранять их для оценки во время выполнения; это производится внутренне путем передачи информации XamlAccessLevel.
Реализация в WPF
В XAML в WPF используется модель доступа частичного доверия, где, если BAML-код загружается в режиме частичного доверия, доступ для сборки, являющейся источником BAML-кода, ограничен методом AssemblyAccessTo. Для отсрочки в WPF используется метод IXamlObjectWriterFactory.GetParentSettings в качестве механизма для передачи информации об уровне доступа.
В терминологии XAML в WPF внутренний тип — это тип, определяемый той же сборкой, которая включает ссылающийся на него XAML-код. Такой тип может быть сопоставлен через пространство имен XAML, в котором намеренно опущена часть сопоставления "assembly=", например xmlns:local="clr-namespace:WPFApplication1". Если BAML-код ссылается на внутренний тип и этот тип имеет уровень доступа internal, для сборки формируется класс GeneratedInternalTypeHelper. Если требуется избежать формирования GeneratedInternalTypeHelper, необходимо либо использовать уровень доступа public, либо выносить соответствующий класс в отдельную сборку и делать эту сборку зависимой.
См. также
Основные понятия
Другие ресурсы
Относящиеся к XAML атрибуты среды CLR для пользовательских типов и библиотек