До сих пор, при изучении привязки в .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
.