Передача данных при навигации

Последнее обновление: 19.02.2023

Рассмотрим, как мы можем передавать данные из одной страницы в другую. Здесь могут быть различные варианты. Наиболее распространенный способ представляет передача данных через конструктор.

Например, пусть у нас есть две страницы:

class PageA : ContentPage
{
	public PageA()
    {
        //........
    }
}

class PageB : ContentPage
{
	public PageB(int x)
    {
        //............
    }
}

Страница PageB в конструкторе в качестве параметра принимает некоторое число, и чтобы перейти на нее из страницы PageA, мы могли бы использовать следующее выражение:

await Navigation.PushAsync(new PageB(56));

Другой вариант состоит в использовании методов или свойств второй страницы для передачи в нее данных. Например, пусть в PageB определен некий метод, принимающий в качестве параметра число:

class PageB : ContentPage
{
	public void Calculate(int x)
    {
    }
}

Тогда передать данные в этот метод из PageA мы могли бы следующим способом:

PageB pageB = new PageB();
await Navigation.PushAsync(pageB);
pageB.Calculate(56);

Теперь рассмотрим на реальном примере. Вначале добавим в проект класс Person, с объектами которого мы будем работать в программе:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace HelloApp;

public class Person : INotifyPropertyChanged
{
    string name = "";
    int age;

    public event PropertyChangedEventHandler? PropertyChanged;

    public string Name
    {
        get => name;
        set
        {
            if (name != value)
            {
                name = value;
                OnPropertyChanged();
            }
        }
    }
    public int Age
    {
        get => age;
        set
        {
            if (age != value)
            {
                age = value;
                OnPropertyChanged();
            }
        }
    }
    public void OnPropertyChanged([CallerMemberName] string prop = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
    }
}

Важно, что этот класс реализует интерфейс INotifyPropertyChanged, что даст возможность элементам пользовательского интерфейса автоматически синхронизировать значения со значениями свойств объекта Person.

Далее добавим в проект новую страницу по типу Content Page, которую назовем PersonPage:

Добавление новой страницы XAML в .NET MAUI и C#

В 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"
             x:Class="HelloApp.MainPage"
             xmlns:local="clr-namespace:HelloApp"
             Title="Список пользователей">
    <StackLayout>
        <Button Text="Добавить" Clicked="AddButton_Click" />
        <ListView x:Name="peopleList" ItemsSource="{Binding}" ItemSelected="OnListViewItemSelected">
            <ListView.Header>
                <Grid BackgroundColor="#ddd">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Label Text="Имя" FontSize="16" Grid.Column="0" />
                    <Label Text="Возраст" FontSize="16" Grid.Column="1" />
                </Grid>
            </ListView.Header>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ViewCell.View>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <Label Text="{Binding Name}" FontSize="16" Grid.Column="0" />
                                <Label Text="{Binding Age}" FontSize="15" Grid.Column="1" />
                            </Grid>
                        </ViewCell.View>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

Здесь в ListView будет выводиться список объектов Person. По нажатию на кнопку будет открываться форма для добавления нового элемента, а в результате выбора элемента в списке ListView выбранный элемент будет передаваться на ту же форму для редактирования.

И в коде c# у MainPage определим обработчики кнопок и выделения списка:

using System.Collections.ObjectModel;

namespace HelloApp;

public partial class MainPage : ContentPage
{
    ObservableCollection<Person> People { get; set; }

    public MainPage()
    {
        InitializeComponent();

        People = new ObservableCollection<Person>
        {
            new Person {Name="Tom", Age = 38},
            new Person {Name="Bob", Age = 42},
            new Person {Name="Sam", Age = 25},
        };
        peopleList.BindingContext = People;
    }
    // обработчик выбора элемента в списке
    async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs args)
    {
        // Получаем выбранный элемент
        if (args.SelectedItem is Person selectedPerson)
        {
            // Снимаем выделение
            peopleList.SelectedItem = null;
            // Переходим на страницу редактирования элемента 
            await Navigation.PushAsync(new PersonPage(selectedPerson));
        }
    }
    // переходим на страницу PersonPage для добавления нового элемента
    async void AddButton_Click(object sender, EventArgs e)
    {
        await Navigation.PushAsync(new PersonPage(null));
    }
    // вспомогательный метод для добавления элемента в список
    protected internal void AddPerson(Person phone)
    {
        People.Add(phone);
    }
}

На странице PersonPage в 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="HelloApp.PersonPage"
             Title="Информация о пользователе">
    <StackLayout>
        <Entry x:Name="nameEntry" Text="{Binding Path=Name}"  />
        <StackLayout Orientation="Horizontal">
            <Stepper x:Name="ageStepper" Minimum="0" Maximum="110" Increment="1"
               Value="{Binding Path=Age}"/>
            <Label x:Name="ageLbl" FontSize="18" Text="{Binding Source={x:Reference Name=ageStepper}, Path=Value }" />
        </StackLayout>
        <Button Text="Сохранить" Clicked="SavePerson" />
    </StackLayout>
</ContentPage>

А в файле кода C# для PersonPage следующие строки:

namespace HelloApp;

public partial class PersonPage : ContentPage
{
    bool edited = true; // флаг редактирования
    // добавляемый/редактируемый пользователь
    Person Person { get; set; }
    public PersonPage(Person? person)
    {
        InitializeComponent();

        if (person is null)
        {
            Person = new Person();
            edited = false;
        }
        else
        {
            Person = person;
        }
        BindingContext = Person;
    }

    async void SavePerson(object sender, EventArgs e)
    {
        await Navigation.PopAsync();

        // если добавление
        if (edited == false)
        {
            if(Application.Current?.MainPage is NavigationPage navPage)
            {
                // стек навигации
                IReadOnlyList<Page> navStack = navPage.Navigation.NavigationStack;
                // количество страниц в стеке
                int pageCount = navPage.Navigation.NavigationStack.Count;
                // находим в стеке предыдущую страницу - то есть MainPage
                if (navStack[pageCount - 1] is MainPage mainPage)
                {
                    // вызываем у главной страницы метод AddPerson для добавления
                    mainPage.AddPerson(Person); 
                }
            }
        }
    }
}

Для разграничения ситуаций добавления и редактирования здесь определена дополнительная переменная edited. Если в конструктор страницы передается объек Person, то эта переменная равна true. Если же в конструктор передается значение null, то переменная равна false, и создается новый объект Person.

В обработчике кнопки SavePerson(), если у нас редактирование, то мы просто возвращаемся назад на предыдущую страницу. Поскольку редактируемый объект Person реализует интерфейс INotifyPropertyChanged, то нам не надо выполнять никаких дополнительных действий, и соответствующий объект на главной станице MainPage будет сам автоматически обновлен.

Если же у нас добавление, то получаем из стека навигации страницу MainPage и вызываем у нее метод AddPerson() для добавления объекта. Стоит также заметить, что на странице MainPage привязка списка идет не к простому списку List, а к объекту ObservableCollection, что позволяет автоматически обновить привязанный объект ListView в случае добавления нового объекта.

Запустим проект, и на странице отобразится список объектов. Мы можем нажать на кнопку добавления, и произодейт переход к странице PersonPage, где можно добавить новый объект:

Привязка списка к ListView в .NET MAUI и C#

Подобным образом можно выберать какой-либо объект, и он будет передан на страницу PersonPage.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850