Xamarin.forms 如何进入导航页面';s堆栈在选项卡式页面中

Xamarin.forms 如何进入导航页面';s堆栈在选项卡式页面中,xamarin.forms,mvvmcross,Xamarin.forms,Mvvmcross,我正在使用MvvmCross和Xamarin表单。我的应用程序的主页是一个带有四个选项卡的MvxTabbedPage。每个选项卡都是导航页面,其中包含自己的内容页面。无论哪个选项卡是当前选项卡,对IMvxNavigationService的任何Navigate调用都会将页面推到第一个选项卡上 Application.Current.Hierarchy()的打印输出如下所示: Application Root HomePage(Tabbed) [0]: MvxNavigation

我正在使用MvvmCross和Xamarin表单。我的应用程序的主页是一个带有四个选项卡的
MvxTabbedPage
。每个选项卡都是导航页面,其中包含自己的内容页面。无论哪个选项卡是当前选项卡,对
IMvxNavigationService
的任何
Navigate
调用都会将页面推到第一个选项卡上

Application.Current.Hierarchy()
的打印输出如下所示:

Application Root
 HomePage(Tabbed)
        [0]: MvxNavigationPage(Navigation)
                          [0]: FirstPage(Content)
        [1]: MvxNavigationPage(Navigation)
                          [0]: SecondPage(Content)
        [2]: MvxNavigationPage(Navigation)
                          [0]: ThirdPage(Content)
        [3]: MvxNavigationPage(Navigation)
                          [0]: FourthPage(Content)
从第二个选项卡启动
导航
详细信息页面
,将导致此层次结构:

Application Root
 HomePage(Tabbed)
        [0]: MvxNavigationPage(Navigation)
                          [0]: FirstPage(Content)
                          [1]: DetailsPage(Content)
        [1]: MvxNavigationPage(Navigation)
                          [0]: SecondPage(Content)
        [2]: MvxNavigationPage(Navigation)
                          [0]: ThirdPage(Content)
        [3]: MvxNavigationPage(Navigation)
                          [0]: FourthPage(Content)
在尝试调试时,我在MvxTabbedPage上的
CurrentPageChanged
事件上附加了一个处理程序,我可以确认
CurrentPage
已正确更新。我也尝试过为TabbedPage设置
WrapInNavigationPage=true
,但它导致了不良的导航行为

HomePage.xaml(无代码隐藏):


HomePageViewModel.cs

    public class HomeViewModel : MvxViewModel
    {
        // Bound Property
        List<IMvxViewModel> _tabViewModels;
        public List<IMvxViewModel> TabViewModels
        {
            get
            {
                return _tabViewModels;
            }
            set
            {
                _tabViewModels = value;
                RaisePropertyChanged(() => TabViewModels);
            }
        }
        // Bound Property
        public TabDataTemplateSelector DataTemplateSelector
        {
            get;
            set;
        }
        // ...

        public class TabDataTemplateSelector : DataTemplateSelector
        {

            private IMvxViewsContainer _viewsContainer;
            protected IMvxViewsContainer ViewsContainer
            {
                get
                {
                    if (_viewsContainer == null)
                        _viewsContainer = Mvx.IoCProvider.Resolve<IMvxViewsContainer>();
                    return _viewsContainer;
                }
            }

            Dictionary<IMvxViewModel, DataTemplate> Cache;

            public TabDataTemplateSelector()
            {

                Cache = new Dictionary<IMvxViewModel, DataTemplate>();

            }

            protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
            {

                Console.WriteLine("Get Data Template for Object {0}", item);

                DataTemplate _dataTemplate = null;

                IMvxViewModel viewModel = item as IMvxViewModel;
                Type viewType;

                if (item != null)
                {

                    if (Cache.ContainsKey(viewModel))
                    {

                        Console.WriteLine("Tab in cache, returning cached data.");
                        _dataTemplate = Cache[viewModel];

                    }
                    else
                    {

                        viewType = ViewsContainer.GetViewType(viewModel.GetType());

                        Console.WriteLine("View Type {0}, ViewModel {1}", viewType, viewModel);

                        _dataTemplate = new DataTemplate(() =>
                        {

                            IMvxView view = (IMvxView)Activator.CreateInstance(viewType);
                            view.DataContext = viewModel;
                            Page page = (Page)view;

                            MvxNavigationPage navigationPage = new MvxNavigationPage(page);
                            navigationPage.Title = page.Title;
                            navigationPage.Icon = page.Icon;

                            return navigationPage;

                        });
                        // Cache DataTemplate
                        Cache[viewModel] = _dataTemplate;
                    }
                }
                return _dataTemplate;
                }
        }
       // ... End of HomeViewModel class
公共类HomeViewModel:MvxViewModel
{
//束缚性质
列出选项卡视图模型;
公共列表选项卡视图模型
{
得到
{
返回选项卡视图模型;
}
设置
{
_tabViewModels=值;
RaisePropertyChanged(()=>TabViewModels);
}
}
//束缚性质
公共选项卡DataTemplateSelector DataTemplateSelector
{
得到;
设置
}
// ...
公共类选项卡DataTemplateSelector:DataTemplateSelector
{
专用IMvxViewsContainer\u viewsContainer;
受保护的IMvxViewsContainer ViewsContainer
{
得到
{
如果(_viewsContainer==null)
_viewsContainer=Mvx.IoCProvider.Resolve();
返回视图容器;
}
}
字典缓存;
公共选项卡DataTemplateSelector()
{
Cache=新字典();
}
受保护的覆盖数据模板OnSelectTemplate(对象项,BindableObject容器)
{
WriteLine(“获取对象{0}的数据模板”,项);
DataTemplate _DataTemplate=null;
IMvxViewModel viewModel=项目作为IMvxViewModel;
类型viewType;
如果(项!=null)
{
if(Cache.ContainsKey(viewModel))
{
WriteLine(“缓存中的选项卡,返回缓存数据”);
_dataTemplate=缓存[viewModel];
}
其他的
{
viewType=ViewsContainer.GetViewType(viewModel.GetType());
WriteLine(“视图类型{0},视图模型{1}”,视图类型,视图模型);
_dataTemplate=新的dataTemplate(()=>
{
IMvxView视图=(IMvxView)Activator.CreateInstance(viewType);
view.DataContext=viewModel;
页面=(页面)视图;
MvxNavigationPage navigationPage=新建MvxNavigationPage(第页);
navigationPage.Title=页面.Title;
navigationPage.Icon=页面.Icon;
返回导航页面;
});
//缓存数据模板
缓存[viewModel]=\u数据模板;
}
}
返回数据模板;
}
}
//…HomeViewModel类结束
非常感谢您的帮助和指点

其他说明:

  • 选项卡式页面具有以下属性:
    [MvxTabbedPagePresentation(TabbedPosition.Root,NoHistory=true,WrapInNavigationPage=false)]

  • ItemSource
    属性是
    MvxViewModel
    对象的列表

  • ItemTemplate
    属性是一个数据模板,它实例化相应的
    页面
    ,并将其包装在
    导航页面

  • MvvmCross 6.2.2,Xamarin表格3.4


我使用带有NavigationPage测试的普通选项卡式页面,无法复制您的问题,您能将您的选项卡式页面和导航代码发布到DetailsPage吗?@LeoZhu感谢您的关注。我添加了一些源代码来展示我是如何制作选项卡式页面及其内容的。此应用程序是由ViewModel驱动的,因此我使用h是一个DataTemplateSelector,而不是XAML。如果{(Cache.ContainsKey(viewModel))}else{…},
else
是否仅执行,则可以放置一个断点并查看代码
once@LeoZhu控制台输出显示,加载选项卡式页面时,
OnSelectTemplate()
会被调用四次(每个ViewModel对象一次),以后不再调用。在选项卡之间导航时不会再次调用它。
    public class HomeViewModel : MvxViewModel
    {
        // Bound Property
        List<IMvxViewModel> _tabViewModels;
        public List<IMvxViewModel> TabViewModels
        {
            get
            {
                return _tabViewModels;
            }
            set
            {
                _tabViewModels = value;
                RaisePropertyChanged(() => TabViewModels);
            }
        }
        // Bound Property
        public TabDataTemplateSelector DataTemplateSelector
        {
            get;
            set;
        }
        // ...

        public class TabDataTemplateSelector : DataTemplateSelector
        {

            private IMvxViewsContainer _viewsContainer;
            protected IMvxViewsContainer ViewsContainer
            {
                get
                {
                    if (_viewsContainer == null)
                        _viewsContainer = Mvx.IoCProvider.Resolve<IMvxViewsContainer>();
                    return _viewsContainer;
                }
            }

            Dictionary<IMvxViewModel, DataTemplate> Cache;

            public TabDataTemplateSelector()
            {

                Cache = new Dictionary<IMvxViewModel, DataTemplate>();

            }

            protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
            {

                Console.WriteLine("Get Data Template for Object {0}", item);

                DataTemplate _dataTemplate = null;

                IMvxViewModel viewModel = item as IMvxViewModel;
                Type viewType;

                if (item != null)
                {

                    if (Cache.ContainsKey(viewModel))
                    {

                        Console.WriteLine("Tab in cache, returning cached data.");
                        _dataTemplate = Cache[viewModel];

                    }
                    else
                    {

                        viewType = ViewsContainer.GetViewType(viewModel.GetType());

                        Console.WriteLine("View Type {0}, ViewModel {1}", viewType, viewModel);

                        _dataTemplate = new DataTemplate(() =>
                        {

                            IMvxView view = (IMvxView)Activator.CreateInstance(viewType);
                            view.DataContext = viewModel;
                            Page page = (Page)view;

                            MvxNavigationPage navigationPage = new MvxNavigationPage(page);
                            navigationPage.Title = page.Title;
                            navigationPage.Icon = page.Icon;

                            return navigationPage;

                        });
                        // Cache DataTemplate
                        Cache[viewModel] = _dataTemplate;
                    }
                }
                return _dataTemplate;
                }
        }
       // ... End of HomeViewModel class