最近在写快报(还没有写完)的过程中,一开始就遇到了这个Master/Detail如何实现的问题。
微软给出Demo并不符合要求,搜索后找到了今日头条开发者写的一篇 :实现Master/Detail布局
拜读之后感觉实现有些麻烦,所以呢这里给出一个更快速的实现。
好滴,下面直接进入正题。
为了实现Master/Detail我决定和今日头条开发者一样采用左右各一个Frame来托管页面
<Grid.ColumnDefinitions> <ColumnDefinition x:Name="MasterColumn" Width="500" /> <ColumnDefinition x:Name="DetailColumn" Width="*" /> </Grid.ColumnDefinitions>
这里左侧给出的宽度为500作为新闻列表的宽度
然后添加两个Frame
<Frame x:Name="MasterFrame" Grid.Column="0" x:FieldModifier="Public"> </Frame> <Frame x:Name="DetailFrame" Grid.Column="1" x:FieldModifier="Public"> </Frame>
然后呢我们为添加一个VisualState,并且添加CurrentStateChanged事件
<VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="AdaptiveStates" CurrentStateChanged="AdaptiveStates_CurrentStateChanged"> <VisualState x:Name="DefaultState"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="720"></AdaptiveTrigger> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="NarrowState"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="0"></AdaptiveTrigger> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="MasterColumn.Width" Value="*" /> <Setter Target="DetailColumn.Width" Value="0" /> <Setter Target="DetailFrame.(Grid.Column)" Value="0"/> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>
看到这里想必各位已经知道了如何实现了,就是在NarrowState的时候主动把右侧的Column宽度设置为0,然后把DetailFrame从右侧移到左侧,此时DetailFrame会覆盖在MasterFrame之上。那么你肯定会问要是DetailFrame里没有内容呢?本应该显示MasterFrame的,但现在DetailFrame将其遮盖了。
其实这就是上面为什么要监听CurrenStateChanged事件的原因
在CurrentStateChanged事件里可以判断如果DetailFrame中内容为空,直接将其设置为不可见就可以了。
下面给出这个函数的代码
private void AdaptiveStates_CurrentStateChanged(object sender, VisualStateChangedEventArgs e) { UpdateUI(); } private void UpdateUI() { if (AdaptiveStates.CurrentState.Name == "NarrowState") { DetailFrame.Visibility = DetailFrame.CanGoBack ? Visibility.Visible : Visibility.Collapsed; } SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = DetailFrame.CanGoBack || MasterFrame.CanGoBack ? AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed; }
为了能在实现在NarrowState的情况下从点击MasterFrame中的新闻之后可以让DetailFrame从不可见变为可见还需要订阅MasterFrame的Navigated事件
为了在按下后退键后DetailFrame被清空后可以返回MasterFrame同样还需要订阅DetailFrame的Navigated事件
所以呢在构造函数如下
public MainPage() { this.InitializeComponent(); this.NavigationCacheMode = NavigationCacheMode.Required; #region Event DetailFrame.Navigated += DetailFrame_Navigated; MasterFrame.Navigated += MasterFrame_Navigated; SystemNavigationManager.GetForCurrentView().BackRequested += View_BackRequested; #endregion }
private void MasterFrame_Navigated(object sender, NavigationEventArgs e) { UpdateUI(); } private void DetailFrame_Navigated(object sender, NavigationEventArgs e) { while (DetailFrame.BackStack.Count > 1) { DetailFrame.BackStack.RemoveAt(1); } UpdateUI(); }
这里需要交代一下快报的情况,DetailFrame默认会有一个背景页面而且默认DetailFrame页面深度为2所以会主动清空上一次的详细页面,这就是RemoveAt(1)的原因。
同样的后退键事件处理函数如下:
private void View_BackRequested(object sender, BackRequestedEventArgs e) { if (DetailFrame.CanGoBack) { DetailFrame.GoBack(); e.Handled = true; } else if (MasterFrame.CanGoBack) { MasterFrame.GoBack(); e.Handled = true; } }
大体的思路就是这样,具体的代码还是直接看源码吧!懒得粘贴了。源文件
最终实现的效果如图: