Skip to content

Instantly share code, notes, and snippets.

@itsWindows11
Created April 22, 2022 14:49
Show Gist options
  • Save itsWindows11/fd4b0703c25a508d1b14c00024ceb265 to your computer and use it in GitHub Desktop.
Save itsWindows11/fd4b0703c25a508d1b14c00024ceb265 to your computer and use it in GitHub Desktop.
UWP NavigationView-dependent module to make navigation easier
<Page
x:Class="ModuleNavigationSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
muxc:BackdropMaterial.ApplyToRootOrPageBackground="True"
d:Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<muxc:NavigationView x:Name="NavView"
Loaded="NavView_Loaded"
ItemInvoked="NavView_ItemInvoked"
BackRequested="NavView_BackRequested"
IsBackEnabled="{x:Bind ContentFrame.CanGoBack, Mode=OneWay}"
IsSettingsVisible="False">
<muxc:NavigationView.AutoSuggestBox>
<AutoSuggestBox x:Name="NavViewSearchBox" QueryIcon="Find" />
</muxc:NavigationView.AutoSuggestBox>
<Frame x:Name="ContentFrame"
Padding="12,0,12,24"
IsTabStop="True"
NavigationFailed="ContentFrame_NavigationFailed" />
</muxc:NavigationView>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{x:Bind NavView.CompactModeThresholdWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ContentFrame.Padding" Value="24,0,24,24" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</Page>
using ModuleNavigationSample.Modules;
using ModuleNavigationSample.Pages;
using System;
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using muxc = Microsoft.UI.Xaml.Controls;
namespace ModuleNavigationSample
{
public sealed partial class MainPage : Page
{
public NavigationModule HomePageModule, SettingsPageModule, TestPageModule, SelectedModule;
public MainPage()
{
InitializeComponent();
}
private void NavView_Loaded(object sender, RoutedEventArgs e)
{
NavView.Loaded -= NavView_Loaded;
HomePageModule = new()
{
PageTitle = "Home",
PageName = "Home",
IsFooterItem = false,
PageIcon = "\uEA8A",
IconHeaderVisibility = Visibility.Visible,
PageType = typeof(HomePage)
};
SettingsPageModule = new()
{
PageTitle = "Settings",
PageName = "Settings",
IsFooterItem = true,
PageIcon = "\uE713",
IconHeaderVisibility = Visibility.Visible,
PageType = typeof(SettingsPage)
};
TestPageModule = new()
{
PageTitle = "Test page",
PageName = "Testing",
IsFooterItem = true,
PageIcon = "\uE716",
IconHeaderVisibility = Visibility.Visible,
PageType = typeof(TestPage)
};
HomePageModule.AttachToNavigationView(NavView);
SettingsPageModule.AttachToNavigationView(NavView, true);
TestPageModule.AttachToNavigationView(NavView, true);
// NavView doesn't load any page by default, so load home page.
NavView.SelectedItem = NavView.MenuItems[0];
// If navigation occurs on SelectionChanged, this isn't needed.
// Because we use ItemInvoked to navigate, we need to call Navigate
// here to load the home page.
HomePageModule.Navigate(ContentFrame);
// Listen to the window directly so the app responds
// to accelerator keys regardless of which element has focus.
Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += CoreDispatcher_AcceleratorKeyActivated;
Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed;
SystemNavigationManager.GetForCurrentView().BackRequested += System_BackRequested;
}
private void NavView_ItemInvoked(muxc.NavigationView sender, muxc.NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
SettingsPageModule.Navigate(ContentFrame, args.RecommendedNavigationTransitionInfo);
}
else if (args.InvokedItemContainer != null)
{
NavigationModule selectedModule = NavigationModule.FromNavigationItem(args.InvokedItemContainer as muxc.NavigationViewItem);
_ = selectedModule.Navigate(ContentFrame, args.RecommendedNavigationTransitionInfo);
SelectedModule = selectedModule;
}
}
private void NavView_BackRequested(muxc.NavigationView sender, muxc.NavigationViewBackRequestedEventArgs args) => TryGoBack();
private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs e)
{
// When Alt+Left are pressed navigate back
if (e.EventType == CoreAcceleratorKeyEventType.SystemKeyDown
&& e.VirtualKey == VirtualKey.Left
&& e.KeyStatus.IsMenuKeyDown == true
&& !e.Handled)
{
e.Handled = TryGoBack();
}
}
private void System_BackRequested(object sender, BackRequestedEventArgs e)
{
if (!e.Handled)
{
e.Handled = TryGoBack();
}
}
private void CoreWindow_PointerPressed(CoreWindow sender, PointerEventArgs e)
{
// Handle mouse back button.
if (e.CurrentPoint.Properties.IsXButton1Pressed)
{
e.Handled = TryGoBack();
}
}
private bool TryGoBack()
{
// 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 ContentFrame_NavigationFailed(object sender, Windows.UI.Xaml.Navigation.NavigationFailedEventArgs e)
{
throw new Exception("Failed to navigate.");
}
}
}
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
namespace ModuleNavigationSample.Modules
{
public class NavigationModule
{
public string PageTitle { get; set; }
public string PageName { get; set; }
public string PageIcon { get; set; }
public Visibility IconHeaderVisibility { get; set; }
public bool IsFooterItem { get; set; }
public Type PageType { get; set; }
public Microsoft.UI.Xaml.Controls.NavigationViewItem LinkedItem { get; set; }
public void AttachToNavigationView(Microsoft.UI.Xaml.Controls.NavigationView view, bool isFooter = false)
{
Microsoft.UI.Xaml.Controls.NavigationViewItem item = new()
{
Content = PageName,
Tag = (string.IsNullOrWhiteSpace(PageTitle) ? PageName : PageTitle, PageType, isFooter, IconHeaderVisibility),
Icon = new FontIcon()
{
Glyph = PageIcon
}
};
IsFooterItem = isFooter;
if (IsFooterItem)
{
view.FooterMenuItems.Add(item);
}
else view.MenuItems.Add(item);
LinkedItem = item;
}
public static NavigationModule FromNavigationItem(Microsoft.UI.Xaml.Controls.NavigationViewItem item)
{
(string, Type, bool, Visibility) pageInfo = ((string, Type, bool, Visibility))item.Tag;
return new()
{
PageTitle = pageInfo.Item1,
PageName = item.Content as string,
PageType = pageInfo.Item2,
PageIcon = (item.Icon as FontIcon).Glyph,
IconHeaderVisibility = pageInfo.Item4,
IsFooterItem = pageInfo.Item3
};
}
public bool Navigate(Frame frame, NavigationTransitionInfo info = null, object arg = null)
{
return frame?.Navigate(PageType, arg, info ?? new EntranceNavigationTransitionInfo()) ?? false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment