Привязка в .NET MAUI. Привязка к произвольным объектам (интерфейс INotifyPropertyChanged)

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

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии