运用MvvmCross框架完成Xamarin.Forms的汉堡菜单结构


玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。

注:本文是英文写的,偷懒自动翻译过来了,原文地点:Implementing MasterDetail layout in Xamarin.Forms by MvvmCross

迎接人人存眷我的民众号:顺序员在新西兰,相识优美的新西兰和码农们的生涯

浏览本文或许须要20分钟。本文目次:

媒介

经由过程MvxScaffolding建立项目

建立MasterDetailPage

建立MasterPage

建立DetailPages

完成菜单功用

微调UI

小结

 

 

媒介

在我的Xamarin和MvvmCross手册中,我展现了运用MvvmCross Framework开辟基础Xamarin运用顺序的基础知识。在开辟实在运用顺序时须要斟酌更多细节,比方组织,款式和数据库等。比方,汉堡菜单组织是古代挪动运用顺序中非经常见的导航形式。我们能够运用MasterDetail导航形式来完成汉堡菜单。接下来,我将向您展现如安在Xamarin.Forms运用顺序中完成MasterDetail组织。在最先之前,我发起您在这里浏览有关MasterDetailPage的官方文档:Xamarin.Forms Master-Detail Page

我的开辟情况以下所示:

  • Windows 10版本10.0.17134
  • Visual Studio 2017版本15.9.4
  • Xamarin.Forms版本3.4.0.1008975
  • MvvmCross版本6.2.2

让我们最先吧。

经由过程MvxScaffolding建立项目

若是您是MvvmCross的新手,运用MvvmCross建立Xamarin运用顺序能够有点顺手。荣幸的是,我们有一些项目模板来简化我们的事情。您能够在官方文档中找到它们:MvvmCross入门我发起你运用这个:MvxScaffolding它是新的,支撑.net规范。您能够经由过程单击VS 2017中的工具 - 扩大和更新来搜刮它,以下所示:

 

装置后,您能够在MvvmCross种别中建立一个新的Xamarin.Forms运用顺序:

 

输入MvxFormsMasterDetailDemo为项目称号。MvxScaffolding为我们供应了一个异常友爱的界面来定制运用顺序。为了更好地明白,我们挑选Blank模板,以下所示:

 

默许设置不包罗UWP项目。若是您须要支撑UWP平台,请挑选它,并挑选Min SDK版本为1803.由于旧的Windows 10版本不支撑某些新功用,因而发起此时运用。别的,您须要输入形貌作为UWP运用顺序称号。

 

单击NEXT按钮,您将看到一个择要窗口。搜检一切信息,然后单击DONE按钮。MvxScaffolding将天生一个具有优越组织的基础空缺Xamarin.Forms运用顺序。

建立MasterDetailPage

MasterDetailPage是运用顺序的根页面。现实上,它是一个MasterDetailPage的实例它不应当用作子页面以确保在分歧平台上的一致用户体验。

建立ViewModel

接下来,增加在MvxFormsMasterDetailDemo.Core项目MasterDetailViewModel中的ViewModels文件夹中挪用的新类文件将其变动成从MvxViewModel继续一般,我们还须要运用它NavigationService来完成ViewModel中的导航。因而,IMvxNavigationService经由过程运用依靠注入注入实例

using MvvmCross.Navigation;
using MvvmCross.ViewModels;

namespace MvxFormsMasterDetailDemo.Core.ViewModels
{
    public class MasterDetailViewModel : MvxViewModel
    {
        readonly IMvxNavigationService _navigationService;

        public MasterDetailViewModel(IMvxNavigationService navigationService)
        {
            _navigationService = navigationService;
        }
    }
}

 

建立XAML文件

Xamarin.Forms为我们供应了一些导航形式,包孕分层导航,选项卡式页面,MasterDetailPage和模态页面等。依据我们的请求,我们愿望在主页面上有一个汉堡菜单。以是我们能够运用MasterDetailPage,它是运用顺序的根页面,包罗两个地区:左侧是MasterPage,右侧是DetailPage。我们能够将菜单放在MasterPage中。单击菜单项时,导航效劳将在DetailPage地区中显现别的一页。

在MvvmCross中,Xamarin.Forms中有MvxFromsPagePresenter分歧的页面范例,它们界说了视图的显现体式格局。我们MvxPagePresentationAttribute用来指定分歧的页面范例。有关更多详细信息,请在此处检察文档:Xamarin.Forms检察演示者

App.cs在MvxFormsMasterDetailDemo.Core项目中翻开该文件。请注意,框架将从HomeViewModel第一页最先如今让我们建立一个MasterDetailPage并用它来替代第一页。

右键单击MvxFormsMasterDetailDemo.UI项目中的Pages文件夹,然后挑选AddNew ItemContent Page从Xamarin.Forms种别中挑选,以下所示:

 

翻开MasterDetailPage.xaml文件。请注意,此页面是一个ContentPage我们须要将其改成继续MvxMasterDetailPage用以下代码替代XAML代码:

<?xml version =“1.0”encoding =“utf-8”?> 
<views:MvxMasterDetailPage xmlns =“http://xamarin.com/schemas/2014/forms” 
             xmlns:x =“http://schemas.microsoft .com / winfx / 2009 / xaml“ 
             x:Class =”MvxFormsMasterDetailDemo.UI.Pages.MasterDetailPage“ 
             xmlns:views =”clr-namespace:MvvmCross.Forms.Views; assembly = MvvmCross.Forms“ 
             xmlns:viewModels =”clr- namespace:MvxFormsMasterDetailDemo.Core.ViewModels; assembly = MvxFormsMasterDetailDemo.Core“ 
             x:TypeArguments =”viewModels:MasterDetailViewModel“> 
</ views:MvxMasterDetailPage>

 

我们MvxMasterDetailPage用来替代默许ContentPage范例。为此,我们须要增加以下代码:

xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"

 

要设置MasterDetailPage的ViewModel,我们须要指定x:TypeArgumentsviewModels:MasterDetailViewModel不要遗忘经由过程增加以下代码导入viewModels定名空间:xmlns:viewModels="clr-namespace:MvxFormsMasterDetailDemo.Core.ViewModels;assembly=MvxFormsMasterDetailDemo.Core"

翻开MasterDetailPage.xaml.cs文件,将其基类替代ContentPageMvxMasterDetailPage<MasterDetailViewModel>MvxMasterDetailPagePresentation属性增加到类中,以下面的代码:

using MvvmCross.Forms.Presenters.Attributes;
using MvvmCross.Forms.Views;
using MvxFormsMasterDetailDemo.Core.ViewModels;
using Xamarin.Forms.Xaml;

namespace MvxFormsMasterDetailDemo.UI.Pages
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    [MvxMasterDetailPagePresentation(Position = MasterDetailPosition.Root, WrapInNavigationPage = false, Title = "MasterDetail Page")]
    public partial class MasterDetailPage : MvxMasterDetailPage<MasterDetailViewModel>
    {
        public MasterDetailPage()
        {
            InitializeComponent();
        }
    }
}

我们来看看MvxMasterDetailPagePresentation属性。有一些异常主要的属性MvxMasterDetailPagePresentationPosition是一个罗列值,用于指导页面的范例,在此处设置为Root。请设置如图所示的其他属性,不然,您能够会取得一些新鲜的结果。

建立MasterPage

MasterPage用于显现汉堡包菜单,ContentPage个中包罗一个ListView我们将运用数据绑定来初始化菜单项。

建立ViewModel

在MvxFormsMasterDetailDemo.Core项目ViewModels文件夹中建立一个类MenuViewModel运用以下代码替代内容:

using System.Collections.ObjectModel;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;

namespace MvxFormsMasterDetailDemo.Core.ViewModels
{
    public class MenuViewModel : MvxViewModel
    {
        readonly IMvxNavigationService _navigationService;

        public MenuViewModel(IMvxNavigationService navigationService)
        {
            _navigationService = navigationService;
            MenuItemList = new MvxObservableCollection<string>()
            {
                "Contacts",
                "Todo"
            };
        }

        #region MenuItemList;
        private ObservableCollection<string> _menuItemList;
        public ObservableCollection<string> MenuItemList
        {
            get => _menuItemList;
            set => SetProperty(ref _menuItemList, value);
        }
        #endregion
    }
}

 

它有一个MenuItemList用来存储一些菜单项属性。为简朴起见,只要两个字符串:ContactsTodo我们还须要IMvxNavigationService在组织函数中注入实例

建立XAML文件

接下来,在MvxFormsMasterDetailDemo.UI项目中的Pages文件夹中,增加一个新的ContentPage,定名为MenuPage.xaml翻开MenuPage.xaml文件并运用以下代码替代内容:

<?xml version="1.0" encoding="utf-8" ?>
<views:MvxContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
             xmlns:viewModels="clr-namespace:MvxFormsMasterDetailDemo.Core.ViewModels;assembly=MvxFormsMasterDetailDemo.Core"
             x:Class="MvxFormsMasterDetailDemo.UI.Pages.MenuPage"
             x:TypeArguments="viewModels:MenuViewModel" >
    <ContentPage.Content>
        <StackLayout>
            <ListView></ListView>
        </StackLayout>
    </ContentPage.Content>
