Сводная информация о Главе 11. Инфраструктура c возможностью привязки
Примечание.
Эта книга была опубликована весной 2016 года и с тех пор не обновлялась. Многое в этой книге остается ценным, но некоторые материалы устарели, а некоторые разделы перестали быть полностью верными или полными.
Каждый программист, работавший с C#, знает концепцию свойств. Свойства в C# содержат методы доступа для присвоения и (или) получения значения. Они часто называются свойствами среды CLR (общеязыковой среды выполнения).
Xamarin.Forms использует расширенное определение свойства, именуемое привязываемым свойством, которое инкапсулировано классом BindableProperty
и поддерживается классом BindableObject
. Эти классы связаны, но довольно отличаются: BindableProperty
используется для определения самого свойства; BindableObject
он похож на object
базовый класс для классов, определяющих привязываемые свойства.
Иерархия классов Xamarin.Forms
В примере ClassHierarchy с помощью отражения демонстрируются иерархия классов Xamarin.Forms и решающая роль, которую в этой иерархии играет BindableObject
. BindableObject
является производным от Object
и родительским классом для Element
, от которого, в свою очередь, наследуется VisualElement
. Это родительский класс для Page
и View
, который является родительским классом для Layout
:
Коротко о BindableObject и BindableProperty
В классах, производных от BindableObject
, многие свойства CLR "подкрепляются" аналогичными привязываемыми свойствами. Например, свойство Text
класса Label
является свойством CLR, но класс Label
определяет также открытое статическое поле только для чтения с именем TextProperty
и типом BindableProperty
.
Приложение может задать или получить свойство Text
из Label
обычным образом или задать Text
вызовом метода SetValue
, который определен в BindableObject
с аргументом Label.TextProperty
. Аналогичным образом, приложение может получить значение свойства Text
вызовом метода GetValue
с аргументом Label.TextProperty
. Это демонстрируется в примере PropertySettings.
Действительно, свойство CLR Text
полностью реализуется с помощью методов SetValue
и GetValue
, определенных BindableObject
в сочетании со статическим свойством Label.TextProperty
.
BindableObject
и BindableProperty
предоставляют поддержку следующих возможностей.
- Присвоение свойствам значений по умолчанию.
- Сохранение текущих значений.
- Предоставление механизмов для проверки значений свойств.
- Поддержание согласованности между связанными свойствами в одном классе.
- Реагирование на изменения свойств.
- Активация уведомлений перед изменением или после изменения свойства.
- Поддержка привязки данных.
- Поддержка стилей.
- Поддержка динамических ресурсов.
При изменении свойства, которое подкреплено привязываемым свойством, BindableObject
запускает событие PropertyChanged
, идентифицирующее измененное свойство. Если свойству присваивается такое же значение, как и прежнее, это событие не запускается.
Некоторые свойства не поддерживаются привязываемыми свойствами, а некоторые Xamarin.Forms классы, например Span
, не являются производными от BindableObject
. Привязываемые свойства может поддерживать только класс, производный от BindableObject
, так как методы SetValue
и GetValue
определяются в BindableObject
.
Так как Span
не является производным от BindableObject
свойства , например Text
, поддерживается привязываемым свойством. Именно поэтому параметр DynamicResource
в свойстве Text
класса Span
вызывает исключение в примере DynamicVsStatic из предыдущей главы. Пример DynamicVsStaticCode демонстрирует, как задать динамические ресурсы в коде с помощью метода SetDynamicResource
, который определен в Element
. Первый аргумент является объектом типа BindableProperty
.
Аналогичным образом, у определенного в BindableObject
метода SetBinding
первый аргумент имеет тип BindableProperty
.
Определение привязываемых свойств
Чтобы определить собственные привязываемые свойства, вызовите статический метод BindableProperty.Create
для создания статического поля только для чтения с типом BindableProperty
.
Это действие демонстрируется в классе AltLabel
из библиотеки Xamarin.FormsBook.Toolkit. Класс является производным от Label
и позволяет указать размер шрифта в пунктах. Применение этого класса демонстрируется в примере FramedText.
Для метода BindableProperty.Create
обязательными являются четыре аргумента:
propertyName
: текстовое имя свойства (то же, что имя свойства CLR);returnType
: тип свойства CLR;declaringType
: тип класса, в котором объявлено свойство;defaultValue
: значение свойства по умолчанию.
Поскольку defaultValue
имеет тип object
, компилятор должен уметь определять тип значения по умолчанию. Например, если returnType
является double
, для defaultValue
нужно задать значение 0,0, а не просто 0, иначе во время выполнения будет вызвано исключение несоответствия типа.
Также достаточно часто привязываемое свойство включает следующее:
propertyChanged
: статический метод, который вызывается при изменении значения свойства. Первым аргументом здесь является экземпляр класса, у которого изменилось свойство.
Другие аргументы BindableProperty.Create
менее широко распространены:
defaultBindingMode
: используется в связи с привязкой данных (как описано в главе 16. Привязка данных)validateValue
: обратный вызов для проверки допустимого значения;propertyChanging
: обратный вызов, который обозначает, что свойство должно быть изменено;coerceValue
: обратный вызов, который изменяет заданное значение на другое значение;defaultValueCreate
: обратный вызов для создания значения по умолчанию, которое нельзя использовать совместно для нескольких экземпляров класса (например, в коллекции).
Привязываемое свойство только для чтения
Привязываемое свойство может быть доступно только для чтения. Чтобы создать привязываемое свойство только для чтения, вызовите статический метод BindableProperty.CreateReadOnly
для определения частного статического поля только для чтения с типом BindablePropertyKey
.
Затем определите метод доступа set
для свойства CLR как private
для вызова перегрузки SetValue
с объектом BindablePropertyKey
. Это не позволит задавать значение свойства за пределами самого класса.
Пример такого подхода демонстрируется в классе CountedLabel
, который используется в примере BaskervillesCount.