Обычно, в любом приложении, будь то приложение .NET MAUI, Blazor или любое другое приложение, можно выделить, как минимум, две части — это интерфейс пользователя, используя который, пользователь взаимодействует с приложением (frontend) и часть, в которой происходит сбор, обработка и хранение данных (backend). Одна из задач, которая стоит перед разработчиком приложения состоит в том, чтобы организовать взаимодействие этих частей — когда пользователь вводит какие-либо данные, то эти данные должны быть каким-либо образом использованы приложением и наоборот — если приложение производит какие-либо изменения в данных, то эти данные должны отобразиться в интерфейсе пользователя. Одним из распространенных решений этой задачи является использование событий: один объект сообщает посредствам событий об изменениях, другой (или другие объекты) — производит какую-либо работу по обработке этих изменений. Однако, наличие большого количества разнообразных объектов приводит к такому же разнообразию обработчиков событий в приложении и, как следствие, код приложения становится трудночитаемым и поддерживаемым, содержит большой объем однотипного стандартного кода. Механизм привязки позволяет автоматизировать процесс передачи данных от одного объекта к другому.
Общие сведения о привязке
Привязка — это метод связывания свойств двух объектов таким образом, чтобы изменения в свойстве одного объекта автоматически отражались свойстве другого объекта.
Эти два объекта называются целевым объектом (source) и источником (target):
- Целевой объект — это объект (и свойство), к которому устанавливается привязка данных.
- Источник — это объект (и свойство), на который ссылается привязка данных.
Целевым объектом обычно выступает како-либо элемент управления (кнопка, метка, текстовое поле и т.д.), производный от BindableObject
. Что касается источника привязки, то таким объектом может выступать как объект, производный от BindableObject
, так и, в принципе, объект любого класса.
Привязка всегда настраивается в целевом объекте и указывает на исходный объект.
Привязка в коде C#
Чтобы настроить привязку данных в коде C#, в .NET MAUI используются следующие два члена класса цели:
- Свойство
BindingContext
, которое задает объект-источник. - Метод
SetBinding()
, который указывает два связываемых свойства: целевое и исходное.
Рассмотрим простой пример создания привязки данных в .NET MAUI. Создайте новое приложение .NET MAUI и измените файл MainPage.xaml следующим образом:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiApp11.MainPage"> <ScrollView> <VerticalStackLayout Padding="30,0" Spacing="25"> <Entry x:Name="textEdit"/> <Label x:Name="textLabel"></Label> </VerticalStackLayout> </ScrollView> </ContentPage>
Пусть наша задача будет состоять в том, чтобы при вводе текста в Entry
этот текст отображался в Label
. Если НЕ использовать привязку, то такую задачу можно решить с использованием события TextChanged
у элемента Entry
. Создадим новый обработчик события в файле отдельного кода:
namespace MauiApp11 { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } //обработчик события TextChanged private void textEdit_TextChanged(object sender, TextChangedEventArgs e) { textLabel.Text = e.NewTextValue; } } }
и назначим этот обработчик событию Entry
:
<Entry x:Name="textEdit" TextChanged="textEdit_TextChanged"/>
Теперь можно запустить приложение и проверить его работу:Теперь изменим немного код и воспользуемся привязкой. Для этого, во-первых, удалим обработчик события
TextChanged
и изменим XAML-код элемента на предыдущий, то есть на:
<Entry x:Name="textEdit"/>
и, во-вторых, изменим конструктор класса MainPage
следующим образом:
public MainPage() { InitializeComponent(); textLabel.BindingContext = textEdit; textLabel.SetBinding(Label.TextProperty, "Text"); }
Здесь целевым объектом выступает метка, а источником — текстовое поле, поэтому свойство BindingContext
мы устанавливаем именно у метки:
textLabel.BindingContext = textEdit;
Далее мы вызываем метод SetBinding()
, чтобы установить привязку. Здесь обратите внимание на первый параметр метода — Label.TextProperty
. Дело в том, что для установления привязки мы должны указать свойство типа BindableProperty
, которым и является TextProperty
, а не обычно используемое свойство Text
. Более того, свойство TextProperty
статическое,
public static readonly BindableProperty TextProperty;
поэтому мы указываем его, используя класс элемента
textLabel.SetBinding(Label.TextProperty, "Text");
Во втором параметре мы указываем свойство источника в виде обычно строки. Можно запустить приложение и убедиться, что оно работает также, как и в предыдущем случае.
Привязка в XAML
Совсем не обязательно использовать код C# для привязки. В XAML мы также можем осуществить привязку, используя расширения разметки. Для демонстрации этой возможности, перепишем код XAML страницы следующим образом:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiApp11.MainPage"> <ScrollView> <VerticalStackLayout Padding="30,0" Spacing="25"> <Entry x:Name="textEdit"/> <Label x:Name="textLabel" BindingContext="{x:Reference textEdit}" Text="{Binding Text}"></Label> </VerticalStackLayout> </ScrollView> </ContentPage>
При этом код класса MainPage
можно сократить до следующего:
public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } }
При указании свойства BindingContext
у Label
мы воспользовались расширением разметки x:Reference
, чтобы передать ссылку на текстовое поле textEdit
. Что касается свойства Text
метки, то здесь мы также воспользовались расширением разметки Binding
указав в качестве параметра свойство объекта-источника Text
. То есть, фактически, мы произвели те же самые действия в XAML, что и ранее в коде C# — определили контекст привязки и установили привязку к свойству Text
.
Расширения x:Reference и Binding могут содержать различные параметры. Например, во всех представленных выше примерах мы использовали важное для привязки свойство элемента — BindingContext. Однако, мы можем не указывать это свойство явно в коде. Вместо этого мы можем воспользоваться параметром Source расширения Binding и сделать код XAML для метки следующим:
<Label x:Name="textLabel" Text="{Binding Source={x:Reference textEdit}, Path=Text}"></Label>
Здесь в параметре Source
мы также передаем ссылку на объект-источник, а в параметре Path
— путь к свойству источника. Следует отметить, что параметр Source
у Binding
имеет приоритет над свойством BindingContext
. То есть, если в коде указано и свойство BindingContext
и параметр Source
, то использоваться будет объект, указанный в Source
.
Расширение разметки Binding
имеет свои преимущества, по сравнению с определением привязки в коде. Например, мы можем привязать различные свойства Label
к свойствам различных объектов. Например, изменим код XAML страницы следующим образом:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiApp11.MainPage"> <ScrollView> <VerticalStackLayout Padding="30,0" Spacing="25"> <Slider Maximum="90" Minimum="-90" x:Name="Rotator"/> <Entry x:Name="textEdit"/> <Label x:Name="textLabel" Text="{Binding Source={x:Reference textEdit}, Path=Text}" Rotation="{Binding Source={x:Reference Rotator}, Path=Value}"/> </VerticalStackLayout> </ScrollView> </ContentPage>
Здесь мы привязываем свойство Text
метки к свойству Text
поля ввода, а свойство Rotation
— к свойству Value
объекта Rotator
типа Slider
. Теперь можно запустить приложение, ввести какой-нибудь текст в поле ввода и изменить значение Slider
, чтобы метка начала поворачиваться:
В дальнейшем, при рассмотрении вопросов, связанных с привязкой, чаще всего мы будем использовать именно расширение разметки XAML для демонстрации тех или иных возможностей.
Итого
Привязка
— это метод связывания свойств двух объектов таким образом, чтобы изменения в свойстве одного объекта автоматически отражались свойстве другого объекта. Привязку можно осуществлять как в коде C#, так и в коде XAML, используя для этого расширения разметки. Расширение разметки Binding
имеет свои преимущества — так, используя Binding
в XAML мы можем привязывать разные свойства объекта-цели к свойствам нескольких объектов-источников.