</views:MvxContentPage>

翻开MenuPage.xaml.cs文件并设置基类和属性,以下所示:

using MvvmCross.Forms.Presenters.Attributes;
using MvvmCross.Forms.Views;
using MvxFormsMasterDetailDemo.Core.ViewModels;
using Xamarin.Forms.Xaml;

namespace MvxFormsMasterDetailDemo.UI.Pages
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    [MvxMasterDetailPagePresentation(Position = MasterDetailPosition.Master, WrapInNavigationPage = false, Title = "HamburgerMenu Demo")]
    public partial class MenuPage : MvxContentPage<MenuViewModel>
    {
        public MenuPage ()
        {
            InitializeComponent ();
        }
    }
}

MvxMasterDetailPagePresentation的属性Position应当被设置为Master,这意味着该页面将被显现为MasterDetailPage的Master。MasterPage另有别的一个圈套:必需设置Title属性,不然,您的运用顺序将被卡住。因而,您必需设置MvxMasterDetailPagePresentation属性的Title属性。

如今我们须要设置数据绑定ListView我们已在ViewModel有MenuItemList,以是我们如今要做的就是设置ListView的ItemsSource,以下所示:

<ListView ItemsSource="{Binding MenuItemList}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextCell Text="{Binding}"></TextCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

现在,我们只是运用TextCell来显现菜单文本。在我们完成汉堡包菜单的悉数功用之前,让我们建立DetailPages。

建立DetailPages

为简朴起见,我们只增加两个页面作为详细信息页面。

建立ViewModels

MvxFormsMasterDetailDemo.Core项目的ViewModels文件夹中增加两个名为ContactsViewModel和TodoViewModel的新文件让它们离别从MvxViewModel继续

using MvvmCross.ViewModels;

namespace MvxFormsMasterDetailDemo.Core.ViewModels
{
    public class ContactsViewModel : MvxViewModel
    {
    }
}
using MvvmCross.ViewModels;

namespace MvxFormsMasterDetailDemo.Core.ViewModels
{
    public class TodoViewModel : MvxViewModel
    {
    }
}

建立XAML文件

将两个ContentPage文件增加到MvxFormsMasterDetailDemo.UI项目的Pages文件夹中,并将它们定名为ContactsPage.xamlTodoPage.xaml要运用MvvmCross功用,我们须要将它们变动成继续自MvxContentPage翻开ContactsPage.xaml文件并运用以下代码替代内容:

<?xml version="1.0" encoding="utf-8" ?>
<views:MvxContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MvxFormsMasterDetailDemo.UI.Pages.ContactsPage"
             xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
             xmlns:viewModels="clr-namespace:MvxFormsMasterDetailDemo.Core.ViewModels;assembly=MvxFormsMasterDetailDemo.Core"
             x:TypeArguments="viewModels:ContactsViewModel">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="Welcome to ContactsPage!"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</views:MvxContentPage>

Label用于指导以后页面。

翻开ContactsPage.xaml.cs文件并更新内容,以下所示:

using MvvmCross.Forms.Presenters.Attributes;
using MvvmCross.Forms.Views;
using MvxFormsMasterDetailDemo.Core.ViewModels;
using Xamarin.Forms.Xaml;

namespace MvxFormsMasterDetailDemo.UI.Pages
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    [MvxMasterDetailPagePresentation(Position = MasterDetailPosition.Detail, NoHistory = true, Title = "Contacts Page")]
    public partial class ContactsPage : MvxContentPage<ContactsViewModel>
    {
        public ContactsPage ()
        {
            InitializeComponent ();
        }
    }
}

Position属性的值MasterDetailPosition.Detail,这意味着此页面应位于MasterDetailPage的Detail地区。NoHistory属性应当是true,用来包管针对分歧平台的导航没有新鲜的行动。Title属性用于在页面顶部显现页面称号。

TodoPage.xamlTodoPage.xaml.cs做一样的变动不要遗忘更新Label控件的Text以显现页面称号。

完成菜单功用

如今,我们有我们须要显现一切的页面:根页叫MasterDetailPage,一个MasterPage叫做MenuPage和两个DetailPages叫做ContactsPageTodoPage接下来,我们须要使菜单一般事情。

显现MasterPage和DetailPage

翻开MasterDetailViewModel.cs文件并掩盖ViewAppearing要领,以下所示:

