UWP中用SplitView和Pivot实现两级目录

两级目录类似以下情况

  • 2015 
    • 2015.1 
      • 内容1
      • 内容2
      • 内容3
      • 内容x
  • 12 
    • 12.1 
      • 内容1
      • 内容2
      • 内容3
    • 12.2 
      • 内容1
      • 内容2
  • 24 
    • 24.1 
      • 内容1
      • 内容2
    • 24.2 
      • 内容1
      • 内容2
      • 内容3
    • 24.3 
      • 内容1
      • 内容2

SplitView控件:

有关SplitView的MS文档:SplitView class 
SplitView图样

由图可以看出SplitView控件由Pane和Content组成,所以Pane可以用来存放一级目录,而Content可以用来存放二级目录以及二级目录下的内容。

SplitView控件有几个重要的属性:

PropertyAccess typeDescription
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="&#xE71D;"/>
                </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"
  • 1
  • 2

然后在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

posted @ 2016-09-28 21:00  天涯海角路  阅读(391)  评论(0)    收藏  举报