两级目录类似以下情况
- 2015
- 2015.1
- 内容1
- 内容2
- 内容3
- 内容x
- 2015.1
- 12
- 12.1
- 内容1
- 内容2
- 内容3
- 12.2
- 内容1
- 内容2
- 12.1
- 24
- 24.1
- 内容1
- 内容2
- 24.2
- 内容1
- 内容2
- 内容3
- 24.3
- 内容1
- 内容2
- 24.1
SplitView控件:
有关SplitView的MS文档:SplitView class
由图可以看出SplitView控件由Pane和Content组成,所以Pane可以用来存放一级目录,而Content可以用来存放二级目录以及二级目录下的内容。
SplitView控件有几个重要的属性:
Property | Access type | Description |
---|---|---|
DisplayMode | Read/write | Gets of sets a value that specifies how the pane and content areas of a SplitView are shown. |
OpenPaneLength | Read/write | Gets or sets the width of the SplitView pane when it’s fully expanded. |
IsPaneOpen | Read/write | Gets or sets a value that specifies whether the SplitView pane is expanded to its full width. |
使用SplitView可以实现UWP上新加入的汉堡包菜单
初始界面
点击右下角菜单按钮后
SplitView代码
<SplitView x:Name="spViewRoot"
DisplayMode="Overlay"
OpenPaneLength="256"
IsPaneOpen="{Binding MenuOpened, Mode=TwoWay}"
IsTabStop="False">
<SplitView.Pane>
<Grid>
</Grid>
</SplitView.Pane>
<SplitView.Content>
<Grid>
</Grid>
</SplitView.Content>
</SplitView>
Splitview的IsPaneOpen决定了Pane是否展开他绑定了一个后台数据:MenuOpened.
private bool menuOpened;
public bool MenuOpened
{
get
{
return menuOpened;
}
set
{
menuOpened = value;
OnPropertyChanged("MenuOpened");
}
}
配合的BottomAppBar代码
<Page.BottomAppBar>
<CommandBar x:Name="btmCmdBar">
<AppBarButton Label="Menu"
Click="AppBarButton_Click">
<AppBarButton.Icon>
<FontIcon Glyph=""/>
</AppBarButton.Icon>
</AppBarButton>
</CommandBar>
</Page.BottomAppBar>
AppBarButton的Click事件里要做的就是对SplitView的IsPaneOpen取反。这样,每次点击菜单按钮就可以让菜单打开或关闭。
接下来要做的就是向SplitView中添加一级目录
一级目录就相当于是一个列表,所以只需要在SplitView的Pane中添加一个ListView即可,当然为了美观我稍微的设计了一下布局
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListView Grid.Row="1"
Grid.ColumnSpan="2"
ItemsSource="{Binding NavList}"
ItemTemplate="{StaticResource MenuListItemTemplate}">
</ListView>
</Grid>
ListView中的元素布局模板全用数据绑定实现:
<Page.Resources>
<DataTemplate x:Key="MenuListItemTemplate"
x:DataType="model:NavItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<FontIcon x:Name="Glyph" FontSize="16" Glyph="{x:Bind SymbolAsChar}" VerticalAlignment="Center" HorizontalAlignment="Center" ToolTipService.ToolTip="{x:Bind Label}"/>
<TextBlock x:Name="Text" Grid.Column="1" Text="{x:Bind Label}" />
</Grid>
</DataTemplate>
<vm:MainPageViewModel x:Key="viewModel"/>
</Page.Resources>
每个菜单元素的Model:
public class NavItem
{
public enum NavType
{
one,
two,
three,
}
public string Label { get; set; }
//用于表示目录名称前的小图标
public Symbol Symbol { get; set; }
public char SymbolAsChar
{
get
{
return (char)this.Symbol;
}
}
//用来标识目录是哪一项
public NavType DestPage { get; set; }
public object Arguments { get; set; }
}
ViewModel代码如下:
//用于前台一级目录中的 ListView 数据绑定
private List<NavItem> navList;
public List<NavItem> NavList
{
get
{
return navList;
}
set
{
navList = value;
}
}
//在 ViewModel 的构造函数中初始化 ListView 的数据
public MainPageViewModel()
{
this.NavList = new List<NavItem>(
new[]
{
new NavItem()
{
Symbol = Symbol.Favorite,
Label = "2015",
DestPage = NavItem.NavType.one,
},
new NavItem()
{
Symbol = Symbol.Favorite,
Label = "12",
DestPage = NavItem.NavType.two,
},
new NavItem()
{
Symbol = Symbol.Favorite,
Label = "24",
DestPage = NavItem.NavType.three,
},
});
}
此时运行程序就得到了我想要的效果:
更多关于SplitView和汉堡包菜单的实现请看MS官方提供的例子:
Windows-universal-samples / Samples / XamlNavigation /
GitHub
接下来就是二级目录和二级目录下内容的呈现了。
Pivot控件
有关Pivot的MS文档:Pivot class
Pivot控件有两个总要的部分:Title和Items。
Title就是显示在Pivot顶部的标题;Items就是Pivot中的内容,也相当于是一个列表。
而每个Pivot的Item又由两部分组成:Header和Item,所以我从内到外设计模板。
使用模板和数据绑定的好处就是可以动态加载Pivot,这样我们不用把Pivot的数量定死,而是根据一级目录下的元素个数来添加Pivot。
每个PivotItem的模板:
每个PivotItem中用一个ListView来展示内容
<DataTemplate x:Key="PivotListTemplate">
<ListView ItemTemplate="{StaticResource PivotListItemTemplate}"
ItemsSource="{Binding ContentList}"/>
</DataTemplate>
<DataTemplate x:Key="PivotListItemTemplate">
<TextBlock Text="{Binding Content}"/>
</DataTemplate>
他只有一个TextBlock用来显示每一个元素中的内容。
每个PivotItem的header模板:
<DataTemplate x:Key="PivotHeaderTemplate">
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
他只有一个TextBlock用来显示每一个元素Header中的内容。
Pivot代码
<Pivot ItemTemplate="{StaticResource PivotListTemplate}"
HeaderTemplate="{StaticResource PiovtHeaderTemplate}"
ItemsSource="{Binding PivotList}"
Title="{Binding PivotTitle}">
</Pivot>
整个数据绑定的结构:
此时运行结果:
接下来要实现的就是通过SplitView的Pane中菜单点击不同的一级目录,然后再SplitView的Content中显示拥有不同数量PivotItem的Pivot。
为了达到以上效果,我们需要改进一下SplitView的Pane中的ListView。
首先需要让ListView实现元素点击事件,由于ListView没有Command,所以我们需要用微软提供的一个方法来实现。
首先添加引用
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
然后在ListView中添加如下代码:
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SelectionChanged">
<core:InvokeCommandAction Command="{Binding NavCommand}" CommandParameter="{Binding ElementName=lvNavMenu, Path=SelectedItem}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
这样我们就将后台的NavCommand绑定到了ListView的SelectionChanged事件。
后台ViewModel中NavCommand代码:
private DelegateCommand navCommand;
public DelegateCommand NavCommand
{
get
{
return navCommand ?? (navCommand = new DelegateCommand(
(Object obj) =>
{
NavItem selectedItem = obj as NavItem;
if (selectedItem != null)
{
this.PivotTitle = selectedItem.Label;
//判断当前选择的是哪一个一级目录,根据不同的选择加载不同的PivotList
switch (selectedItem.DestPage)
{
case NavItem.NavType.one:
this.PivotList = new List<MyPivotItem>() { new MyPivotItem() };
break;
case NavItem.NavType.two:
this.PivotList = new List<MyPivotItem>() { new MyPivotItem(), new MyPivotItem() };
break;
case NavItem.NavType.three:
this.PivotList = new List<MyPivotItem>() { new MyPivotItem(), new MyPivotItem(), new MyPivotItem() };
break;
}
this.MenuOpened = false;
}
},
(Object obj) => true));
}
}
结果如下所示
更多有关Pivot 的内容请看微软官方的GitHub例子:
Windows-universal-samples / Samples / XamlPivot /
GitHub
本人所用Demo源码:GitHub