最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

焦点热讯:MAUI新生6.5-导航路由Navigation

来源:博客园

MAUI的Shell导航框架,也是以路由方式进行导航,并提供了两套导航方式,一是如前面章节所述的视觉层次结构,会自动建立导航路由,可以进行不同层次页面的导航切换;二是为页面手动注册路由,并执行代码导航。


(相关资料图)

一、注册路由

1、视觉层次结构页面的路由注册

在视觉层次结构中(Shell>FlyoutItem或TabBar>Tab>ShellContent),框架自动建立导航路由,可以直接进行导航切换。如果要通过代码导航到视觉层次页面,可以在定义视觉层次结构时,显示的定义路由,如:

                                                                            animals    domestic        cats        dogs    monkeys    bears    elephantsabout

2、非视觉层次结构页面的路由注册

MAUI中还有很多页面,没有在视觉层次结构中定义,这些页面需要进行手动注册路由,一般在AppShell后台代码的构造函数中进行。

public partial class AppShell : Shell{    public AppShell()    {        InitializeComponent();        //注册非视觉层次页面路由,所有路由名称需保持唯一,它们是全局的        //当导航到视觉层次结构中的路由时,并不会创建导航堆栈;但导航到非视觉层次页面路由时,创建导航堆        Routing.RegisterRoute("dogdetail",typeof(DogDetail));        Routing.RegisterRoute("monkeydetail", typeof(MonkeyDetail));        //也可以将路由注册到不同的视觉层次结构上,可以实现跟踪当前路由层次,导航到不同的页面        //如下例中,都是导航到detail,但在dogs路由层次结构中时,将导航到DogDetail;反之,将导航到MonkeyDetail        Routing.RegisterRoute("dogs/detail", typeof(DogDetail));        Routing.RegisterRoute("monkeys/detail", typeof(MonkeyDetail));    }}

二、执行导航

1、在视觉层次结构中,可以直接执行导航跳转。注:这些跳转页面,不会进入到导航堆栈中。

2、非视觉层次结构的页面,需要通过编程式导航来实现。

//下例为Monkeys页面,通过按钮点击事件进行导航public partial class Monkeys : ContentPage{    ......private async void Button_Clicked(object sender, EventArgs e)    {        //Shell.Curren获得对当前Shell对象的引用,等效于((Shell)App.Current.MainPage)        //Shell对象包括了GoToAsync导航方法,以及CurrentItem、CurrentPage、CurrentState、BackButtonBehavior等属性        await Shell.Current.GoToAsync("dogdetail");        await ((Shell)App.Current.MainPage).GoToAsync("dogdetail");        await DisplayAlert("显示当前路由", Shell.Current.CurrentState.Location.ToString(), "OK");    }}

3、绝对路由和相对路由

  • 视觉层次结构的页面,可以通过绝对路径进行导航,如【Shell.Current.GoToAsync("//animals/domestic/dogs")】
  • 非视觉层次结构的页面,可以通过相对路径进行导航,如【Shell.Current.GoToAsync("dogdetail")】
  • 上下文导航。注册非视觉层次结构页面时,将路由注册到结构层次页面上,如Routing.RegisterRoute("monkeys/detail"...)。当在Monkeys页面中,导航到detail时,会匹配monkeys/detail。
  • 向后导航。向后导航,【await Shell.Current.GoToAsync("..")】;向后导航与路由导航结合,【await Shell.Current.GoToAsync("../route")】;可以多次向后导航,【await Shell.Current.GoToAsync("../../route")】
  • 关于路由导航,还有一些概念比较模糊,建议暂时按以上两种方式来导航

三、导航传参

1、传递参数。

1)方法一:查询字符串

//传递字符串:直接通过查询字符串传递参数//传递一个字符串参数await Shell.Current.GoToAsync("monkeydetail?name=sun");//传递多个字符串参数await Shell.Current.GoToAsync("monkeydetail?name=sun&sex=male");//也可以使用内插值变量string name = "sun"await Shell.Current.GoToAsync($"monkeydetail?name={name}");

2)方法一:字典类型参数

//传递对象:通过GoToAsync方法的第二个参数,IDictionary字典类型对象传参//传递一个对象var p1 = new Person{Name="zs",Age=18};var navigationParam = new Dictionary{    { "person1", p1 }};await Shell.Current.GoToAsync($"persondetail", navigationParame);//传递多个对象var p1 = new Person{Name="zs",Age=18};var p2 = new Person{Name="ls",Age=28};var navigationParam = new Dictionary{    { "person1", p1 }    { "person2", p2 }};await Shell.Current.GoToAsync($"persondetail", navigationParame);

2、接收参数。

1)方法一:通过QueryProperty特性,接收路由参数

//QueryProperty特性//QueryProperty特性的第一个参数为接收路由参数的属性,第一个参数为路由参数的键名//通过查询参数传递的路由参数,会自动转为键值对形式//注意接收路由参数的属性,必须是可观察属性(MVVM),触发PropertyChanged事件[QueryProperty(nameof(Name), "name")][QueryProperty(nameof(Sex), "sex")]public partial class MonkeyDetail : ContentPage{    public MonkeyDetail()    {        InitializeComponent();        BindingContext = this; //将BindingContext设置为当前对象    }    //定义可观察属性Name来接收键名为name的路由参数    private string name;    public string Name    {        get { return name; }        set         {            name = value;            OnPropertyChanged();        }    }    //定义可观察属性Sex来接收键名为sex的路由参数    private string sex;    public string Sex    {        get { return sex; }        set        {            sex = value;            OnPropertyChanged();        }    }}//XAML文件中使用路由参数            

2)方法二:通过实现IQueryAttributable接口,接收路由参数(在ViewModel中使用)

//接收字符串路由参数public class PersonDetailViewModel : IQueryAttributable, ObservableObject{    [ObservableProperty]    private string name;    [ObservableProperty]    private string sex;    public void ApplyQueryAttributes(IDictionary query)    {        name = HttpUtility.UrlDecode(query["name"].ToString());        sex = HttpUtility.UrlDecode(query["sex"].ToString());    }}//接收对象类型参数public class PersonDetailViewModel : IQueryAttributable, INotifyPropertyChanged{    [ObservableProperty]    private Person person;    public void ApplyQueryAttributes(IDictionary query)    {        person = query["p1"] as Person;    }    ...}

四、路由守卫

1、全局守卫:类似于生命周期函数,Shell类提供OnNavigating(导航发生前)和OnNavigated(导航发生后)可重写方法,通过重写这两个方法,可以对导航进行控制,实现路由守卫的功能。OnNavigating和OnNavigated方法,在AppShell.xaml.cs中定义。

//OnNavigating和OnNavigated方法的常用属性和方法public partial class AppShell : Shell{    public AppShell()    {        InitializeComponent();        ......    }    protected override void OnNavigating(ShellNavigatingEventArgs args)    {        base.OnNavigating(args);        ShellNavigationState current = args.Current;//当前页,可通过Location属性获取URL        ShellNavigationState target = args.Target; //目标页,可通过Location属性获取URL        ShellNavigationSource source = args.Source; //导航类型,枚举,包括Unknown/Push/Pop/PopToRoot/Insert/Remove/ShellItemChanged/ShellSectionChanged/ShellContentChanged        bool canCancle = args.CanCancel; //是否可以取消        bool canclled = args.Cancelled; //是否取消        args.Cancel(); //取消导航        //获取导航令牌,并完成导航        ShellNavigatingDeferral token = args.GetDeferral();        token.Complete();    }    protected override void OnNavigated(ShellNavigatedEventArgs args)    {        base.OnNavigated(args);        ShellNavigationState current = args.Current; //当前页        ShellNavigationState previous = args.Previous; //上一页        ShellNavigationSource source = args.Source; //导航类型    }}//案例一:取消各后导航protected override void OnNavigating(ShellNavigatingEventArgs args){    base.OnNavigating(args);    if (args.Source == ShellNavigationSource.Pop)    {        args.Cancel();    }}//案例二、跟进弹出框的选择按钮,确定是否继续导航protected override async void OnNavigating(ShellNavigatingEventArgs args){    base.OnNavigating(args);    ShellNavigatingDeferral token = args.GetDeferral();    var result = await DisplayActionSheet("Navigate?", "Cancel", "Yes", "No");    if (result != "Yes")    {        args.Cancel();    }    token.Complete();}

2、局部守卫:Shell层次结构中的Tab,提供了一系列的重写方法。我们可以自定义Tab的派生类,并重新定义这些重写方法。在视觉层次结构中使用自定义的Tab派生类,就可以控制这个Tab下的路由行为,从而实现局部守卫的功能。

public class MyTab:Tab{    protected override void OnInsertPageBefore(Page page, Page before)    {        base.OnInsertPageBefore(page, before);    }    protected override void OnRemovePage(Page page)    {        base.OnRemovePage(page);    }    protected override Task OnPopAsync(bool animated)    {        return base.OnPopAsync(animated);    }    protected override Task OnPushAsync(Page page, bool animated)    {        return base.OnPushAsync(page, animated);    }    protected override Task OnPopToRootAsync(bool animated)    {        return base.OnPopToRootAsync(animated);    }}

五、后退按钮

当导航到非结构层次页面时,会创建导航堆栈,并显示后退按钮,可以重新定义后退按钮的样式和行为

                    ......

六、Navigation导航

Navigation导航类,在Shell框架中仍然可以使用,但不建议混合使用。Navigation会创建导航堆栈,并显示后退按钮。如:

//导航和后退await Navigation.PushAsync(new DetailsPage());await Navigation.PopAsync();await Navigation.PushModalAsync(new DetailsPage());await Navigation.PopModalAsync();//导航传参Contact contact = new Contact{    Name = "Jane Doe",    Age = 30,    Occupation = "Developer",    Country = "USA"};...await Navigation.PushModalAsync(new DetailsPage(contact));//通过BindingContext导航传参Contact contact = new Contact{    Name = "Jane Doe",    Age = 30,    Occupation = "Developer",    Country = "USA"};await Navigation.PushAsync(new DetailsPage{    BindingContext = contact  });

关键词: 视觉层次 重新定义