Содержание
Передача данных в параметрах URI в приложениях .NET MAUI, использующих Shell
, осуществляется практически также, как и в веб-приложениях, например, Blazor. При этом, в параметрах URI могут передаваться не только примитивные данные, но и сложные объекты.
Пример приложения
Для начала, создадим небольшой пример приложения .NET MAUI, с помощью которого будет демонстрироваться передача данных в параметрах URI. Создадим новое приложение .NET MAUI и сразу добавим в проект новую страницу с названием DetailPage
:
Сразу добавим для этой страницы модель представления, которую назовем
DetailViewModel
Зарегистрируем эту модель как сервис и используем на странице. Для этого изменим код MauiProgram.cs следующим образом:
using Microsoft.Extensions.Logging; using URIParams.ViewModels; namespace URIParams; public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); builder.Services.AddSingleton<DetailViewModel>(); #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); } }
Запросим модель представления в конструкторе страницы и передадим её в свойство BindingContext
. Изменим код DetailPage.xaml.cs:
using URIParams.ViewModels; namespace URIParams; public partial class DetailPage : ContentPage { public DetailPage(DetailViewModel model) { BindingContext = model; InitializeComponent(); } }
Теперь изменим код страницы DetailPage.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="URIParams.DetailPage" xmlns:vm="clr-namespace:URIParams.ViewModels" x:DataType="vm:DetailViewModel" Title="DetailPage"> <VerticalStackLayout> </VerticalStackLayout>
Здесь мы подключили пространство имен
xmlns:local="clr-namespace:URIParams.ViewModels"
и указали параметр x:DataType
для элемента страницы:
x:DataType="local:DetailViewModel"
для того, чтобы использовать т.н. скомпилированные привязки XAML. Внутри макета VerticalStackLayout
мы будем выводить различные данные, которые будут передаваться с использованием параметров URI, поэтому пока оставим этот элемент без содержимого.
На главную страницу добавим кнопку:
<?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="URIParams.MainPage"> <ScrollView> <VerticalStackLayout Padding="30,0" Spacing="25"> <Button x:Name="NavigateBtn" Text="Перейти" Clicked="OnNavigateBtnClicked" HorizontalOptions="Fill" /> </VerticalStackLayout> </ScrollView> </ContentPage
Обработчик события Clicked
кнопки пока оставим пустым — клик по кнопке будет осуществлять переход на страницу DetailPage
. Теперь у нас всё готово для рассмотрения вопросов, связанных с приемом и передачей данных через URI. Для начала рассмотрим основную теорию, а, затем, доработаем наш пример.
Передача данных в параметрах URI
Передача в параметрах URI может осуществляться при использовании метода GoToAsync()
статического класса Shell
.
Передача примитивных типов данных
Передача примитивных типов данных через параметры URI может осуществляться также, как и в веб-приложениях, то есть URI должен выглядеть следующим образом:
[//]адрес?имя_параметра=значение
Например, напишем следующий код кнопки на главной странице приложения:
private void OnNavigateBtnClicked(object sender, EventArgs e) { Shell.Current.GoToAsync("//details?param=Hello,world!"); }
Здесь мы передаем строку «Hello,world!» в параметре с именем param
. Чтобы передать несколько параметров, необходимо их разделять в URI символом &
. Например,
private void OnNavigateBtnClicked(object sender, EventArgs e) { Shell.Current.GoToAsync("//details?param=Hello,world!&id=123"); }
Здесь мы передаем уже два параметра — param
и id
со значениями Hello,world!
и 123
, соответственно.
Передача сложных объектов
Передача сложных объектов через параметры URI в .NET MAUI осуществляется с использованием перегруженной версии метода GoToAsync()
:
public Task GoToAsync(ShellNavigationState state, IDictionary<string,object> parameters);
Например:
private void OnNavigateBtnClicked(object sender, EventArgs e) { Shell.Current.GoToAsync("//details", new Dictionary<string, object?>() { { "person", new Person() { Id = 1, Name = "Vlad", Description = "https://csharp.webdelphi.ru" }} }); }
Здесь мы передаем в параметрах объект типа Person
с именем параметра person
. Аналогичным образом мы можем передавать несколько объектов или объекты совместно с примитивными типами данных.
Получение данных из URI
Для получения данных из URI могут использоваться два способа: путем реализации интерфейса IQueryAttributable
или с использованием атрибута QueryPropertyAttribute
.
Атрибут QueryPropertyAttribute
Атрибут имеет следующее описание:
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=true)] public class QueryPropertyAttribute : Attribute
И содержим два свойства:
Свойство | Тип | Описание |
Name |
string |
Имя свойства которому будет присваиваться значение параметра |
Query |
string |
Имя параметра в URI |
Например, добавим в приложение модель (класс) Person
:
public class Person { public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } }
И воспользуемся обработчиком Clicked
кнопки в котором в параметрах запроса передается объект типа Person
(см. выше). Допишем нашу модель представления DetailViewModel
следующим образом:
using System.ComponentModel; using System.Runtime.CompilerServices; namespace URIParams.ViewModels { [QueryProperty(nameof(Pers),"person")] public partial class DetailViewModel: INotifyPropertyChanged { private Person _person; public Person Pers { get => _person; set { if (_person != value) { _person = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged([CallerMemberName] string prop = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); } } }
Теперь значение из параметра URI с именем person
будет передаваться в свойство Pers
. Чтобы убедиться в этом, сделаем привязку к Pers
на странице DetailPage
:
<?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="URIParams.DetailPage" xmlns:vm="clr-namespace:URIParams.ViewModels" x:DataType="vm:DetailViewModel" Title="DetailPage"> <VerticalStackLayout> <Label Text="{Binding Pers.Id, Mode=TwoWay}"/> <Label Text="{Binding Pers.Name, Mode=TwoWay}"/> <Label Text="{Binding Pers.Description, Mode=TwoWay}"/> </VerticalStackLayout> </ContentPage>
Запустим приложение и проверим результат. Вот, что мы увидим на странице после клика по кнопке:
Атрибут можно повторять. Например, передадим в параметрах URI два значения. Изменим обработчик события Clicked
кнопки:
private void OnNavigateBtnClicked(object sender, EventArgs e) { Shell.Current.GoToAsync("//details", new Dictionary<string, object?>() { { "person", new Person() { Id = 1, Name = "Vlad", Description = "https://csharp.webdelphi.ru" }}, {"hello", "Привет!" } }); }
Добавим новое свойство в модель представления и определим ещё один атрибут QueryProperty
:
[QueryProperty(nameof(Pers),"person")] [QueryProperty(nameof(Greetings), "hello")] public partial class DetailViewModel: INotifyPropertyChanged { ... private string _greetings; public string Greetings { get { return _greetings; } set { if (_greetings != value) { _greetings = value; OnPropertyChanged(); } } } .... }
Добавим новую метку на страницу DetailPage
:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage ....> <VerticalStackLayout> <Label Text="{Binding Greetings, Mode=TwoWay}" FontSize="18" FontAttributes="Bold"/> .... </VerticalStackLayout> </ContentPage>
Результат работы приложения:
Получение данных навигации с помощью QueryPropertyAttribute
небезопасного и не должно использоваться с полной обрезкой или NativeAOT. Поэтому, следующий способ можно назвать рекомендуемым для получения данных из параметров URI.
Интерфейс IQueryAttributable
Для того, чтобы мы могли считывать данные из параметров URI, класс страницы, которая должна получать данные или модель представления могут реализовать интерфейс IQueryAttributable
. Этот интерфейс содержит всего один метод:
public void ApplyQueryAttributes (IDictionary<string,object> query);
В словаре query
возвращаются все параметры URI и их значения. Например, перепишем нашу модель с использованием этого интерфейса:
using System.ComponentModel; using System.Runtime.CompilerServices; namespace URIParams.ViewModels { public partial class DetailViewModel: IQueryAttributable, INotifyPropertyChanged { private Person _person; public Person Pers { get => _person; set { if (_person != value) { _person = value; OnPropertyChanged(); } } } private string _greetings; public string Greetings { get { return _greetings; } set { if (_greetings != value) { _greetings = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged([CallerMemberName] string prop = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); } public void ApplyQueryAttributes(IDictionary<string, object> query) { if (query.TryGetValue("person", out object? pers)) { if (pers is Person) Pers = (Person) pers; } if (query.TryGetValue("hello", out object? greet)) { Greetings = (string)greet; } } } }
Запустите приложение и убедитесь. что получен результат как на рисунке выше.
Итого
Приложения, использующие Shell, могут передавать любые данные в параметрах URI с использованием метода Shell.GoToAsync()
. Для чтения значений параметров URI и передачи их в свойства используется интерфейс IQueryAttributable
или атрибут QueryPropertyAttribute