mardi 4 août 2015

UWP SplitView DisplayMode="Overlay" doesn't work

I have a SplitView in WIn10 C# application. I set SplitVIew DisplayMode to Overlay but it still used the Inline. Here's my XAML:

<Page x:Name="Root"
  x:Class="NavigationMenuSample.AppShell"
  xmlns="http://ift.tt/o66D3f"
  xmlns:x="http://ift.tt/mPTqtT"
  xmlns:local="using:NavigationMenuSample"
  xmlns:controls="using:NavigationMenuSample.Controls"
  xmlns:d="http://ift.tt/pHvyf2"
  xmlns:mc="http://ift.tt/pzd6Lm"
  Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
  KeyDown="AppShell_KeyDown"
  TabNavigation="Cycle"
  mc:Ignorable="d">

<!-- Using a Page as the root for the app provides a design time experience as well as ensures that
     when it runs on Mobile the app content won't appear under the system's StatusBar which is visible 
     by default with a transparent background.  It will also take into account the presence of software
     navigation buttons if they appear on a device.  An app can opt-out by switching to UseCoreWindow.
-->

<Page.Resources>
    <DataTemplate x:Key="NavMenuItemTemplate" x:DataType="local:NavMenuItem">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="48" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <!-- Showing a ToolTip and the Label is redundant.  We put the ToolTip on the icon.
                 It appears when the user hovers over the icon, but not the label which provides
                 value when the SplitView is 'Compact' while reducing the likelihood of showing
                 redundant information when the label is shown.-->
            <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>
</Page.Resources>

<Grid>
    <!-- Adaptive triggers -->
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState>
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="720" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="RootSplitView.DisplayMode" Value="CompactInline"/>
                    <Setter Target="RootSplitView.IsPaneOpen" Value="True"/>
                </VisualState.Setters>
            </VisualState>
            <VisualState>
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="RootSplitView.DisplayMode" Value="Overlay"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <!-- Top-level navigation menu + app content -->
    <SplitView x:Name="RootSplitView"
               DisplayMode="Overlay"
               OpenPaneLength="256"
               IsTabStop="False">
        <SplitView.Pane>
            <!-- A custom ListView to display the items in the pane.  The automation Name is set in the ContainerContentChanging event. -->
            <controls:NavMenuListView x:Name="NavMenuList"
                                      TabIndex="3"
                                      Margin="0,48,0,0"
                                      ContainerContentChanging="NavMenuItemContainerContentChanging"
                                      ItemContainerStyle="{StaticResource NavMenuItemContainerStyle}"
                                      ItemTemplate="{StaticResource NavMenuItemTemplate}"
                                      ItemInvoked="NavMenuList_ItemInvoked">
                <controls:NavMenuListView.Header>
                    <!-- Using this custom back navigation button until the system-provided back button is enabled. -->
                    <Button x:Name="BackButton"
                            TabIndex="2"
                            Style="{StaticResource NavigationBackButtonStyle}"
                            IsEnabled="{Binding AppFrame.CanGoBack, ElementName=Root}"
                            Width="{Binding ItemsPanelRoot.Width, ElementName=NavMenuList}"
                            HorizontalAlignment="{Binding ItemsPanelRoot.HorizontalAlignment, ElementName=NavMenuList}"
                            Click="BackButton_Click"/>
                </controls:NavMenuListView.Header>
            </controls:NavMenuListView>
        </SplitView.Pane>

        <!-- OnNavigatingToPage we synchronize the selected item in the nav menu with the current page.
             OnNavigatedToPage we move keyboard focus to the first item on the page after it's loaded. -->
        <Frame x:Name="frame"
               Navigating="OnNavigatingToPage"
               Navigated="OnNavigatedToPage">
            <Frame.ContentTransitions>
                <TransitionCollection>
                    <NavigationThemeTransition>
                        <NavigationThemeTransition.DefaultNavigationTransitionInfo>
                            <EntranceNavigationTransitionInfo/>
                        </NavigationThemeTransition.DefaultNavigationTransitionInfo>
                    </NavigationThemeTransition>
                </TransitionCollection>
            </Frame.ContentTransitions>
        </Frame>
    </SplitView>

    <!-- Declared last to have it rendered above everything else, but it needs to be the first item in the tab sequence. -->
    <ToggleButton x:Name="TogglePaneButton"
                  TabIndex="1"
                  Style="{StaticResource SplitViewTogglePaneButtonStyle}"
                  IsChecked="{Binding IsPaneOpen, ElementName=RootSplitView, Mode=TwoWay}"
                  Unchecked="TogglePaneButton_Checked"
                  AutomationProperties.Name="Menu"
                  ToolTipService.ToolTip="Menu" />
</Grid>

I got this from XAMLNavigationSample from Win 10 github samples. And here's the .cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Metadata;
using Windows.UI.Xaml.Automation;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using NavigationMenuSample.Controls;
using NavigationMenuSample.Views;

namespace NavigationMenuSample
{
    /// <summary>
    /// The "chrome" layer of the app that provides top-level navigation with
    /// proper keyboarding navigation.
    /// </summary>
    public sealed partial class AppShell : Page
    {
        // Declare the top level nav items
        private List<NavMenuItem> navlist = new List<NavMenuItem>(
            new[]
            {
                new NavMenuItem()
                {
                    Symbol = Symbol.Contact,
                    Label = "Basic Page",
                    DestPage = typeof(BasicPage)
                },
                new NavMenuItem()
                {
                    Symbol = Symbol.Edit,
                    Label = "CommandBar Page",
                    DestPage = typeof(CommandBarPage)
                },
                new NavMenuItem()
                {
                    Symbol = Symbol.Favorite,
                    Label = "Drill In Page",
                    DestPage = typeof(DrillInPage)
                },
            });

        public static AppShell Current = null;

        /// <summary>
        /// Initializes a new instance of the AppShell, sets the static 'Current' reference,
        /// adds callbacks for Back requests and changes in the SplitView's DisplayMode, and
        /// provide the nav menu list with the data to display.
        /// </summary>
        public AppShell()
        {
            this.InitializeComponent();

            this.Loaded += (sender, args) =>
            {
                Current = this;

                this.TogglePaneButton.Focus(FocusState.Programmatic);
            };

            SystemNavigationManager.GetForCurrentView().BackRequested += SystemNavigationManager_BackRequested;

            // If on a phone device that has hardware buttons then we hide the app's back button.
            if (ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
            {
                this.BackButton.Visibility = Visibility.Collapsed;
            }

            NavMenuList.ItemsSource = navlist;
        }

        public Frame AppFrame { get { return this.frame; } }

        /// <summary>
        /// Default keyboard focus movement for any unhandled keyboarding
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AppShell_KeyDown(object sender, KeyRoutedEventArgs e)
        {
            FocusNavigationDirection direction = FocusNavigationDirection.None;
            switch (e.Key)
            {
                case Windows.System.VirtualKey.Left:
                case Windows.System.VirtualKey.GamepadDPadLeft:
                case Windows.System.VirtualKey.GamepadLeftThumbstickLeft:
                case Windows.System.VirtualKey.NavigationLeft:
                    direction = FocusNavigationDirection.Left;
                    break;
                case Windows.System.VirtualKey.Right:
                case Windows.System.VirtualKey.GamepadDPadRight:
                case Windows.System.VirtualKey.GamepadLeftThumbstickRight:
                case Windows.System.VirtualKey.NavigationRight:
                    direction = FocusNavigationDirection.Right;
                    break;

                case Windows.System.VirtualKey.Up:
                case Windows.System.VirtualKey.GamepadDPadUp:
                case Windows.System.VirtualKey.GamepadLeftThumbstickUp:
                case Windows.System.VirtualKey.NavigationUp:
                    direction = FocusNavigationDirection.Up;
                    break;

                case Windows.System.VirtualKey.Down:
                case Windows.System.VirtualKey.GamepadDPadDown:
                case Windows.System.VirtualKey.GamepadLeftThumbstickDown:
                case Windows.System.VirtualKey.NavigationDown:
                    direction = FocusNavigationDirection.Down;
                    break;
            }

            if (direction != FocusNavigationDirection.None)
            {
                var control = FocusManager.FindNextFocusableElement(direction) as Control;
                if (control != null)
                {
                    control.Focus(FocusState.Programmatic);
                    e.Handled = true;
                }
            }
        }

        #region BackRequested Handlers

        private void SystemNavigationManager_BackRequested(object sender, BackRequestedEventArgs e)
        {
            bool handled = e.Handled;
            this.BackRequested(ref handled);
            e.Handled = handled;
        }

        private void BackButton_Click(object sender, RoutedEventArgs e)
        {
            bool ignored = false;
            this.BackRequested(ref ignored);
        }

        private void BackRequested(ref bool handled)
        {
            // Get a hold of the current frame so that we can inspect the app back stack.

            if (this.AppFrame == null)
                return;

            // Check to see if this is the top-most page on the app back stack.
            if (this.AppFrame.CanGoBack && !handled)
            {
                // If not, set the event to handled and go back to the previous page in the app.
                handled = true;
                this.AppFrame.GoBack();
            }
        }

        #endregion

        #region Navigation

        /// <summary>
        /// Navigate to the Page for the selected <paramref name="listViewItem"/>.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="listViewItem"></param>
        private void NavMenuList_ItemInvoked(object sender, ListViewItem listViewItem)
        {
            var item = (NavMenuItem)((NavMenuListView)sender).ItemFromContainer(listViewItem);

            if (item != null)
            {
                if (item.DestPage != null &&
                    item.DestPage != this.AppFrame.CurrentSourcePageType)
                {
                    this.AppFrame.Navigate(item.DestPage, item.Arguments);
                }
            }
        }

        /// <summary>
        /// Ensures the nav menu reflects reality when navigation is triggered outside of
        /// the nav menu buttons.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnNavigatingToPage(object sender, NavigatingCancelEventArgs e)
        {
            if (e.NavigationMode == NavigationMode.Back)
            {
                var item = (from p in this.navlist where p.DestPage == e.SourcePageType select p).SingleOrDefault();
                if (item == null && this.AppFrame.BackStackDepth > 0)
                {
                    // In cases where a page drills into sub-pages then we'll highlight the most recent
                    // navigation menu item that appears in the BackStack
                    foreach (var entry in this.AppFrame.BackStack.Reverse())
                    {
                        item = (from p in this.navlist where p.DestPage == entry.SourcePageType select p).SingleOrDefault();
                        if (item != null)
                            break;
                    }
                }

                var container = (ListViewItem)NavMenuList.ContainerFromItem(item);

                // While updating the selection state of the item prevent it from taking keyboard focus.  If a
                // user is invoking the back button via the keyboard causing the selected nav menu item to change
                // then focus will remain on the back button.
                if (container != null) container.IsTabStop = false;
                NavMenuList.SetSelectedItem(container);
                if (container != null) container.IsTabStop = true;
            }
        }

        private void OnNavigatedToPage(object sender, NavigationEventArgs e)
        {
            // After a successful navigation set keyboard focus to the loaded page
            if (e.Content is Page && e.Content != null)
            {
                var control = (Page)e.Content;
                control.Loaded += Page_Loaded;
            }
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            ((Page)sender).Focus(FocusState.Programmatic);
            ((Page)sender).Loaded -= Page_Loaded;
        }

        #endregion

        public Rect TogglePaneButtonRect
        {
            get;
            private set;
        }

        /// <summary>
        /// An event to notify listeners when the hamburger button may occlude other content in the app.
        /// The custom "PageHeader" user control is using this.
        /// </summary>
        public event TypedEventHandler<AppShell, Rect> TogglePaneButtonRectChanged;

        /// <summary>
        /// Callback when the SplitView's Pane is toggled open or close.  When the Pane is not visible
        /// then the floating hamburger may be occluding other content in the app unless it is aware.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TogglePaneButton_Checked(object sender, RoutedEventArgs e)
        {
            this.CheckTogglePaneButtonSizeChanged();
        }

        /// <summary>
        /// Check for the conditions where the navigation pane does not occupy the space under the floating
        /// hamburger button and trigger the event.
        /// </summary>
        private void CheckTogglePaneButtonSizeChanged()
        {
            if (this.RootSplitView.DisplayMode == SplitViewDisplayMode.Inline ||
                this.RootSplitView.DisplayMode == SplitViewDisplayMode.Overlay)
            {
                var transform = this.TogglePaneButton.TransformToVisual(this);
                var rect = transform.TransformBounds(new Rect(0, 0, this.TogglePaneButton.ActualWidth, this.TogglePaneButton.ActualHeight));
                this.TogglePaneButtonRect = rect;
            }
            else
            {
                this.TogglePaneButtonRect = new Rect();
            }

            var handler = this.TogglePaneButtonRectChanged;
            if (handler != null)
            {
                // handler(this, this.TogglePaneButtonRect);
                handler.DynamicInvoke(this, this.TogglePaneButtonRect);
            }
        }

        /// <summary>
        /// Enable accessibility on each nav menu item by setting the AutomationProperties.Name on each container
        /// using the associated Label of each item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void NavMenuItemContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
        {
            if (!args.InRecycleQueue && args.Item != null && args.Item is NavMenuItem)
            {
                args.ItemContainer.SetValue(AutomationProperties.NameProperty, ((NavMenuItem)args.Item).Label);
            }
            else
            {
                args.ItemContainer.ClearValue(AutomationProperties.NameProperty);
            }
        }
    }
}

What I want to achieve: (also I want to make Pane transparent, but I think this is possible easily. enter image description here

What I have: enter image description here

There is another problem with this sample: The Pane is ALWAYS open on the startup even if I do IsPaneOpen="False"



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire