До сих пор, при изучении привязки в .NET MAUI мы ограничивались примерами, в которых в качестве источника привязки выступали объекты типов, определенные в .NET MAUI в которых уже всё настроено для обеспечения нормальной работы приложения. При этом, инфраструктура .NET MAUI позволяет привязываться вообще к любым объектам в приложении, в том числе и к объектам типы которых разрабатываются нами самостоятельно.
Привязка к произвольному объекту C#
Создадим новое приложение .NET MAUI и добавив в проект следующий класс:
namespace MauiApp15
{
public class Project
{
public string Name { get; set; }
public bool IsActive { get; set; }
public double Cost { get; set; }
}
}
Теперь откроем файл отдельного кода MainPage.xaml.cs и изменим его следующим образом:
namespace MauiApp15
{
public partial class MainPage : ContentPage
{
public Project Project { get; set; }
public MainPage()
{
InitializeComponent();
Project = new Project()
{
Name = "Test",
Cost = 100000.56,
IsActive = true,
};
}
}
}
Теперь у класса MainPage появилось свойство типа Project, к которому мы можем сделать привязку в интерфейсе приложения. Отредактируем XAML-код страницы MainPage следующим образом:
<?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"
xmlns:local="clr-namespace:MauiApp15"
x:Class="MauiApp15.MainPage">
<ContentPage.Resources>
<ResourceDictionary>
<local:Project x:Key="MyProject" Cost="10000" Name="Test" IsActive="True"/>
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView>
<VerticalStackLayout BindingContext="{StaticResource MyProject}"
Padding="30,0"
Spacing="25">
<Entry Text="{Binding Name}"/>
<Label Text="{Binding Name}"/>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Здесь объект типа Project определен как статический ресурс с ключом MyProject:
<ContentPage.Resources>
<ResourceDictionary>
<local:Project x:Key="MyProject" Cost="10000" Name="Test" IsActive="True"/>
</ResourceDictionary>
</ContentPage.Resources>
Далее, для проверки работы привязки мы привязываем элементы Entry и Label к свойству Name ресурса. В результате ожидается следующая работа приложения — при изменении названия проекта в Label должно отразиться новое имя. По факту же мы получим вот такой результат:
То есть, изначально привязка срабатывает и в Label, и в Entry выводится имя проекта, однако при изменении имени в Entry, элемент Label не получает никаких изменений так как наш объект никаким образом не сигнализирует об изменении своих свойств.
Интерфейс INotifyPropertyChanged
Для того, чтобы наш объект мог сообщать любым другим объектам в приложении об изменении своих свойств, он должен реализовать интерфейс INotifyPropertyChanged. Этот интерфейс предоставляет нам следующее событие:
event PropertyChangedEventHandler? PropertyChanged;
public delegate void PropertyChangedEventHandler(object? sender, PropertyChangedEventArgs e);
public class PropertyChangedEventArgs : EventArgs
{
public virtual string? PropertyName { get; }
}
То есть в аргументах события должно передаваться имя измененного свойства в виде обычной строки. Перепишем код нашего класса следующим образом:
public class Project : INotifyPropertyChanged
{
string name = "";
bool isActive = false;
double cost = 0;
public string Name {
get => name;
set
{
if (name != value)
{
name = value;
OnPropertyChanged();
}
}
}
public bool IsActive {
get => isActive;
set {
if (isActive != value)
{
isActive = value;
OnPropertyChanged();
}
}
}
public double Cost
{
get => cost;
set {
if (cost != value)
{
cost = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
При изменении значения какого-либо свойства элемента вызывается метод OnPropertyChanged(), который и генерирует событие интерфейса. Обратите внимание на атрибут [CallerMemberName] у параметра этого метода. Атрибут CallerMemberName позволяет не указывать вручную имя измененного свойства.
Теперь, если запустить приложение, то результат будет такой, как мы и ожидали:
Теперь наш объект сообщает об изменении своих свойств и привязка работает так как и ожидалось.
Итого
В .NET MAUI мы можем делать привязку к объектам любого класса. Для того, чтобы привязка к произвольному объекту работала, объект должен сообщать об изменении своих свойств. Для этого класс объекта должен реализовать интерфейс INotifyPropertyChanged, который предоставляет нам событие PropertyChanged.