一个常规的App是由多个Page组成的,出现多个Page就会涉及页面跳转问题。Xamarin.Forms页面之间的跳转通过Navigation Stack管理Page,如页面A跳转到页面B时,会将B压入栈定,此时页面B成为活动页面,执行Back操作时,页面B从栈定推出使页面A重新变为活动页面。
每个应用程序都有一个特殊页作为应用程序的入口(main page, or the home page, or the start page),Xamarin.Forms中由App的MainPage属性设置。
INavigation介绍
Xamarin.Forms中页面分为Modal pages(模态页面) 和 modeless pages(非模态页面),跳转到一个新的页面可以通过PushAsync
和PushModalAsync
两个方法实现,两个方法均传入一个Page对象作为参数。同样提供了PopAsync
和PopModalAsync
两个方法返回前一个页面。PushAsync和PopAsync是对非模态页面的操作,PushModalAsync和PopModalAsync操作的是模态页面。PopToRootAsync方法表示回到导航栈低页面。RemovePage方法从导航栈中删除一个页面。InserPageBefore方法将一个page插入到指定page之前。通过这些方法操作Navigation Stack可以在不同Page间跳转。
关于PopXXX和Push方法定义返回Task类型介绍参考(涉及的OnDisappearing和OnAppearing不在本文不再说明):
http://www.cnblogs.com/qiandi/p/5598742.html
当我们调用PushAsync方法时必须修改App的MainPage属性为NavigationPage对象,否则报如下异常,使用NavigationPage时不必在为iOS单独设置Page的Padding属性解决页面和状态栏遮盖问题。
PopXXX和PushXXX提供的bool类型参数重载方法设置为true增加页面跳转动画。
INavigation还定义了两个IReadOnlyListModalStack
和NavigationStack
,NavigationStack表示非模态页面的集合,PushAsync和PopAsync会改变NavigationStack的内容,ModalStack表示模态页面的集合PushModalAsync和PopModalAsync会改变ModalStack的内容,这两个属性不能直接修改,且提供了类似堆栈的功能。这两个集合不能混合跳转,非模态页面可以导航到模态页面但是模态页面不能导航到非模态页面。
如果用MainPage = new NavigationPage(new Page0());
初始化App的MainPage属性运行应用程序,此时IOS平台中ModalStack为空,Android和Windows平台ModalStack包含一个元素(MainPage对应NavigationPage实例)。三个平台中的NavigationStack集合包均含一个Page0的实例。
这些方法均定义在INavigation中,VisualElement提供了一个INavigation类型只读属性Navigation,可以通过调用Navigation的方法实现跳转。
页面中调用代码Navigation.PushAsync(new ModelessPage(), true);
Programmers familiar with Android architecture are sometimes curious how Xamarin.Forms page navigation integrates with the aspect of Android application architecture known as the activity. A Xamarin.Forms application running on an Android device comprises only one activity, and the page navigation is built on top of that. A ContentPage is a Xamarin.Forms object; it is not an Android activity, or a fragment of an activity.
前面提到的参考链接有说明,什么意思自己看看吧!!!
NavigationPage介绍
NavigationPage的作用就是导航管理页面。
NavigationPage提供的属性
- BarBackgroundColor - 获取、设置NavigationPage顶部导航栏的背景色(iOS、Android、Windows 平台有效)。
- BarTextColor - 获取、设置NavigationPage顶部导航栏显示文本颜色(iOS、Windows平台有效)。
不同平台效果:
- CurrentPage - 获取Navigation Stack最顶部页面,不管当前显示页面是模态页面还是非模态页面,CurrentPage都表示NavigationStack集合中的最后一项。
when a modal page is active, CurrentPage continues to indicate the last modeless page that was active before navigation to a modal page
NavigationPage提供的BindableProperty
- HasBackButtonProperty - 是否显示非模态页面导航栏的返回按钮(iOS、Android起作用)
C#设置NavigationPage.SetHasBackButton(this, false);
XAML设置NavigationPage.HasBackButton="False"
- HasNavigationBarProperty - 是否显示导航栏
- BackButtonTitleProperty - 设置返回按钮的文本(仅iOS平台)
- TitleIconProperty - 设置导航栏上显示图标(iOS平台Icon代替Title,Android修改左侧图标显示,Windows 无效)
屏蔽Android、Windows Mobile 返回按键
Android和Windows Phone会包含一个返回键,返回键提供类似PopAsync或PopModalAsync的工能,程序中要屏蔽返回键的功能需要重写Page的OnBackButtonPressed
方法。OnBackButtonPressed方法返回true值,程序不处理返回按键。
protected override bool OnBackButtonPressed()
{
//return base.OnBackButtonPressed();
return true;
}
Page还定义了SendBackButtonPressed
方法,用来模拟返回按钮被按下。调用该方法与Android按下返回键功能类似。
官方电子书中提到“Although this works on iOS and Android, it currently does not work on the Windows Runtime platforms.”这个方法只对iOS和Android有效,Windows Runtime platforms不能正常工作。 实际测试iOS无效,Android正常,Windows 无法测试。
页面间传值
一个应用程序会包含多个页面,把数据从一个页面传到另一个页面该怎么做?
构造函数传值
页面跳转的PushXXX方法传入Page页面实例作为参数,可以通过Page页面的构造函数传入数据,如Navigation.PushModalAsync(new DataPage(label.Text));
,在DataPage重载的构造函数中在处理接收的数据。
属性方法传值
根据页面的属性或调用方法传值。如:
构造函数传值是单向的不能传递返回数据,通过属性传值可以从当前页面向前一个页面传值。应从NavigationStack集合中取得前一个页面实例。
var stack = (App.Current.MainPage as NavigationPage).Navigation.NavigationStack;
int lastIndex = stack.Count - 1;
navigationPage homePage = stack[lastIndex] as navigationPage;
if (homePage == null)
{
homePage = stack[lastIndex - 1] as navigationPage;
}
homePage.SetText(Value + "页面返回数据了");
从模态页面跳转到非模态页面和模态页面跳转到模态页面两种情况,跳转前的页面在NavigationStack中有不同的位置。如果是非模态页面跳转到非模态页面?又要从ModalStack中获取前一个页面实例,所以通过属性和方法传值不推荐!!!
Messaging Center传值
MessagingCenter是一个静态类,提供了Subscribe、Unsubscribe和Send三个公开的方法。Subscribe订阅接收的消息信息,参数、发送者类型等。Unsubscribe取消订阅,不在接收消息。Send发送指定类型消息。
Messaging Center传值示例:
数据接收页面增加消息订阅代码:
MessagingCenter.Subscribe(this, "Value", (arg1, arg2) =>
{
label.Text = arg2;
});
Subscribe包含两个范型参数,第一个为消息发送者类型,第二个为传递数据类型。Subscribe包含三个参数,第一个为消息接收者,第二个参数为字符串类型消息标示,第三个参数是一个lambda表达式,表示接收到消息后的动作。
数据传递页面增加发送消息代码:
MessagingCenter.Send(this, "Value", label.Text);
Send两个范型参数与Subscribe方法相同。Send包含三个参数,第一个参数为消息发送者,第二个参数为消息标示,第三个参数为传递的数据对象。
本示例Send方法应在PushAsync后执行。PushAsync执行前消息没有订阅,Send发送消息此时没有接收者。
不再接收消息时应该调用Unsubscribe取消指定消息的订阅,对资源回收释放。本示例取消订阅代码添加在Subscribe方法的lambda中。
MessagingCenter.Unsubscribe(this, "Value");
Strictly speaking, however, unsubscribing shouldn’t be necessary because the MessagingCenter maintains WeakReference objects for subscribers。
MessagingCenter定义了一个Dictionary
类型对象通过WeakReference管理subscribers,所以Unsubscribe方法不是必须的。, List >>>
事件传值
WinForm中常用的传值形式,事件传值。推荐数据回传时使用。
Page1 跳转到Page2时,Page2添加事件定义:
public EventHandler Value;
Page2 返回Page1 时,触发事件:
EventHandler handler = Value;
if (handler != null)
{
handler(this, "增加返回字符串");
}
Page1 跳转到Page2时,订阅Page2的事件:
var page = new Page2();
page.Value += (sender, e) =>
{
label.Text = e;
};
Navigation.PushAsync(page);
传递复杂数据继承
EventArgs
实现传值
App Class传值
Xamarin.Forms应用程序会提供一个App类(继承Application)作为程序的入口,该对象在应用程序运行期间一直存在,可以借助App类实现不同页面之间数据传递。
修改App代码定义属性保存、获取数据。如:
获取App类实例可以通过(App)Application.Current)
获取。或着直接定义static 属性,直接通过App.Value 传值。