到了Win10,微软模仿其他平台也推出了汉堡菜单,但并没有提供现成的控件,而是需要开发者通过一个名为SplitView的控件来实现。我个人并不觉得左上角的菜单有多么方便,汉堡菜单的使用必然会改变以前的导航模式,比如以前底部的AppBar使用很频繁,现在可以通过汉堡菜单的按钮来切换不同的页面。因此之前的App的导航模式需要重新设计。
假设有A、B、C三个平行的页面,可以在每个页面的左侧都放个汉堡菜单,也可以像web的框架页一样,做一个壳,汉堡菜单只放在外面的框架里,点击不同的按钮,在content里实现不同页面的导航。我比较倾向第二种,之前在做澎湃新闻uwp的时候就使用了这种方式,后来看了下Template10的模板,也是用的这种方式,在主页面外层套了一个Frame,而且还实现 了一个汉堡菜单控件。有兴趣的同学可以参考Template10来快速生成一个带汉堡菜单的基础App,Github地址:https://github.com/Windows-XAML/Template10 ,这个项目还带了很多好东西,比如一些常用的帮助类和一些behavior等,值得uwp开发者好好学习。
我没有直接使用T10的模板,以下介绍的还是当时使用MVVM-Sidekick框架实现的页面内导航。
首先通过MVVM-Sidekick提供的项目模板来新建一个UWP项目,命名为NavDemo。
考虑我们要实现的目的:在主页面放置一个汉堡菜单,在右侧的content中实现不同页面的导航。
先来看一下效果:
PC版:
手机版:
一、创建菜单项类
汉堡菜单每个选项一般是由一个图标和一个文字组成,我还是使用FontAwesomeFont这个字体来显示图标,如何使用这个字体来做图标,可参考我之前的blog。首先建立一个菜单的类NavMenuItem,放在Models目录下,使用provm代码段生成两个属性:
publicclass NavMenuItem : BindableBase<NavMenuItem> { ///<summary> /// FontAwesomeFontFamily ///</summary> publicstring Glyph { get {return _GlyphLocator(this).Value; } set { _GlyphLocator(this).SetValueAndTryNotify(value); } } #region Property string Glyph Setup protectedProperty<string> _Glyph =new Property<string> { LocatorFunc = _GlyphLocator }; staticFunc<BindableBase,ValueContainer<string>> _GlyphLocator = RegisterContainerLocator<string>("Glyph", model => model.Initialize("Glyph",ref model._Glyph, ref _GlyphLocator, _GlyphDefaultValueFactory)); staticFunc<string> _GlyphDefaultValueFactory = () => {return default(string); }; #endregion ///<summary> ///文字 ///</summary> publicstring Label { get {return _LabelLocator(this).Value; } set { _LabelLocator(this).SetValueAndTryNotify(value); } } #region Property string Label Setup protectedProperty<string> _Label =new Property<string> { LocatorFunc = _LabelLocator }; staticFunc<BindableBase,ValueContainer<string>> _LabelLocator = RegisterContainerLocator<string>("Label", model => model.Initialize("Label",ref model._Label, ref _LabelLocator, _LabelDefaultValueFactory)); staticFunc<string> _LabelDefaultValueFactory = () => {return default(string); }; #endregion }
打开NavDemo\ViewModels\MainPage_Model.cs,使用propvm代码段生成一个列表:
publicObservableCollection<NavMenuItem> NavMenuItemList { get {return _NavMenuItemListLocator(this).Value; } set { _NavMenuItemListLocator(this).SetValueAndTryNotify(value); } } #region Property ObservableCollection<HamburgerMenuItem> NavMenuItemList Setup protectedProperty<ObservableCollection<NavMenuItem>> _NavMenuItemList =new Property<ObservableCollection<NavMenuItem>> { LocatorFunc = _NavMenuItemListLocator }; staticFunc<BindableBase,ValueContainer<ObservableCollection<NavMenuItem>>> _NavMenuItemListLocator = RegisterContainerLocator<ObservableCollection<NavMenuItem>>("NavMenuItemList", model => model.Initialize("NavMenuItemList",ref model._NavMenuItemList, ref _NavMenuItemListLocator, _NavMenuItemListDefaultValueFactory)); staticFunc<ObservableCollection<NavMenuItem>> _NavMenuItemListDefaultValueFactory = () =>default(ObservableCollection<NavMenuItem>); #endregion
public MainPage_Model() { if (IsInDesignMode ) { Title = "Title is a little different in Design mode"; } NavMenuItemList = new ObservableCollection<NavMenuItem>(); NavMenuItemList.Add(newNavMenuItem { Glyph = "\uf015", Label = "首页" }); NavMenuItemList.Add(newNavMenuItem { Glyph = "\uf002", Label = "搜索" }); NavMenuItemList.Add(newNavMenuItem { Glyph = "\uf05a", Label = "关于" }); }
在项目中新建Resources目录,把FontAwesome.otf字体文件放在里面。在项目中新建CustomTheme目录,然后建立自定义的样式资源文件CustomStyles.xaml,代码如下:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:NavDemo"> <FontFamily x:Key="FontAwesomeFontFamily">/Resources/FontAwesome.otf#FontAwesome</FontFamily> <Style x:Key="SplitViewTogglePaneButtonStyle" TargetType="ToggleButton"> <Setter Property="FontSize" Value="20" /> <Setter Property="FontFamily" Value="{ThemeResource SymbolThemeFontFamily}" /> <Setter Property="MinHeight" Value="48" /> <Setter Property="MinWidth" Value="48" /> <Setter Property="Margin" Value="0" /> <Setter Property="Padding" Value="0" /> <Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="VerticalAlignment" Value="Top" /> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="Background" Value="Transparent" /> <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" /> <Setter Property="Content" Value="" /> <Setter Property="AutomationProperties.Name" Value="Menu" /> <Setter Property="UseSystemFocusVisuals" Value="True"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ToggleButton"> <Grid Background="{TemplateBinding Background}" x:Name="LayoutRoot"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextBlock.Foreground)"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Checked"/> <VisualState x:Name="CheckedPointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="CheckedPressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="CheckedDisabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextBlock.Foreground)"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" AutomationProperties.AccessibilityView="Raw" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="CustomTheme/CustomStyles.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>
拆分视图控件具有一个可展开/可折叠的窗格和一个内容区域。内容区域始终可见。窗格可以展开和折叠或停留在打开状态,而且可以从应用窗口的左侧或右侧显示其自身。窗格中有三种模式:
|
所以我就根据官方文档设置为48了。
修改MainPage.xaml,把根Grid改为以下代码:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"DataContext="{StaticResource DesignVM}"> <!-- Top-level navigation menu + app content --> <SplitView x:Name="RootSplitView" IsPaneOpen="True" DisplayMode="Inline" OpenPaneLength="256" IsTabStop="False"> <SplitView.Pane> <!-- A custom ListView to display the items in the pane. The automation Name is set in the ContainerContentChanging event. --> <ListView ItemsSource="{Binding NavMenuItemList}"> </ListView> </SplitView.Pane> <SplitView.Content> <Frame x:Name="mainFrame"> </Frame> </SplitView.Content> </SplitView> <!-- Declared last to have it rendered above everything else, but it needs to be the first item in the tab sequence. --> <ToggleButton x:Name="TogglePaneButton" TabIndex="1" Style="{StaticResource SplitViewTogglePaneButtonStyle}" IsChecked="{Binding IsPaneOpen, ElementName=RootSplitView, Mode=TwoWay}" AutomationProperties.Name="Menu" ToolTipService.ToolTip="Menu" /> </Grid>
注意,如果当SplitView的Content直接设置为Frame的时候,也就是把外层的<SplitView.Content>去掉后,会报一个错:
这个错误可以不用理会,程序是可以正常运行的。
此外 还要有一个按钮来控制菜单的展开关闭状态,用一个ToggleButton来实现,这个按钮的图标一般是三个横杠,设置其Style为SplitViewTogglePaneButtonStyle即可。
然后,还要设置ListView的项模板,可以使用Blend来设计项模板,但因为这个比较简单,我就直接手写了,在Resources目录下添加一个资源文件CustomDataTemplates.xaml,项目所有的自定义模板都可以写在这里,代码如下:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core" xmlns:Behaviors="using:MVVMSidekick.Behaviors"> <DataTemplate x:Key="NavMenuItemTemplate" > <Grid> <Grid.ColumnDefinitions> <ColumnDefinition MinWidth="48" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <FontIcon x:Name="Glyph" FontFamily="{StaticResource FontAwesomeFontFamily}" FontSize="16" Margin="0" Glyph="{Binding Glyph}" VerticalAlignment="Center" HorizontalAlignment="Center" ToolTipService.ToolTip="{Binding Label}"/> <TextBlock x:Name="Text" Grid.Column="1" Text="{Binding Label}" VerticalAlignment="Center"/> </Grid> </DataTemplate> </ResourceDictionary>
再把这个项模板应用到页面的ListView控件上:
ItemTemplate="{StaticResource NavMenuItemTemplate}"
现在跑一下试试,报错了:
原来忘了把刚才的模板文件引入进来,修改App.xaml,修改为以下的样子:
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="CustomTheme/CustomStyles.xaml"/> <ResourceDictionary Source="Resources/CustomDataTemplates.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>
现在可以运行了:
貌似左上角的按钮跟ListView重叠了,这样可不好看。
三、调整显示效果
左上角的按钮应用了SplitViewTogglePaneButtonStyle样式,最小高度为48,把ListView往下移动一点,添加一个Margin属性,顶部把开关按钮的空间空出来:
<ListView Margin="0,48,0,0" ItemsSource="{Binding NavMenuItemList}" ItemTemplate="{StaticResource NavMenuItemTemplate}">
现在列表位置正常了,但图标的位置貌似还是偏右了,那就再给ListView设置ItemContainerStyle样式,在CustomStyles.xaml文件里添加以下代码:
<Style x:Key="NavMenuItemContainerStyle" TargetType="ListViewItem"> <Setter Property="MinWidth" Value="{StaticResource SplitViewCompactPaneThemeLength}"/> <Setter Property="Height" Value="48"/> <Setter Property="Padding" Value="0"/> </Style>
<ListView Margin="0,48,0,0" ItemsSource="{Binding NavMenuItemList}" ItemTemplate="{StaticResource NavMenuItemTemplate}" ItemContainerStyle="{StaticResource NavMenuItemContainerStyle}"> </ListView>
再跑一下:
现在样式正常了。
四、增加新页面
现在MainPage.xaml只是一个壳,右侧内容是空的,下面来添加几个页面。在项目里添加几个页面,比如可以命名为HomePage、SearchPage、AboutPage等:
因为每个页面里已经默认添加了一个TextBlock,并且绑定到了vm的Title属性,这个属性默认取值就是当前页面的Name,所以我们就不用改了,知道当前页面是哪个就行了。
现在的问题是,如何在MainPage载入时,自动在SplitView的Content里显示HomePage呢?
这就需要用到MVVM-Sidekick的一个Behavior了,用Blend打开项目,找到行为:
有一个叫做BaeconBehavior的行为,把它拖到……咦,怎么找不到Content呢?
那就直接手写吧,把Frame部分的代码改成这样:
<SplitView.Content> <Frame x:Name="mainFrame" mvvm:StageManager.Beacon="frameMain" x:FieldModifier="public"> </Frame> </SplitView.Content>
mvvm:StageManager.Beacon="frameMain"
找到OnBindedViewLoad方法,取消默认的注释,将该方法改为以下的样子:
protectedoverride async Task OnBindedViewLoad(MVVMSidekick.Views.IView view) { awaitbase.OnBindedViewLoad(view); await StageManager["frameMain"].Show(newHomePage_Model()); }
跑一下看看:
很好,默认转到HomePage页了。
五、实现其他页面导航
现在可以处理菜单部分的导航了,点击不同的项导航到不同的页面。看到这里应该也有个大概了,处理不同项的点击事件,将名为frameMain的StageManager使用Show方法展示不同的ViewModel即可。
使用ItemClick事件吗?No,还记得我之前提过的SendToEventRouterAction吗?如果不熟悉的话就翻翻我之前的blog吧,这里我还是用这个Action来实现。
修改项模板为:
<DataTemplate x:Key="NavMenuItemTemplate" > <Grid> <Interactivity:Interaction.Behaviors> <Core:EventTriggerBehavior EventName="Tapped"> <Behaviors:SendToEventRouterAction IsEventFiringToAllBaseClassesChannels="True" EventRoutingName="NavToPage" EventData="{Binding}" /> </Core:EventTriggerBehavior> </Interactivity:Interaction.Behaviors> <Grid.ColumnDefinitions> <ColumnDefinition MinWidth="48" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <FontIcon x:Name="Glyph" FontFamily="{StaticResource FontAwesomeFontFamily}" FontSize="16" Margin="0" Glyph="{Binding Glyph}" VerticalAlignment="Center" HorizontalAlignment="Center" ToolTipService.ToolTip="{Binding Label}"/> <TextBlock x:Name="Text" Grid.Column="1" Text="{Binding Label}" VerticalAlignment="Center"/> </Grid> </DataTemplate>
privatevoid RegisterCommand() { //一般列表项点击事件 MVVMSidekick.EventRouting.EventRouter.Instance.GetEventChannel<Object>() .Where(x => x.EventName == "NavToPage") .Subscribe( async e => { NavMenuItem item = e.EventDataas NavMenuItem; if (item !=null) { switch (item.Label) { case"首页": await StageManager["frameMain"].Show(newHomePage_Model()); break; case"搜索": await StageManager["frameMain"].Show(newSearchPage_Model()); break; case"关于": await StageManager["frameMain"].Show(newAboutPage_Model()); break; default: break; } } } ).DisposeWith(this); }
别忘了在OnBindedViewLoad方法里调用一下:
privatebool isLoaded; ///<summary> /// This will be invoked by view when the view fires Load event and this viewmodel instance is already in view's ViewModel property ///</summary> ///<param name="view">View that firing Load event</param> ///<returns>Task awaiter</returns> protectedoverride async Task OnBindedViewLoad(MVVMSidekick.Views.IView view) { if (!isLoaded) { this.RegisterCommand(); this.isLoaded =true; } awaitbase.OnBindedViewLoad(view); await StageManager["frameMain"].Show(newHomePage_Model()); }
跑一下看看,咦,有时候好用,有时候不好用,点击图标和文字的时候好用,点击不到图标和文字就不好用,这是什么原因?
熟悉ListView的同学可能会想到,ListViewItem默认是没有横向撑满的,所以虽然点击了项,但因为项模板里的Grid没有横向撑满,所以并没有触发Grid的Tapped事件,那我们可以设置ListItemStyle,让ListViewItem都横向撑满。在NavMenuItemContainerStyle里添加以下代码:
<Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/>
这样就可以横向纵向撑满了,再跑下:
又乱套了,再改哪里呢,修改项模板NavMenuItemTemplate,设置左侧列宽为Auto:
<DataTemplate x:Key="NavMenuItemTemplate" > <Grid > <Interactivity:Interaction.Behaviors> <Core:EventTriggerBehavior EventName="Tapped"> <Behaviors:SendToEventRouterAction IsEventFiringToAllBaseClassesChannels="True" EventRoutingName="NavToPage" EventData="{Binding}" /> </Core:EventTriggerBehavior> </Interactivity:Interaction.Behaviors> <Grid.ColumnDefinitions> <ColumnDefinition MinWidth="48" Width="Auto" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <FontIcon x:Name="Glyph" FontFamily="{StaticResource FontAwesomeFontFamily}" FontSize="16" Margin="0" Glyph="{Binding Glyph}" VerticalAlignment="Center" HorizontalAlignment="Center" ToolTipService.ToolTip="{Binding Label}"/> <TextBlock x:Name="Text" Grid.Column="1" Text="{Binding Label}" VerticalAlignment="Center" /> </Grid> </DataTemplate>
再运行一下:
现在正常了。
看一下手机上的样子:
六、其他细节调整
使用了一下感觉还是有点细节需要改进,比如菜单弹出后,点击项后应该让菜单自动缩回去,现在改一下吧。
在MainPage的vm里添加一个属性:
///<summary> ///是否展开菜单 ///</summary> publicbool IsPaneOpen { get {return _IsPaneOpenLocator(this).Value; } set { _IsPaneOpenLocator(this).SetValueAndTryNotify(value); } } #region Property bool IsPaneOpen Setup protectedProperty<bool> _IsPaneOpen =newProperty<bool> { LocatorFunc = _IsPaneOpenLocator }; staticFunc<BindableBase,ValueContainer<bool>> _IsPaneOpenLocator = RegisterContainerLocator<bool>("IsPaneOpen", model => model.Initialize("IsPaneOpen",ref model._IsPaneOpen, ref _IsPaneOpenLocator, _IsPaneOpenDefaultValueFactory)); staticFunc<bool> _IsPaneOpenDefaultValueFactory = () =>default(bool); #endregion |
在vm的构造函数里将此值设置为false,默认为关闭。
然后将SplitView的IsPaneOpen属性绑定到上面:
<SplitView x:Name="RootSplitView" IsPaneOpen="{Binding IsPaneOpen,Mode=TwoWay}" DisplayMode="Inline" OpenPaneLength="256" IsTabStop="False"> |
修改RegisterCommand方法,在点击每个项的部分,添加以下代码,关闭菜单:
this.IsPaneOpen =false; |
现在点击菜单项后可以自动关闭菜单面板了。
还可以继续针对PC版和手机版调整一下细节,PC版屏幕大,可以让菜单收起时留下图标的部分,这就需要调整PC版的DisplayMode属性为CompactInline,需要请StateTriggers出马了。
在根Grid里添加以下代码:
<!-- Adaptive triggers --> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="720" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="RootSplitView.DisplayMode" Value="CompactInline"/> <Setter Target="RootSplitView.IsPaneOpen" Value="True"/> <Setter Target="RootSplitView.CompactPaneLength" Value="48" /> </VisualState.Setters> </VisualState> <VisualState> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="0" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="RootSplitView.DisplayMode" Value="Overlay"/> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> |
这段代码的意思是,如果宽度大于720,就将SplitView的DisplayMode设置为CompactInline,菜单收起的时候可以保留图标部分,这部分图标的宽度通过CompactPaneLength这个值来设定。
还有一点,手机是有硬件返回键的,在菜单弹出的时候,如果用户点击了返回键,应该让菜单缩回去,所以还要额外处理一下手机的返回键。
给项目添加Mobile Extensions引用:
注意我安装了两个版本的SDK,这里需要根据项目的实际版本来选择对应的扩展。
打开MainPage.xaml.cs,添加以下代码:
protectedoverride void OnNavigatedTo(NavigationEventArgs e) { if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) { HardwareButtons.BackPressed += HardwareButtons_BackPressed; } base.OnNavigatedTo(e); } protectedoverride void OnNavigatedFrom(NavigationEventArgs e) { if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) { HardwareButtons.BackPressed -= HardwareButtons_BackPressed; } base.OnNavigatedFrom(e); } privatevoid HardwareButtons_BackPressed(object sender,BackPressedEventArgs e) { //throw new NotImplementedException(); var vm =this.LayoutRoot.DataContext as MainPage_Model; if (vm !=null) { if (vm.IsPaneOpen) { e.Handled = true; vm.IsPaneOpen = false; } } }
附demo下载地址:
链接:http://pan.baidu.com/s/1pJRJcRh 密码:jofi
开发者交流群:53078485,期待您的加入!