xamarin.forms 导航封装


xamarin.forms导航的实现,MS提供了多种方法(参考链接), 再此不赘述。

说一下导航封装,以便于在anywhere都能使用。

面向接口编程单一职责原则,将导航拆分为页面的跳转(navigation)与页面的激活(Active)两个接口并实现。

导航服务interface

    public interface IContentNavigationService
    {
        /// 
        /// 导致到page
        /// 
        /// 页面键
        /// 
        /// 基于页面名字进行导航,摆脱页面类型
        Task NavigationToAsync(Type type);
        Task NavigationToAsync(string StrPagekey,TabbedPage tabbedPage,Page[] pages, string strTitle);
    }

导航服务实现

class ContentNavigationService : IContentNavigationService
    {
        /// 
        /// 导航到页面type
        /// 
        /// 页面type
        /// 
        public async Task NavigationToAsync(Type type)
        {
            //throw new NotImplementedException();
            await MainPage.Navigation.PushAsync(_contentPageActivationService.Activate(type));
          
        }

        /// 
        /// 
        /// 
        /// 页面键,不能重复
        /// TabbedPage 实例
        /// tabbed page的子页面
        /// 此主要针对的为FBin中的情况,有好想法后可优化
        /// 
        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 = nameof(pageKey);
            if (cacheNavigationPages.ContainsKey( nameof(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];
            }
        }

        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        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];
            }
        }

        
        /// 
        /// 缓存页面,避免重复实例化,导致内存耗损严重——单例
        /// 
        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(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(async (type) => {
                cns = cns ?? new ContentNavigationService(new ContentPageActivationService());
                await cns.NavigationToAsync(type);
            });
        }

MenuCommand = new Command中的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>     
        <Label Style="{x:StaticResource  LabelWhiteFont}">Home PageLabel>
    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}"/>
            
            <Button Text="RM Management" Style="{StaticResource BtnMargin20}" />
        StackLayout>
    ContentPage.Content>
ContentPage>