Определение пользовательских типов для использования со службами XAML .NET

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

Шаблоны конструкторов и определения типов для XAML

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

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

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

Если включить преобразователь величин, значения объекта по-прежнему можно указывать для типов, которые не соответствуют этим критериям. Дополнительные сведения см. в статье Преобразователи типов и расширения разметки для XAML.

Структуры

В XAML всегда можно создавать структуры с помощью определения среды CLR. Это связано с тем, что компилятор 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 с помощью типичных шаблонов среды CLR get и шаблонов методов доступа set, а также ключевые слова, подходящих для языка, система типов XAML может сообщить о таком свойстве как о член с соответствующими сведениями, предоставленными для свойств XamlMember, таких как IsReadPublic и IsWritePublic.

Определенные свойства позволяют использовать текстовый синтаксис благодаря применению TypeConverterAttribute. Дополнительные сведения см. в статье Преобразователи типов и расширения разметки для XAML.

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

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

События

Если события определяются как общедоступное событие среды CLR, система типов XAML может сообщить о событии как о члене с IsEvent=true. Подключение обработчиков событий не входит в сферу возможностей служб XAML .NET. Подключение остается зависимой от конкретных платформ и реализаций.

Методы

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

Поля

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

Присоединяемые члены

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

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

Метод доступа GetPropertyName

Сигнатура метода доступа GetPropertyName должна иметь следующий вид:

public static object GetPropertyName(object target)

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

  • Возвращаемое значение можно указать как более конкретный тип в реализации.

Чтобы поддержать текстовый синтаксис, реализуемый в TypeConverter, для использования атрибутов присоединяемого члена, примените TypeConverterAttribute к методу доступа GetPropertyName. Применение к get вместо set может показаться неинтуитивным, однако это соглашение способно поддерживать концепцию присоединяемых членов, доступных только для чтения, которые являются сериализуемыми, что полезно в сценариях конструкторов.

Метод доступа SetPropertyName

Сигнатура метода доступа SetPropertyName должна иметь следующий вид:

public static void SetPropertyName(object target, object value)

  • В своей реализации объект target можно указать как более конкретный тип, с той же логикой и последствиями, которые описаны в предыдущем разделе.

  • Объект value можно указать как более конкретный тип в реализации.

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

Хранилища присоединяемых членов

Данных методов доступа обычно недостаточно, чтобы предоставить средства размещения значений присоединяемых членов в графе объектов или чтобы извлечь значения из графа объектов и их правильно сериализовать. Чтобы обеспечить эту функциональность, объекты target в предыдущих сигнатурах методов доступа были должны поддерживать хранение значений. Механизм хранения должен соответствовать принципу присоединяемых членов, согласно которому член присоединяется к целевым объектам, в список членов которых он не входит. Службы XAML .NET предоставляют метод реализации хранилищ присоединяемых членов посредством API IAttachedPropertyStore и AttachablePropertyServices. IAttachedPropertyStore используется модулями записи XAML для обнаружения реализации хранилища и должен быть реализован в типе, который является объектом target методов доступа. Статические API AttachablePropertyServices используются в теле методов доступа и ссылаются на присоединяемый член по его идентификатору AttachableMemberIdentifier.

Правильное определение атрибутов для типов, членов и сборок важно для передачи информации о системе типов XAML службам XAML .NET. Сведения о системе типов XAML отчетов актуальны в следующих ситуациях:

  • Типы предназначены для использования вместе с системами XAML, которые непосредственно основаны на модулях чтения XAML и модулях записи XAML служб XAML .NET.
  • Определена или применяется платформа с использованием XAML, которая основана на этих модулях чтения 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 загружается под частичным доверием, доступ ограничен AssemblyAccessTo для сборки, которая является источником BAML. Для отсрочки WPF использует IXamlObjectWriterFactory.GetParentSettings в качестве механизма передачи сведений об уровне доступа.

В терминологии XAML WPF внутренний тип — это тип, определенный той же сборкой, которая также содержит ссылающийся код XAML. Такой тип может быть сопоставлен посредством пространства имен XAML, в котором, например, в сопоставлении намеренно опущена часть «assembly=», например, xmlns:local="clr-namespace:WPFApplication1". Если BAML ссылается на внутренний тип и этот тип имеет уровень доступа internal, в результате для сборки создается класс GeneratedInternalTypeHelper. Чтобы избежать использования GeneratedInternalTypeHelper, необходимо либо использовать уровень доступа public, либо выделить соответствующий класс в отдельную сборку и сделать эту сборку зависимой.

См. также