Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Примечание.
Эта книга была опубликована весной 2016 года и с тех пор не обновлялась. Многое в этой книге остается ценным, но некоторые материалы устарели, а некоторые разделы перестали быть полностью верными или полными.
Программистам часто приходится писать обработчики событий, которые отслеживают изменение свойства одного объекта и используют его для изменения значения свойства в другом объекте. Этот процесс можно автоматизировать с помощью технологии привязки данных. Привязки данных обычно определяются в XAML и становятся частью определения пользовательского интерфейса.
Очень часто эти привязки данных соединяют объекты пользовательского интерфейса с базовыми данными. Это метод, который рассматривается более в главе 18. MVVM. Но привязки данных могут также соединять два и более элементов пользовательского интерфейса. Этот способ демонстрируется в первых нескольких примерах привязки данных в этой главе.
Основы привязки данных
В привязке данных участвуют несколько свойств, методов и классов:
- класс
Bindingнаследуется отBindingBaseи инкапсулирует множество характеристик привязки данных; - свойство
BindingContextопределено в классеBindableObject; - метод
SetBindingтакже определен в классеBindableObject; - класс
BindableObjectExtensionsопределяет три дополнительных методаSetBinding.
Следующие два класса поддерживают расширения разметки XAML для привязок:
BindingExtensionподдерживает расширение разметкиBinding.ReferenceExtensionподдерживает расширение разметкиx:Reference.
В привязке данных участвуют два интерфейса:
INotifyPropertyChangedв пространстве именSystem.ComponentModelиспользуется для реализации уведомлений об изменении свойства;IValueConverterиспользуется для определения небольших классов, которые в привязках данных преобразуют значения из одного типа в другой.
Привязка данных соединяет два свойства одного объекта или (чаще) двух разных объектов. Эти два свойства называются исходным и целевым. Как правило, изменение исходного свойства приводит к изменению целевого свойства, но иногда направление изменяется. Но, в любом случае:
- целевое свойство должно подкрепляться
BindableProperty; - исходное свойство обычно является членом класса, который реализует
INotifyPropertyChanged.
Класс, который реализует INotifyPropertyChanged, запускает событие PropertyChanged при изменении значения свойства. BindableObject реализует INotifyPropertyChanged и автоматически вызывает событие PropertyChanged, когда подкрепленное BindableProperty свойство изменяет значения. Но можно написать собственные классы с реализацией INotifyPropertyChanged без наследования от BindableObject.
Код и XAML
В примере OpacityBindingCode показано, как задать привязку данных в коде.
- Исходным является свойство
ValueобъектаSlider. - Целевым является свойство
OpacityобъектаLabel.
Эти два объекта связываются путем присвоения BindingContext из объекта Label в объект Slider. Эти два свойства связываются путем вызова метода расширения SetBinding для Label со ссылкой на привязываемое свойство OpacityProperty и свойство Value объекта Slider, выраженное строковым значением.
Теперь изменение Slider приводит к тому, что Label исчезает и появляется снова.
OPacityBindingXaml — это такая же программа, но в ней привязка данных настроена в XAML. BindingContext в Label содержит расширение разметки x:Reference, которое ссылается на Slider, а свойство Opacity в Label содержит расширение разметки Binding, у которого свойство Path ссылается на свойство Value объекта Slider.
Источник и BindingContext
В примере BindingSourceCode показан другой подход, реализуемый в коде. Для создания объекта Binding свойству Source присваивается объект Slider, а свойству Path задается значение "Value". Затем для объекта Label вызывается метод SetBinding из BindableObject.
Конструктор Binding также можно использовать для определения объекта Binding.
В примере BindingSourceXaml показан аналогичный подход с использованием XAML. Свойству Opacity объекта Label присвоено расширение разметки Binding, где Path получает значение свойства Value, и Source содержит внедренное расширение разметки x:Reference.
Итак, у нас есть несколько способов указать исходный объект для привязки:
- через свойство
BindingContextв целевом объекте; - через свойство
Sourceв самом объектеBinding.
Если указаны оба варианта, второй имеет более высокий приоритет. Преимуществом BindingContext является то, что оно распространяется через визуальное дерево. Это очень удобно, если несколько целевых свойств привязаны к одному и тому же исходному объекту.
Программа WebViewDemo демонстрирует этот способ на примере элемента WebView. Два элемента Button для перемещения вперед и назад наследуют BindingContext от своего родительского элемента, который ссылается на WebView. Затем свойства IsEnabled двух кнопок получают простые расширения разметки Binding, нацеленные на свойства IsEnabled кнопки, как определяется свойствами CanGoBack и CanGoForward только для чтения в объекте WebView.
Режим привязки
Присвойте свойству Mode объекта Binding значение одного из элементов перечисления BindingMode:
OneWayозначает, что изменение исходного свойства влияет на целевое;OneWayToSourceозначает, что изменение целевого свойства влияет на исходное;TwoWayозначает, что исходное и целевое свойства влияют друг на друга;Defaultозначает, что используетсяDefaultBindingMode, указанное при создании целевогоBindableProperty. Если не указано ни одно значение, по умолчанию используетсяOneWayдля обычных привязываемых свойств иOneWayToSourceдля привязываемых свойств только для чтения.
Примечание.
Перечисление BindingMode теперь также включает OnTime, при выборе которого привязка применяется только в случае изменения контекста привязки, а не изменения исходного свойства.
Свойства, которые могут стать целевыми для привязки данных в сценариях MVVM, обычно имеют для DefaultBindingMode значение TwoWay. К ним относятся:
- свойство
ValueобъектовSliderиStepper; - свойство
IsToggledобъектаSwitch. - свойство
TextобъектовEntry,EditorиSearchBar; - свойство
DateобъектаDatePicker. - свойство
TimeобъектаTimePicker.
В примере BindingModes демонстрируются четыре режима привязки данных, где целевым является свойство FontSize объекта Label, а исходным — свойство Value объекта Slider. Это позволяет каждому Slider управлять размером шрифта соответствующего Label. Однако элементы Slider не инициализируются, так как DefaultBindingMode для свойства FontSize имеет значение OneWay.
В примере ReverseBinding настраивается привязка свойства Value объекта Slider к свойству FontSize каждого объекта Label. Кажется, что должно быть наоборот, но так лучше работает инициализация элементов Slider, так как в свойстве Value объекта Slider параметр DefaultBindingMode имеет значение TwoWay.
Похожим способом привязки определяются в MVVM, и вы будете часто использовать этот тип привязки.
Форматирование строк
Если целевое свойство имеет тип string, вы можете применить свойство StringFormat, определенное в BindingBase, для преобразования исходного свойства в string. Задайте для свойства StringFormat строку форматирования .NET, которая будет использоваться совместно со статическим форматом String.Format для отображения объекта. При использовании этой строки форматирования в расширении разметки ее следует заключить в одинарные кавычки, чтобы фигурные скобки не были ошибочно приняты за внедренное расширение разметки.
В примере ShowViewValues показано использование StringFormat в XAML.
В примере WhatSizeBindings демонстрируется отображение размера страницы с привязками к свойствам Width и Height объекта ContentPage.
Почему "путь" так называется?
Свойство Path ("Путь") объекта Binding получило такое название, так как оно может содержать серию свойств и индексаторов, разделенных точками. В BindingPathDemos представлено несколько примеров.
Преобразователи значений привязки
Если исходное и целевое свойства привязки имеют разные типы, преобразование между этими типами можно выполнить с помощью преобразователя привязок. Этот класс реализует интерфейс IValueConverter и содержит два метода: Convert для преобразования исходного значения в целевое и ConvertBack для преобразования целевого значения в исходное.
Класс IntToBoolConverter из библиотеки Xamarin.FormsBook.Toolkit служит примером преобразования int в bool. Это демонстрируется в примере ButtonEnabler, который включает Button только в том случае, если в Entry введен хотя бы один символ.
Класс BoolToStringConverter преобразует bool в string и определяет два свойства, чтобы указать текст для возвращаемых значений false и true.
BoolToColorConverter действует аналогично. В примере SwitchText показано использование этих двух преобразователей для отображения разных текстов разными цветами на основе значения параметра Switch.
Универсальный BoolToObjectConverter может заменить BoolToStringConverter и BoolToColorConverter, выполняя роль обобщенного преобразователя bool в объект любого типа.
Привязки и пользовательские представления
Вы можете упростить пользовательские элементы управления, используя привязки данных. В файле кода NewCheckBox.cs определяются свойства Text, TextColor, FontSize, FontAttributes и IsChecked, но он не содержит логику для визуальных элементов управления.
Вместо этого в файле NewCheckBox.cs.xaml определена вся разметку для визуальных элементов управления через привязки данных в элементах Label, основанные на свойствах в файле кода программной части.
В примере NewCheckBoxDemo демонстрируется пользовательский элемент управления NewCheckBox.
