xamarin.forms导航的实现,MS提供了多种方法(参考链接), 再此不赘述。
说一下导航封装,以便于在anywhere都能使用。
按面向接口编程与单一职责原则,将导航拆分为页面的跳转(navigation)与页面的激活(Active)两个接口并实现。
导航服务interface
public interface IContentNavigationService
{
/// <summary>
/// 导致到page
/// </summary>
/// <param name="StrPagekey">页面键</param>
/// <returns></returns>
/// 基于页面名字进行导航,摆脱页面类型
Task NavigationToAsync(Type type);
Task NavigationToAsync(string StrPagekey,TabbedPage tabbedPage,Page[] pages, string strTitle);
}
导航服务实现
class ContentNavigationService : IContentNavigationService
{
/// <summary>
/// 导航到页面type
/// </summary>
/// <param name="type">页面type</param>
/// <returns></returns>
public async Task NavigationToAsync(Type type)
{
//throw new NotImplementedException();
await MainPage.Navigation.PushAsync(_contentPageActivationService.Activate(type));
}
/// <summary>
///
/// </summary>
/// <param name="StrPagekey">页面键,不能重复</param>
/// <param name="tabbedPage">TabbedPage 实例</param>
/// <param name="pages">tabbed page的子页面</param>
/// <param name="strTitle">此主要针对的为FBin中的情况,有好想法后可优化</param>
/// <returns></returns>
public async Task NavigationToAsync(string StrPagekey,TabbedPage tabbedPage,Page[] pages,string strTitle)
{
await MainPage.Navigation.PushAsync(_contentPageActivationService.Activate(StrPagekey, tabbedPage,pages, strTitle));
}
private Page mainPage;//当前主页
public Page MainPage => mainPage ?? (mainPage = Application.Current.MainPage);//get mainpage
private IContentPageActivationService _contentPageActivationService;//激活页面
public ContentNavigationService(IContentPageActivationService contentPageActivationService)
{
_contentPageActivationService = contentPageActivationService;
}
}
内容页激活interface
public interface IContentPageActivationService { Page Activate(Type type); Page Activate(string pageKey,TabbedPage tabbedPage,Page[] pages,String name); }
导航激活实现——激活服务中最开始按学习的方法,但在使用过程中发现其对不同的页面需要在switch中去增加相应的代码,太垃圾,于是用反射对不同type进行首次实例化。
class ContentPageActivationService : IContentPageActivationService { public Page Activate(Type pageKey) { //throw new NotImplementedException(); string strPageKey = pageKey.Name; if (cacheNavigationPages.ContainsKey(strPageKey)) { return cacheNavigationPages[strPageKey]; } else { /* switch (pageKey) { case ConstParameter.FgBinManagement: cacheNavigationPages[strPageKey] = new ChooseType(); break; case ConstParameter.FpbMain: cacheNavigationPages[strPageKey] = new FpbMainPage(); break; }*/ cacheNavigationPages[strPageKey] = (Page)Activator.CreateInstance(pageKey); var titleView = new Label { Text = strPageKey, TextColor = Color.White }; NavigationPage.SetTitleView(cacheNavigationPages[strPageKey], titleView); return cacheNavigationPages[strPageKey]; } } /// <summary> /// /// </summary> /// <param name="pageKey"></param> /// <param name="pages"></param> /// <param name="name"></param> /// <returns></returns> public Page Activate(string pageKey, TabbedPage tabbedPage,Page[] pages, string name) { //throw new NotImplementedException(); if (cacheNavigationTabbedPage.ContainsKey(pageKey)) { if (!(pages[pages.Length - 1] is PartialBox)) { cacheNavigationTabbedPage[pageKey].Children[0].Title = name; } return cacheNavigationTabbedPage[pageKey]; } else { cacheNavigationTabbedPage[pageKey] = tabbedPage;//new FgMainPage(); //导航栏设置标题 //var titleView = new Label { Text=pageKey,TextColor=Color.White}; //NavigationPage.SetTitleView(tabbedPage,titleView); if (pages[0].Title == nameof(Transfer) ) { pages[0].Title = name; } foreach (var item in pages) { cacheNavigationTabbedPage[pageKey].Children.Add(item); } return cacheNavigationTabbedPage[pageKey]; } } /// <summary> /// 缓存页面,避免重复实例化,导致内存耗损严重——单例 /// </summary> private Dictionary<string, Page> cacheNavigationPages = new Dictionary<string, Page>(); private Dictionary<string, TabbedPage> cacheNavigationTabbedPage = new Dictionary<string, TabbedPage>(); }
调用tabbedpage 导航
Transfer transfer = new Transfer(); Status status = new Status(); Inventory inventory = new Inventory(); PartialBox partial = new PartialBox(); private ContentNavigationService cns; FgMainPage fgMainPageTransfer; Page[] pagesTransfer; Page[] pagesPartial; FgMainPage fgMainPagePartial; public async void TransferPageAsync(string strTitle) { //if (cns == null) //{ // cns = new ContentNavigationService(new ContentPageActivationService()); //} cns= cns ?? new ContentNavigationService(new ContentPageActivationService()); if (strTitle.ToLower()!=nameof(partial).ToLower()) { pagesTransfer =pagesTransfer??new Page[]{ transfer, status, inventory }; await cns.NavigationToAsync(ConstantNavigationConstants.FgMainTransferPage, fgMainPageTransfer??new FgMainPage(), pagesTransfer, strTitle); } else { NavigateToPartial(strTitle); } //await cns.NavigationToAsync(ConstantNavigationConstants.FgMainTransferPage); }
ViewModel中调用 page导航,注意此红色字体的 command参数,此片指定为type,以方便在前端的xml中引入不同的page class
public ICommand MenuCommand { get; set; } private ContentNavigationService cns; public MenuViewModel() { /* MenuCommand = new Command<View>(async (view)=>{ //var p = ((Button)view).Text; //var id= ((Button)view).Id; cns = cns ?? new ContentNavigationService(new ContentPageActivationService()); await cns.NavigationToAsync(((Button)view).Text); });*/ MenuCommand = new Command<Type>(async (type) => { cns = cns ?? new ContentNavigationService(new ContentPageActivationService()); await cns.NavigationToAsync(type); }); }
MenuCommand = new Command<Type>中的Type从前端xml中通过 CommandParameter={x:Type local:ChooseType} 传递其类型。如下代码,注意其传递不同class时需要contentPage中先引入并命名,然后在CommandParameter中才能进行正常的引用。
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="XamrinScanner.Views.MenuPage" xmlns:local="clr-namespace:XamrinScanner.Views.FgBinManagement" xmlns:Fpb="clr-namespace:XamrinScanner.Views.FiredPalletBoxMap" xmlns:vModel="clr-namespace:XamrinScanner.ViewModel" > <NavigationPage.TitleView> <!--navigation title--> <Label Style="{x:StaticResource LabelWhiteFont}">Home Page</Label> </NavigationPage.TitleView> <ContentPage.BindingContext> <vModel:MenuViewModel/> </ContentPage.BindingContext> <ContentPage.Content> <StackLayout VerticalOptions="Center" Margin="10,10"> <Button Text="Management" Style="{StaticResource BtnMargin20}"/> <Button Text="hipping" Style="{StaticResource BtnMargin20}"/> <Button Text="Bin Management" Style="{StaticResource BtnMargin20}" x:Name="ChooseType" Command="{Binding MenuCommand}" CommandParameter="{x:Type local:ChooseType }"/> <Button Text="Pallet Box Map" Style="{StaticResource BtnMargin20}" x:Name="FpbMain" Command="{Binding MenuCommand}" CommandParameter="{x:Type Fpb:FpbMainPage}"/> <!--CommandParameter="{x:Type local:FpbMainPage}"--> <Button Text="RM Management" Style="{StaticResource BtnMargin20}" /> </StackLayout> </ContentPage.Content> </ContentPage>