1. 程式人生 > >UWP 2018 新版 NavigationView 嘗鮮

UWP 2018 新版 NavigationView 嘗鮮

sel pin 如果 mep file mage hub onf per

本文參考了官方文檔以及提供的示例代碼(官方代碼貌似有點誤導,所以寫了這一篇,並且文末有GayHub代碼地址)

官方文檔發布於20180806,說明NavigationView剛發布了沒幾天,還在開發中,所以裏面的接口啥的隨時會變! 隨時會變! 隨時會變! ,用在你的項目之前,請需要做好充足的心理準備。

技術分享圖片

不過他變任他變,效果還是非常誘人的。看一下效果圖

技術分享圖片

2018 新版 NavigationView實現了漢堡菜單和頂部菜單的近乎完美結合,可以參考官方商店的設計風格,就是用的這個控件。

不過要用這個控件,也不是那麽容易的,因為他需要Windows UI Library支持,而這個庫不支持VS2015,必須是2017或者更高版本。詳見 Getting started with the Windows UI Library

下面就說一下實現的完整步驟吧。

1.安裝Microsoft.UI.Xaml

在NuGet中搜索Microsoft.UI.Xaml,需要勾選預發行版本。

然後需要將Microsoft.UI.Xaml添加到應用程序資源。

a. 如果你程序沒有其他的程序資源,那麽

<Application>
    <Application.Resources>
        <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls"/> 
    </Application.Resources
> </Application>

b. 如果已存在其他的,那麽只需要合並一下即可

<Application>
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <XamlControlsResources  xmlns="using:Microsoft.UI.Xaml.Controls"/>
            </
ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>

2. 添加引用

在xaml文件中,添加

xmlns:controls="using:Microsoft.UI.Xaml.Controls"

在.cs文件中添加

using MUXC = Microsoft.UI.Xaml.Controls;

3. 編寫Xaml界面

註意一下被註釋掉的代碼,你可以反註釋一下,看看效果。

我這裏主要是模仿一下商店的風格。

代碼和官方的不大一樣,主要是控件NavigationView,官方並沒有在前面加上命名空間controls,我這裏加上了。如果不加的話,編譯器並不知道i用的是新版的控件。後臺代碼如果不加的話,會爆出N個錯誤。

詳見我的Issue Developers and VS may get confused with namespace Microsoft.UI.Xaml.Controls and Windows.UI.Xaml.Controls

<Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState>
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="{x:Bind NavView.CompactModeThresholdWidth}" />
                    </VisualState.StateTriggers>

                    <VisualState.Setters>
                        <Setter Target="NavView.PaneDisplayMode" Value="Top"/>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <controls:NavigationView x:Name="NavView"
                    SelectionFollowsFocus="Enabled"
                    ItemInvoked="NavView_ItemInvoked"
                    IsSettingsVisible="True"
                    Loaded="NavView_Loaded"
                    BackRequested="NavView_BackRequested">
            <controls:NavigationView.MenuItems>
                <controls:NavigationViewItem Content="Home" x:Name="home" Tag="home">
                    <controls:NavigationViewItem.Icon>
                        <FontIcon Glyph="&#xE10F;"/>
                    </controls:NavigationViewItem.Icon>
                </controls:NavigationViewItem>
                <!--<controls:NavigationViewItemSeparator/>-->
                <!--<controls:NavigationViewItemHeader Content="Main pages"/>-->
                <controls:NavigationViewItem Icon="AllApps" Content="Apps" x:Name="apps" Tag="apps"/>
                <controls:NavigationViewItem Icon="People" Content="Games" x:Name="games" Tag="games"/>
                <controls:NavigationViewItem Icon="Video" Content="Movies and TVs" x:Name="moviestvs" Tag="moviestvs"/>
                <controls:NavigationViewItem Icon="Audio" Content="Music" x:Name="music" Tag="music"/>
                <controls:NavigationViewItem Icon="PhoneBook" Content="Books" x:Name="books" Tag="books"/>
            </controls:NavigationView.MenuItems>

            <!--<controls:NavigationView.AutoSuggestBox>
                <AutoSuggestBox x:Name="ASB" QueryIcon="Find"/>
            </controls:NavigationView.AutoSuggestBox>-->

            <!--<controls:NavigationView.HeaderTemplate>
                <DataTemplate>
                    <Grid Margin="24,10,0,0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Style="{StaticResource TitleTextBlockStyle}"
                           FontSize="28"
                           VerticalAlignment="Center"
                           Text="Welcome"/>
                        <CommandBar Grid.Column="1"
                            HorizontalAlignment="Right"
                            VerticalAlignment="Top"
                            DefaultLabelPosition="Right"
                            Background="{ThemeResource SystemControlBackgroundAltHighBrush}">
                            <AppBarButton Label="Refresh" Icon="Refresh"/>
                            <AppBarButton Label="Import" Icon="Import"/>
                        </CommandBar>
                    </Grid>
                </DataTemplate>
            </controls:NavigationView.HeaderTemplate>-->

            <Frame x:Name="ContentFrame"/>
        </controls:NavigationView>

        <TextBlock Text="New Navigation View" FontSize="12" Margin="12,6,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    </Grid>