public override async void ViewAppearing()
        {
            base.ViewAppearing();
            await _navigationService.Navigate<MenuViewModel>();
            await _navigationService.Navigate<ContactsViewModel>();
        }

ContactsPage运用顺序启动时被用作DetailPage。由于我们已MenuPage和ContactsPage指定了属性MvxMasterDetailPagePresentation,以是MvvmCross会找到并将它们显如今准确地位。

在MvxFormsMasterDetailDemo.Core项目中翻开App.cs文件,并将第一页替代为MasterDetailPage

public class App : MvxApplication
    {
        public override void Initialize()
        {
            RegisterAppStart<MasterDetailViewModel>();
        }
    }

如今我们能够为三个平台启动运用顺序:

安卓:

   

默许视图很好。Xamarin.Forms会自动在页面左上角增加一个汉堡包图标按钮。当我们单击按钮时,菜单显现,但没有页眉。我们稍后会调解UI。

iOS版:

   

iOS的默许视图与Android分歧。页面上没有汉堡包图标。关于MenuPage标题栏的别的一个题目与Android雷同。看起来我们须要增加一个汉堡图标并显现头部标题栏。我们稍后会如许做。

UWP:

 

发生了甚么?MasterPage自动显现,但没有默许的汉堡包按钮。

有关MasterDetailPage导航行动的详细信息,请在此处浏览:MasterDetailPage概述依据文档,母版页应当有一个包罗按钮的导航栏。但如今我们取得了一些分歧的结果。无论怎样,我们能够本身处置惩罚它。

要修复UWP的组织,只需设置MasterBehaviorMasterDetailPage 属性便可。它是一个罗列值,用于肯定详细信息页面在MasterDetailPage中的显现体式格局。若是保存它Default,它将离别显现分歧平台的DetailPage。这就是我们取得分歧结果的缘由。

MasterDetailPage.xaml在MvxFormsMasterDetailDemo.UI项目中翻开该文件。MasterBehavior在页面界说中增加属性并将其设置为Popover,这意味着DetailPage将掩盖或局部掩盖MasterPage:

-玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。-
<?xml version="1.0" encoding="utf-8" ?>
<views:MvxMasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MvxFormsMasterDetailDemo.UI.Pages.MasterDetailPage"
             xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
             xmlns:viewModels="clr-namespace:MvxFormsMasterDetailDemo.Core.ViewModels;assembly=MvxFormsMasterDetailDemo.Core"
             x:TypeArguments="viewModels:MasterDetailViewModel" MasterBehavior="Popover">

</views:MvxMasterDetailPage>

要检察结果,请运转UWP项目,它看起来像如许:

   

如今它在页面左上方有默许的汉堡包按钮。运转Android和iOS项目以确保一切内容都不会因细微变动而中缀。您能够会注意到这三个平台之间仍存在一些差别。比方,UWP项目有标题栏,但Android和iOS没有。Android和UWP有默许的汉堡包按钮,但iOS没有。我们稍后会修复它们。

设置菜单导航

单击菜单项时,运用顺序应显现准确的DetailPage。如今让我们设置Command菜单项。在MvxFormsMasterDetailDemo.Core项目中翻开MenuViwModel.cs文件,然后增加一个Command,以下所示:

#region ShowDetailPageAsyncCommand;
        private IMvxAsyncCommand<string> _showDetailPageAsyncCommand;
        public IMvxAsyncCommand<string> ShowDetailPageAsyncCommand
        {
            get
            {
                _showDetailPageAsyncCommand = _showDetailPageAsyncCommand ?? new MvxAsyncCommand<string>(ShowDetailPageAsync);
                return _showDetailPageAsyncCommand;
            }
        }
        private async Task ShowDetailPageAsync(string param)
        {
            // Implement your logic here.
        }
        #endregion

这是一个实例IMvxAsyncCommand<T>,个中包罗来自数据绑定的参数。参数的范例是string,由于我们晓得MenuItemListis中的工具是string范例若是您MenuItemList 有其他一些泛型范例,请记着将泛型范例变动成您的现实项范例。

然后我们须要为敕令设置数据绑定。MenuPage.xaml在MvxFormsMasterDetailDemo.UI项目中翻开该文件并搜检以后ItemTemplate

<ListView ItemsSource="{Binding MenuItemList}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextCell Text="{Binding}"></TextCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

这里我们只运用一个简朴的TextCell来显现菜单文本。怎样将敕令绑定到ListView

在我们最先数据绑定之前,我发起您浏览本文:Xamarin.Forms Command 接口在Xamarin.Forms中,一些控件原生支撑Command,好比ButtonMenuItemTextCell和一些继续自它们的类。而且,SearchBar支撑SearchCommand,现实上也是一种ICommand范例的属性ListView的RefreshCommand属性也是ICommand接口的实例

关于那些不直接支撑ICommand的控件,Xamarin.Forms供应了一个TapGestureRecognizer来支撑Command绑定。有关详细信息,请浏览以下文章:增加点按手势辨认器请记着,虽然GestureRecognizer支撑多种手势,如pinchpanswipe,但只TapGestureRecognizer支撑ICommand别的一个限定是视图元素必需支撑GestureRecognizers

如今让我通知你怎样运用TapGestureRecognizer绑定Command到菜单项。起首,设置MenuPage的x:Name属性

<views:MvxContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
             xmlns:viewModels="clr-namespace:MvxFormsMasterDetailDemo.Core.ViewModels;assembly=MvxFormsMasterDetailDemo.Core"
             x:Class="MvxFormsMasterDetailDemo.UI.Pages.MenuPage"
             x:TypeArguments="viewModels:MenuViewModel" 
             x:Name="MainContent">

我们须要称号来援用页面的以后ViewModel。

更新ItemTemplate以下:

<ListView.ItemTemplate>
    <DataTemplate>
        <ViewCell>
            <StackLayout Padding="10">
                <StackLayout.GestureRecognizers>
                    <TapGestureRecognizer 
                        Command="{Binding BindingContext.DataContext.ShowDetailPageAsyncCommand, Source={x:Reference MainContent}}"
                        CommandParameter="{Binding}">
                    </TapGestureRecognizer>
                </StackLayout.GestureRecognizers>
                <Label Text="{Binding}" VerticalOptions="Center"></Label>
            </StackLayout>
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

 

我们对ItemTemplate做了一些修正

起首,用ViewCell替代默许的TextCellViewCell为我们供应了更多自界说UI的天真性。以是我们能够随便界说ItemTemplate比方,我们能够会为每一个菜单项增加一个图标。

ViewCell元素中,运用一个StackLayout控件作为容器,它支撑GestureRecognizers,以是我们能够将TapGestureRecognizer增加StackLayout

TapGestureRecognizer元素中,我界说了两个主要的属性,一个是Command,别的一个是CommandParameter正如我在之前的文章中所说,你必需异常清晰DataContext你绑定到你的看法。关于我们的情况下,我必需找到MenuViewModel中的敕令ShowDetailPageAsyncCommand,以是我用Source={x:Reference MainContent}猎取源工具,这是一个以后的名为MainContent的页面如今我们能够猎取页面的ViewModel,也就是 BindingContext.DataContext,然后将BindingContext.DataContext.ShowDetailPageAsyncCommand用作绑定途径。我对BindingContext.DataContext有点疑心,由于它与UWP中的语法分歧。请注意,完全语法是:

Command =“{Binding Path = BindingContext.DataContext.ShowDetailPageAsyncCommand,Source = {x:Reference MainContent}}”

当Path作为敕令绑定的第一个参数增加时,能够被删除。

关于CommandParameter,它更轻易。只需将以后字符串绑定到它。以是它是CommandParameter="{Binding}"若是您运用包罗某些属性的工具,请运用CommandParameter="{Binding YourProperty}"

接下来,让我们更新敕令。再次翻开MvxFormsMasterDetailApp.Core项目中ViewModels文件夹的MenuViewModel.cs文件,并完成该ShowDetailPageAsync要领,以下面的代码:

private async Task ShowDetailPageAsync(string param)
        {
            // Implement your logic here.
            switch (param)
            {
                case "Contacts":
                    await mvxNavigationService.Navigate<ContactsViewModel>();
                    break;
                case "Todo":
                    await mvxNavigationService.Navigate<TodoViewModel>();
                    break;
                default:
                    break;
            }
        }
        #endregion

此要领吸收来自敕令绑定的参数。因而,我们能够肯定哪一个页面应显现为DetailPage。

如今启动运用顺序并视察导航行动。另有一个题目。单击菜单项时,虽然DetailPage显现准确,但MenuPage仍掩盖DetailPage。以是我们必需掌握MasterPage的导航行动。为此,我们须要将Xamarin.Forms装置到MvxFormsMasterDetailDemo.Core项目。您能够经由过程Xamarin.Forms在NuGet包管理器中搜刮来装置它请与其他项目装置雷同版本的Xamarin.Forms以制止援用毛病。关于我的演示处置惩罚方案,我运用Xamarin.Forms.3.4.0.1008975

ShowDetailPageAsyncswitch以后的要领中增加一些代码(这段代码来自https://github.com/MvvmCross/MvvmCross/issues/2995)

if (Application.Current.MainPage is MasterDetailPage masterDetailPage)
{
    masterDetailPage.IsPresented = false;
}
else if (Application.Current.MainPage is NavigationPage navigationPage
         && navigationPage.CurrentPage is MasterDetailPage nestedMasterDetail)
{
    nestedMasterDetail.IsPresented = false;
}

IsPresented用于掌握是不是显现母版页。要隐蔽MasterPage,请将其设置为false有关更多详细信息,请在此处浏览:建立和显现详细信息页面

启动一切三个平台的运用顺序,以确保菜单一般事情。

设置数据绑定的其他要领

运用TextCell的固有敕令

XAML天下的数据绑定机制是天真的。现实上,我们有多种要领来完成我们的目的。比方,若是您仅用TextCell显现菜单项,则能够运用简朴的要领举行导航。正如我在上一节中所说,TextCell原生支撑ICommand以是我们能够运用如许的数据绑定语法:

<DataTemplate>
    <TextCell Text="{Binding}" Command="{Binding BindingContext.DataContext.ShowDetailPageAsyncCommand, Source={x:Reference MainContent}}" CommandParameter="{Binding}"></TextCell>
</DataTemplate>

这类体式格局更轻易。当用户点击时TextCell,它会触发Command但瑕玷是您没法自界说菜单项的UI。TextCell只支撑笔墨。若是要增加一些图象或界说庞杂的项目组织,则必需运用ViewCell

运用Bahaviors

别的,您能够以为我们能够运用ItemSelectedItemTapped事宜。固然,我们能够!但不幸的是,这些事宜没有完成ICommand接口,以是我们不克不及直接运用数据绑定。要运用ICommand绑定,我们须要运用a Behavior将事宜转换为敕令,以下所述:可重用的EventToCommandBehavior

您能够不熟习行动。行动来自Blend SDK,它是XAML天下中异常有效的库。能够将这些行动附加到某些控件并侦听某些事宜,然后在ViewModel中挪用某些敕令。这是为那些未设想为与Command交互的控件增加Command形式支撑的好要领因而,我们能够文雅地运用MVVM形式,而不是在代码隐蔽文件中运用事宜处置惩罚顺序。

您能够依照官方文档中的申明建立您的EventToCommandBehavior,但我们能够运用第三方库疾速完成:Behaviors.Xamarin.Forms.Netstandard它不是官方项目,但易于运用。您能够经由过程搜刮Behaviors.Xamarin.FormsNuGet包管理器将其装置到MvxFormsMasterDetailApp.UI项目

 

我们能够运用此库来使ListView控件在挑选项目时在ViewModel中触发我们的敕令。为此,MenuViewModel.cs文件中增加叫做SelectedMenuItem的可绑定属性,该属性用于指导以后所选项,以下所示:

#region SelectedMenuItem;
private string _selectedMenuItem;
public string SelectedMenuItem
{
    get => _selectedMenuItem;
    set => SetProperty(ref _selectedMenuItem, value);
}
#endregion

ShowDetailPageAsyncCommand下面的代码替代我们在上一节中建立地区:

#region ShowDetailPageAsyncCommand;
        private IMvxAsyncCommand _showDetailPageAsyncCommand;
        public IMvxAsyncCommand ShowDetailPageAsyncCommand
        {
            get
            {
                _showDetailPageAsyncCommand = _showDetailPageAsyncCommand ?? new MvxAsyncCommand(ShowDetailPageAsync);
                return _showDetailPageAsyncCommand;
            }
        }
        private async Task ShowDetailPageAsync()
        {
            // Implement your logic here.
            switch (SelectedMenuItem)
            {
                case "Contacts":
                    await _navigationService.Navigate<ContactsViewModel>();
                    break;
                case "Todo":
                    await _navigationService.Navigate<TodoViewModel>();
                    break;
                default:
                    break;
            }
            if (Application.Current.MainPage is MasterDetailPage masterDetailPage)
            {
                masterDetailPage.IsPresented = false;
            }
            else if (Application.Current.MainPage is NavigationPage navigationPage
                     && navigationPage.CurrentPage is MasterDetailPage nestedMasterDetail)
            {
                nestedMasterDetail.IsPresented = false;
            }
        }
        #endregion

你找到了区分吗?我从敕令中删除参数,并ShowDetailPageAsync要领中运用了SelectedMenuItem属性 接下来,我们须要为ListView的SelectedItem设置数据绑定在MvxFormsMasterDetailApp.UI项目的Pages文件夹中翻开MenuPage.xaml文件,删除以后ListView控件,然后增加一个新文件ListView,以下所示:

<ListView x:Name="MenuList" ItemsSource="{Binding MenuItemList}" 
          SelectedItem="{Binding SelectedMenuItem, Mode=TwoWay}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextCell Text="{Binding}"></TextCell>
            </DataTemplate>
        </ListView.ItemTemplate>
</ListView>

经由过程以下代码SelectedItem="{Binding SelectedMenuItem, Mode=TwoWay}",我们能够在ViewModel 中设置ListView的SelectedItem与SelectedMenuItem属性之间的双向数据绑定

在views:MvxContentPage界说中导入Behavior定名空间xmlns:behaviors="clr-namespace:Behaviors;assembly=Behaviors"如今我们能够运用behaviors前缀来运用库中的行动。更新ListView以下所示的XMAL 

<ListView x:Name="MenuList" ItemsSource="{Binding MenuItemList}" 
          SelectedItem="{Binding SelectedMenuItem, Mode=TwoWay}">
    <ListView.Behaviors>
        <behaviors:EventHandlerBehavior EventName="ItemSelected">
            <behaviors:InvokeCommandAction 
                Command="{Binding BindingContext.DataContext.ShowDetailPageAsyncCommand, 
                Source={x:Reference MainContent}}"></behaviors:InvokeCommandAction>
            </behaviors:EventHandlerBehavior>
    </ListView.Behaviors>
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextCell Text="{Binding}"></TextCell>
            </DataTemplate>
        </ListView.ItemTemplate>
