Код XAML и пользовательские классы для WPF
Реализация языка XAML в платформах CLR поддерживает возможность определения пользовательского класса или структуры на любом языке CLR и последующего доступа к этому классу с помощью разметки XAML. В одном файле разметки можно использовать сочетание определенных в Windows Presentation Foundation (WPF) типов и пользовательских типов, обычно сопоставляя пользовательские типы с префиксом пространства имен XAML. В этом разделе обсуждаются требования, которым должен соответствовать пользовательский класс, чтобы его можно было использовать в качестве элемента XAML.
Пользовательские классы в приложениях или сборках
Пользовательские классы, используемые в XAML, можно определить двумя способами: в коде программной части или другом коде, который создает основное приложение Windows Presentation Foundation (WPF), или как класс в отдельной сборке, например как исполняемый файл или библиотеку DLL, используемые в качестве библиотеки классов. Каждый из этих подходов имеет определенные преимущества и недостатки.
Преимуществом создания библиотеки классов является то, что все подобные пользовательские классы могут совместно использоваться несколькими различными приложениями. Отдельная библиотека также облегчает управление версиями приложений и упрощает создание класса, который предполагается использовать в качестве корневого элемента на странице XAML.
Преимущество определения пользовательских классов в приложении состоит в том, что этот способ является относительно простым и сводит к минимуму проблемы развертывания и тестирования, возникающие при введении отдельных сборок за пределами главного исполняемого файла приложения.
Независимо от того, определены ли пользовательские классы в одной или разных сборках, они должны быть распределены между пространством имен CLR и пространством имен XML, чтобы их можно было использовать в XAML в качестве элементов. См. раздел Пространства имен XAML и сопоставление пространств имен для WPF XAML.
Требования к пользовательскому классу как элементу XAML
Чтобы можно было создавать экземпляр класса в качестве объектного элемента, класс должен удовлетворять указанным ниже требованиям.
Пользовательский класс должен быть открытым и должен поддерживать открытый конструктор по умолчанию (без параметров). (Примечания о структурах см. в следующем разделе.)
Пользовательский класс не должен быть вложенным. Вложенные классы и "точка" в их общем синтаксисе использования в среде CLR конфликтуют с другими функциями WPF и XAML, такими как присоединенные свойства.
В дополнение к разрешению синтаксиса объектных элементов определение объекта также разрешает синтаксис элемента свойства для всех других открытых свойств, которые принимают объект в качестве типа значения. Это происходит потому, что экземпляр объекта теперь может быть создан в качестве объектного элемента и может заполнить значение элемента свойства.
Структуры
Структуры, определяемые как настраиваемые типы, всегда следует создавать в XAML в WPF. Причина заключается в том, что компиляторы CLR неявным образом создают для структуры конструктор по умолчанию, который инициализирует все свойства со значениями по умолчанию. В некоторых случаях поведение конструктора по умолчанию или использование объектных элементов для структуры является нежелательным. Это возможно в тех случаях, когда структура используется для заполнения значений и функционирует в качестве объединения, в котором хранятся взаимоисключающие значения, и поэтому ни одному из свойств нельзя присвоить значение. Объект WPF Примером такой структуры является Grid
Требования к свойствам пользовательского класса как атрибутам XAML
Свойства должны ссылаться на тип, передаваемый по значению (такой как примитив), или использовать класс для типа, имеющего конструктор по умолчанию или преобразователь выделенного типа, к которому может получить доступ процессор XAML. В реализации XAML среды CLR процессоры XAML находят такие преобразователи с помощью собственной поддержки примитивов языка либо путем применения Type
Помимо этого, свойство может ссылаться на абстрактный тип класса или интерфейс. Для абстрактных классов или интерфейсов ожидаемый результат синтаксического анализа XAML заключается в том, что значение свойства должно быть заполнено практическими экземплярами класса, которые реализуют интерфейс, или экземплярами типов, которые являются производными от абстрактного класса.
Свойства могут объявляться в абстрактном классе, но могут быть заданы только в практических классах, производных от абстрактных классов. Это объясняется тем, что для создания объектного элемента для класса в целом требуется открытый конструктор по умолчанию в классе.
Синтаксис атрибута с поддержкой TypeConverter
Если поддерживается выделенный преобразователь типов атрибутов на уровне класса, то применяемый тип преобразования включает синтаксис атрибута для любого свойства, для которого необходимо создать экземпляр этого типа. Преобразователь типа не включает использование объектного элемента типа — только наличие конструктора по умолчанию для данного типа разрешает использование объектного элемента. Таким образом, свойства, разрешенные преобразователем типов, обычно не используются в синтаксисе свойств, если только сам тип не поддерживает синтаксис объектных элементов. Исключением из этого является указание синтаксиса элемента свойства при наличии элемента свойства, содержащего строку. Это использование действительно фактически эквивалентна использованию синтаксиса атрибута и такое использование не часто, если не существует потребность в более надежную обработку пробела значение атрибута. Например, ниже показано использование элемента свойства, который принимает строку, а использование атрибута эквивалентно.
<Button>Hallo!
<Button.Language>
de-DE
</Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>
Примерами свойств, где синтаксис атрибута разрешен, но синтаксис элемента свойства, содержащего объектный элемент, запрещен XAML являются различные свойства, принимающие Cursor типа. Cursor Класс имеет выделенный преобразователь типа Cursor
Преобразователь типа каждого свойства
В качестве альтернативы само свойство может объявлять преобразователь типов на уровне свойств. Это позволяет «мини-язык», который создает объекты типа встроенного свойства путем обработки входящих строковых значений атрибута в качестве входных данных для Convert
При каждом предоставлении свойства, использующего XAML (особенно в том случае, если вы являетесь автором элемента управления), настоятельно рекомендуем резервировать это свойство с помощью свойства зависимости. Это особенно верно в случае, если используется существующая Windows Presentation Foundation (WPF) реализация обработчика XAML, так как можно повысить производительность с помощью Dependency
Написание и установка атрибутов преобразователя типов
Иногда нужно будет написать собственный Type
Требования к синтаксису атрибутов обработчиков событий XAML пользовательского класса
Чтобы событие можно было использовать в качестве события CLR, оно должно быть предоставлено в качестве открытого события класса, поддерживающего конструктор по умолчанию, или абстрактного класса, где событие может быть доступно в производных классах. Чтобы использоваться как перенаправленное событие, ваш CLR событие должно явным образом реализовывать add
и remove
методы, которые добавляют и удаляют обработчики для CLR сигнатуры события и направляют эти обработчики в Add
Note
Можно регистрировать обработчики непосредственно для перенаправленных событий с помощью Add
Написание свойств коллекции
Свойства, принимающие тип коллекции, имеют синтаксис XAML, который позволяет определять объекты, добавляемые в коллекцию. Этот синтаксис имеет две важные функции.
Объект, являющийся объектом коллекции, необязательно определять в синтаксисе объектного элемента. Присутствие этого типа коллекции подразумевается всякий раз, когда в XAML указывается свойство, принимающее тип коллекции.
Дочерние элементы свойства коллекции в разметке обрабатываются для того, чтобы они стали элементами коллекции. Обычно доступ кода к элементам коллекции осуществляется через методы списка или словаря, такие как
Add
, или через индексатор. Но синтаксис XAML не поддерживает методы или индексаторы (исключение: XAML 2009 может поддерживать методы, но с помощью XAML 2009 ограничивает возможные способы использования WPF; см. в разделе возможности языка XAML 2009). Коллекции, очевидно, являются очень общим требованием для построения дерева элементов, и требуется какой-нибудь способ заполнения этих коллекций в декларативном XAML. Таким образом, дочерние элементы свойства коллекции обрабатываются путем добавления их в коллекцию, которая является значением типа свойства коллекции.
Реализация служб XAML в .NET Framework и, следовательно, процессор XAML WPF используют указанное ниже определение того, что составляет свойство коллекции. Тип свойства должен реализовывать один из следующих интерфейсов:
Реализует IList.
Реализует IDictionary или универсальный эквивалент (IDictionary<TKey,TValue>).
Является производным от Array (Дополнительные сведения о массивах в XAML см. в разделе расширение разметки x: Array.)
Реализует IAdd
Child (интерфейс определяется WPF).
Каждый из этих типов в среде CLR имеет метод Add
, который используется процессором XAML для добавления элементов в базовую коллекцию при создании графа объекта.
Note
Универсальный List
и Dictionary
интерфейсы (IList<T> и IDictionary<TKey,TValue>) не поддерживаются при обнаружении коллекций WPF процессор XAML. Тем не менее, можно использовать List<T> класса в качестве базового класса, так как он реализует IList напрямую, или Dictionary<TKey,TValue> как базовый класс, так как он реализует IDictionary напрямую.
При объявлении свойства, принимающего коллекцию, будьте осторожны при инициализации значения свойства в новых экземплярах типа. Если свойство не реализуется как свойство зависимости, то со свойством достаточно использовать резервное поле, вызывающее конструктор типа коллекции. Если свойство является свойством зависимости, то может потребоваться инициализация свойства коллекции как части конструктора типа по умолчанию. Это обусловлено тем, что свойство зависимости принимает значение по умолчанию из метаданных и обычно нежелательно, чтобы начальное значение свойства коллекции было статической общей коллекцией. Экземпляр коллекции должен иметься для каждого экземпляра содержащего типа. Дополнительные сведения см. в разделе Пользовательские свойства зависимостей.
Вы можете реализовать пользовательский тип коллекции для свойства коллекции. Из-за неявной обработки свойства коллекции пользовательскому типу коллекции не требуется предоставлять конструктор по умолчанию, который будет использоваться в XAML неявно. Однако при необходимости можно предоставить конструктор по умолчанию для типа коллекции. Это может оказаться целесообразным. Если не предоставить конструктор по умолчанию, невозможно будет явно объявить коллекцию в качестве объектного элемента. Некоторые разработчики разметки могут предпочесть просмотр явной коллекции в качестве стиля разметки. Кроме того, конструктор по умолчанию может уменьшить требования к инициализации при создании объектов, использующих тип коллекций в качестве значения свойства.
Объявление свойств содержимого XAML
Язык XAML определяет концепцию свойства содержимого XAML. Каждый класс, используемый в синтаксисе объекта, может иметь только одно свойство содержимого XAML. Чтобы объявить свойство в качестве свойства содержимого XAML для класса, примените Content
Можно определить свойство коллекции как свойство содержимого XAML. Это отражается на использовании этого свойства, так как объектный элемент может иметь один или несколько дочерних элементов без промежуточных объектных элементов коллекции или тегов элементов свойства. Эти элементы затем рассматриваются как значение для свойства содержимого XAML и добавляются к резервному экземпляру коллекции.
Некоторые существующие свойства содержимого XAML используют тип свойства Object
. Это позволяет XAML, содержимого, свойство, которое может принимать как простые значения, такие как String так и значение ссылки на объект. Если следовать этой модели, то тип будет отвечать как за определение типа, так и за обработку возможных типов. Типичной причиной Object содержимого типа является поддержка как простых средств добавления содержимого объекта в виде строки (которая получает обработку представления по умолчанию) или улучшенных средств для добавления содержимого объекта, который задает нестандартное представление или Дополнительные данные.
Сериализация XAML
В некоторых сценариях (например, если вы являетесь автором элемента управления) следует убедиться в том, что любое представление объекта, которое может быть создано в XAML, также может быть сериализовано обратно в эквивалентную разметку XAML. Требования к сериализации не описываются в этом разделе. См. разделы Общие сведения о разработке элементов управления и Дерево элементов и сериализация.