4. 添加後臺代碼

首先添加一下必要的引用

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Foundation;
using Windows.System;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Navigation;
using MUXC = Microsoft.UI.Xaml.Controls;

紅色代碼部分是我自己添加的,官方沒有。

因為發現當初與設置界面的時候,拖動窗體改變大小,app會崩潰。目前已經提交官方pr,等待審核

// List of ValueTuple holding the Navigation Tag and the relative Navigation Page 
        private readonly IList<(string Tag, Type Page)> _pages = new List<(string Tag, Type Page)>
        {
            ("home", typeof(HomePage)),
            ("apps", typeof(AppsPage)),
            ("games", typeof(GamesPage)),
            ("moviestvs", typeof(MovieandTVPage)),
            ("music", typeof(MusicPage)),
            ("books", typeof(BooksPage)),
        };

        private void NavView_Loaded(object sender, RoutedEventArgs e)
        {
            // You can also add items in code behind
            //NavView.MenuItems.Add(new NavigationViewItemSeparator());
            //NavView.MenuItems.Add(new NavigationViewItem
            //{
            //    Content = "Settings",
            //    Icon = new SymbolIcon(Symbol.Folder),
            //    Tag = "content"
            //});
            //_pages.Add(("content", typeof(SettingsPage)));

            ContentFrame.Navigated += On_Navigated;

            // NavView doesn‘t load any page by default: you need to specify it
            NavView_Navigate("home");

            // Add keyboard accelerators for backwards navigation
            var goBack = new KeyboardAccelerator { Key = VirtualKey.GoBack };
            goBack.Invoked += BackInvoked;
            this.KeyboardAccelerators.Add(goBack);

            // ALT routes here
            var altLeft = new KeyboardAccelerator
            {
                Key = VirtualKey.Left,
                Modifiers = VirtualKeyModifiers.Menu
            };
            altLeft.Invoked += BackInvoked;
            this.KeyboardAccelerators.Add(altLeft);
        }

        private void NavView_ItemInvoked(MUXC.NavigationView sender, MUXC.NavigationViewItemInvokedEventArgs args)
        {
            if (args.InvokedItem == null)
                return;

            if (args.IsSettingsInvoked)
                ContentFrame.Navigate(typeof(SettingsPage));
            else
            {
                // Getting the Tag from Content (args.InvokedItem is the content of NavigationViewItem)
                var navItemTag = NavView.MenuItems
                    .OfType<MUXC.NavigationViewItem>()
                    .First(i => args.InvokedItem.Equals(i.Content))
                    .Tag.ToString();

                NavView_Navigate(navItemTag);
            }
        }

        private void NavView_Navigate(string navItemTag)
        {
            var item = _pages.First(p => p.Tag.Equals(navItemTag));
            ContentFrame.Navigate(item.Page);
        }

        private void NavView_BackRequested(MUXC.NavigationView sender, MUXC.NavigationViewBackRequestedEventArgs args)
        {
            On_BackRequested();
        }

        private void BackInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
        {
            On_BackRequested();
            args.Handled = true;
        }

        private bool On_BackRequested()
        {
            if (!ContentFrame.CanGoBack)
                return false;

            // Don‘t go back if the nav pane is overlayed
            if (NavView.IsPaneOpen &&
                (NavView.DisplayMode == MUXC.NavigationViewDisplayMode.Compact ||
                NavView.DisplayMode == MUXC.NavigationViewDisplayMode.Minimal))
                return false;

            ContentFrame.GoBack();
            return true;
        }

        private void On_Navigated(object sender, NavigationEventArgs e)
        {
            NavView.IsBackEnabled = ContentFrame.CanGoBack;

            if (ContentFrame.SourcePageType == typeof(SettingsPage))
            {
                // SettingsItem is not part of NavView.MenuItems, and doesn‘t have a Tag
                NavView.SelectedItem = (MUXC.NavigationViewItem)NavView.SettingsItem;
            }
            else
            {
                var item = _pages.First(p => p.Page == e.SourcePageType);

                NavView.SelectedItem = NavView.MenuItems
                    .OfType<MUXC.NavigationViewItem>()
                    .First(n => n.Tag.Equals(item.Tag));
            }
        }

如果你發現,代碼中

IList<(string Tag, Type Page)> _pages = new List<(string Tag, Type Page)>

報錯,請在NuGet中安裝 System.ValueTuple

5. 延申擴展

商店還有一個效果,就是ScrollViewer向下拉的時候,再導航欄下面會有一個模糊的玻璃效果。

技術分享圖片

這個效果官方也做了說明,參考

Scroll content under top pane

不過我的程序中沒做上去,因為 ScrollViewer的 CanContentRenderOutsideBounds 這個屬性,再17134中並沒有,應該在 Insider 17723出現了。

詳見

Windows 10 SDK Preview Build 17723 available now! JULY 31, 2018 10:36 AM

但是不曉得這個屬性,會不會照顧低版本系統呢。。。。。。又是一個坑!!!

我在HomePage裏面註釋了,預覽版可以嘗試一下。

<ScrollViewer>
            <!--<ScrollViewer CanContentRenderOutsideBounds"True">-->
            <StackPanel>
                <TextBlock FontSize="30" TextWrapping="Wrap" Margin="0,100,0,0" IsColorFontEnabled="True" HorizontalAlignment="Center" VerticalAlignment="Center">
                    <Run>For a seamless look+feel, if your app has pages that use a ScrollViewer and your navigation pane is top positioned, we recommend having the content scroll underneath the top nav pane.      
                 This can be achieved by setting the CanContentRenderOutsideBounds property on the relevant ScrollViewer to true.</Run>
                </TextBlock>
                <TextBlock Text="Home" FontSize="100" Margin="0,100,0,0" IsColorFontEnabled="True" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                <TextBlock Text="Home" FontSize="100" Margin="0,100,0,0" IsColorFontEnabled="True" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                <TextBlock Text="Home" FontSize="100" Margin="0,100,0,0" IsColorFontEnabled="True" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                <TextBlock Text="Home" FontSize="100" Margin="0,100,0,0" IsColorFontEnabled="True" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                <TextBlock Text="Home" FontSize="100" Margin="0,100,0,0" IsColorFontEnabled="True" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                <TextBlock Text="Home" FontSize="100" Margin="0,100,0,0" IsColorFontEnabled="True" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </StackPanel>
        </ScrollViewer>

6. 再延申擴展一下

官方還說 Microsoft.UI.Xaml 支持更低的系統版本,最低支持到14393。但是在編譯程序的時候,目標系統一定要是17134或者更高。

有低版本的系統,你可以在低版本上跑一下看看。反正半個月前是不能運行的,我測試過。

不過你的實際程序可能還有其他的官方庫,那些有的可能最低是16299,所以14393也只是一個水中月而已。

7. GayHub項目地址

https://github.com/hupo376787/NewNavigationView

參考官方文檔:

Windows UI Library (Preview version)

Navigation view (Preview version)

Windows 10 SDK Preview Build 17723 available now! JULY 31, 2018 10:36 AM

UWP 2018 新版 NavigationView 嘗鮮