</ListView>

ListView控件安排了一个Behaviors局部有一个被挪用的行动EventHandlerBehavior,它将被ItemSelected事宜触发在Behaviors中,有一个InvokeCommandAction,它将挪用ViewModel中的ShowDetailPageAsyncCommand请注意数据绑定语法。我们须要指定绑定SourcePath绑定。若是你只是运用{Binding ShowDetailPageAsyncCommand}它,它将没法一般事情。以是要警惕以后控件的BindingContext

运转三个平台的运用顺序,您将看到它按预期事情。您能够挑选任何要领来完成菜单功用。我只想通知你怎样以分歧的体式格局做到这一点。或许你会将它们用于其他场景。

微调UI

分歧平台的UI存在一些缺点。比方,iOS的页眉和汉堡菜单图标不如我们预期的那末好。让我们处置惩罚它们。

增加iOS的汉堡包图标

依据MasterDetailPage的官方文档,我以为iOS也应当显现像Android和UWP如许的按钮,但现实并非如此。我们能够Icon为MasterPage 设置属性。

此处下载图象文件将其粘贴到MvxFormsMasterDetailDemo.iOS项目的Resources文件夹中。若是没有如许的文件夹,请建立一个。图象的Build Action属性应当是BundleResource

在MvxFormsMasterDetailApp.UI项目的Pages文件夹中翻开MenuPage.xaml文件将以下代码增加到以下views:MvxContentPage局部:Icon="hamburger.png"如今启动iOS运用顺序:

 

那很好!

为Android和iOS增加标题栏

UWP将为MasterPage增加默许标题栏。关于Android和iOS,我们须要离别界说它。

为了为分歧的平台供应一些特定的值,我们能够运用Device类,该类包罗很多属性和要领,能够资助我们自界说特定平台的组织和功用。您能够在此处浏览有关它的详细信息:Xamarin.Forms装备类

依据我们的请求,我们只须要为Android和iOS增加标题栏。MvxFormsMasterDetailDemo.UI项目的Pages文件夹中翻开MenuPage.xaml文件ListView界说之前增加以下代码

<StackLayout HeightRequest="40">
    <StackLayout.IsVisible>
        <OnPlatform x:TypeArguments="x:Boolean">
            <On Platform="Android, iOS" Value="True" />
            <On Platform="UWP" Value="False" />
        </OnPlatform>
    </StackLayout.IsVisible>
    <Label Text="My HamburgerMenu Demo" Margin="10" VerticalOptions="Center" FontSize="Large"></Label>
</StackLayout>

现实上,OnPlatform符号正在做一些相似switch在代码中建立语句的器械它包罗几个On范例来吸收Platform属性,透露表现以后平台。有一些分歧的值,以肯定分歧的平台:iOSAndroidUWPmacOS因而,对Android和iOS来讲,我们能够经由过程设置其属性来建立一个包罗Label控件StackLayout并设置其其IsVisible属性以显现运用称号但关于UWP来讲,它是看不见的。这意味着增加代码不会对UWP举行任何变动。

