天天看點

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

UWP中用SplitView和Pivot實作兩級目錄

由圖可以看出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上新加入的漢堡包菜單

UWP中用SplitView和Pivot實作兩級目錄

初始界面

UWP中用SplitView和Pivot實作兩級目錄

點選右下角菜單按鈕後

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,
        },
    });
}
           

此時運作程式就得到了我想要的效果:

UWP中用SplitView和Pivot實作兩級目錄

更多關于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>
           

整個資料綁定的結構:

UWP中用SplitView和Pivot實作兩級目錄

此時運作結果:

UWP中用SplitView和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));
    }
}
           

結果如下所示

UWP中用SplitView和Pivot實作兩級目錄
UWP中用SplitView和Pivot實作兩級目錄
UWP中用SplitView和Pivot實作兩級目錄

更多有關Pivot 的内容請看微軟官方的GitHub例子:

Windows-universal-samples / Samples / XamlPivot /

GitHub

本人所用Demo源碼:GitHub