Обычно, в любом приложении, будь то приложение .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 мы можем привязывать разные свойства объекта-цели к свойствам нескольких объектов-источников.