运转适用于Android和iOS的运用。它适用于Android。但在iOS平台上,标题栏轻微掩盖了手机的状态栏,以下所示:

 

我们能够为StackLayout增加一些Margin为iOS 增加别的一个OnPlatform符号,以下所示:

<StackLayout.Margin>
    <OnPlatform x:TypeArguments="Thickness">
        <On Platform="iOS" Value="0,20,0,0" />
    </OnPlatform>
</StackLayout.Margin>

它只影响iOS的UI。如今来看看一切平台:

iOS版:

 

安卓:

 

UWP:

 

好的,一切都很好,除UWP的列表项高度......

调解UWP项目的高度

您能够会注意到,若是我们将其TextCell用作ListView的项模板,则Android和iOS的ListView的项都有默许边距和款式但关于UWP平台,项没有默许款式和恰当高度。让我们界说项目模板的款式。同时,我们应当确保它适用于每一个平台。

翻开MvxFormsMasterDetailDemo.UI项目中的Pages文件夹中MenuPage.xaml文件。经由过程以下代码更新ItemTemplate

<ListView.ItemTemplate>
    <DataTemplate>
        <ViewCell>
            <StackLayout HeightRequest="50">
                <Label Text="{Binding}" Margin="20,0,0,0" 
                       VerticalOptions="CenterAndExpand"></Label>
            </StackLayout>
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

这就对了。末了,全部文件看起来像如许:

<?xml version="1.0" encoding="utf-8" ?>
<views:MvxContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
             xmlns:viewModels="clr-namespace:MvxFormsMasterDetailDemo.Core.ViewModels;assembly=MvxFormsMasterDetailDemo.Core"
             x:Class="MvxFormsMasterDetailDemo.UI.Pages.MenuPage"
             x:TypeArguments="viewModels:MenuViewModel" 
             x:Name="MainContent"
             xmlns:behaviors="clr-namespace:Behaviors;assembly=Behaviors"
             Icon="hamburger.png">
    <ContentPage.Content>
        <StackLayout>
            <StackLayout HeightRequest="40">
                <StackLayout.IsVisible>
                    <OnPlatform x:TypeArguments="x:Boolean">
                        <On Platform="Android, iOS" Value="True" />
                        <On Platform="UWP" Value="False" />
                    </OnPlatform>
                </StackLayout.IsVisible>
                <StackLayout.Margin>
                    <OnPlatform x:TypeArguments="Thickness">
                        <On Platform="iOS" Value="0,20,0,0" />
                    </OnPlatform>
                </StackLayout.Margin>
                <Label Text="HamburgerMenu Demo" Margin="10" VerticalOptions="Center" FontSize="Large"></Label>
            </StackLayout>
            <ListView x:Name="MenuList" ItemsSource="{Binding MenuItemList}" 
                      SelectedItem="{Binding SelectedMenuItem, Mode=TwoWay}">
                <ListView.Behaviors>
                    <behaviors:EventHandlerBehavior EventName="ItemSelected">
                        <behaviors:InvokeCommandAction 
                            Command="{Binding BindingContext.DataContext.ShowDetailPageAsyncCommand, 
                            Source={x:Reference MainContent}}"></behaviors:InvokeCommandAction>
                        </behaviors:EventHandlerBehavior>
                </ListView.Behaviors>
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout HeightRequest="50">
                                <Label Text="{Binding}" Margin="20,0,0,0" 
                                       VerticalOptions="CenterAndExpand"></Label>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    </ContentPage.Content>
</views:MvxContentPage>

如今是时刻为一切三个平台启动运用顺序并视察终究结果!如今,该运用顺序显现三个平台的准确汉堡菜单,它具有恰当的边距和款式。

小结

在本文中,我向您展现了怎样经由过程Xamarin.Forms和MvvmCross Framework为iOS,Android和UWP建立基础的汉堡菜单组织。我不是专业设想师,因而您能够须要为本身的运用顺序微调款式。我愿望您能够依照这些步调建立一个清洁,文雅的MVVM架构的汉堡菜单组织。别的,我愿望你能从我的演示中取得数据绑定基础知识。请记着,完成雷同目的能够有多种要领,而我的实行并非最好的要领。现实上,我以为为每一个项目增加一个图标会更好!若是您找到更好的处置惩罚方案,请留下批评并在下面举行议论。

你能够在我的GitHub上找到repo:MvxFormsMasterDetailDemoHappy Coding!

 

-玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。