Сводная информация о Главе 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.