Windows 10 UWP,NavigationView 在 BackNavigation 上更新选定的 MenuItem
Windows 10 UWP, NavigationView Update Selected MenuItem on BackNavigation
我正在编写一个 windows 10 UWP 应用程序并希望结合使用 NavigationView 和 BackRequested
事件处理程序来处理返回导航,但是 "GoBack" 不会更新选定的菜单项,这意味着当我使用后退按钮时,选定的菜单项不会改变。为了解决这个问题,我创建了一个丑陋的 foreach 循环,它使用标签在后退导航中选择 MenuItem
。这行得通,但我想知道是否有更优雅的方法来做到这一点,
GoBack
不会触发 ItemInvoked
或 SelectionChanged
事件,所以我似乎无法使用它们。
MainPage.xaml
<NavigationView x:Name="NavView"
CompactModeThresholdWidth="1920" ExpandedModeThresholdWidth="1920"
ItemInvoked="NavView_ItemInvoked"
SelectionChanged="NavView_SelectionChanged"
Loaded="NavView_Loaded"
Canvas.ZIndex="0">
<NavigationView.MenuItems>
<NavigationViewItem x:Uid="HomeNavItem" Content="Home" Tag="home">
<NavigationViewItem.Icon>
<FontIcon Glyph=""/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItemSeparator/>
</NavigationView.MenuItems>
<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"/>
</Grid>
</DataTemplate>
</NavigationView.HeaderTemplate>
<Frame x:Name="ContentFrame" Margin="24">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition/>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
</NavigationView>
MainPage.xaml.cs 片段:
public MainPage()
{
this.InitializeComponent();
// initial page for ContentFrame
ContentFrame.Navigate(typeof(HomePage));
ContentFrame.Navigated += MainFrame_Navigated;
SystemNavigationManager.GetForCurrentView().BackRequested += MainPage_BackRequested;
}
private void MainPage_BackRequested(object sender, BackRequestedEventArgs e)
{
string tag = null;
if (!ContentFrame.CanGoBack) return;
e.Handled = true;
ContentFrame.GoBack();
if (ContentFrame.SourcePageType == typeof(HomePage))
{
tag = "home";
}
foreach (var navViewMenuItem in NavView.MenuItems)
{
if (navViewMenuItem is NavigationViewItem item)
{
if (item.Tag.Equals(tag)) item.IsSelected = true;
}
}
}
private void MainFrame_Navigated(object sender, NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = ((Frame) sender).CanGoBack
? AppViewBackButtonVisibility.Visible
: AppViewBackButtonVisibility.Collapsed;
}
NavigationView
菜单项本身可以执行其他操作,而不仅仅是导航,因此控件具有 "no reason" 来跟踪后退导航并相应地更新。但是,您可以设置 MenuItems
的标签并将其用于 ItemInvoked
导航和后退导航。
NavigationView
菜单项 XAML 将包含与目标页面类型名称完全匹配的 Tag
:
<NavigationView Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<NavigationView.MenuItems>
<NavigationViewItem Content="First" Tag="FirstPage">
<NavigationViewItem.Icon>
<FontIcon Glyph="1" FontFamily="Segoe UI"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Second" Tag="SecondPage">
<NavigationViewItem.Icon>
<FontIcon Glyph="2" FontFamily="Segoe UI"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
...
</NavigationView.MenuItems>
</NavigationView>
现在,在 MainFrame_Navigated
方法中,我们可以执行以下操作:
//get the Type of the currently displayed page
var pageName = AppFrame.Content.GetType().Name;
//find menu item that has the matching tag
var menuItem = AppNavigationView.MenuItems
.OfType<NavigationViewItem>()
.Where(item => item.Tag.ToString() == pageName)
.First();
//select
AppNavigationView.SelectedItem = menuItem;
您也可以对 ItemInvoked
处理程序使用类似的方法:
var invokedMenuItem = sender.MenuItems
.OfType<NavigationViewItem>()
.Where(item =>
item.Content.ToString() ==
args.InvokedItem.ToString())
.First();
var pageTypeName = invokedMenuItem.Tag.ToString();
var pageType = Assembly.GetExecutingAssembly().GetType($"{PageNamespace}.{pageTypeName}");
AppFrame.Navigate(pageType);
其中 PageNamespace
是一个字符串常量,带有存储 Pages
的命名空间的名称。您可以使用 nameof
使其安全地保持最新,例如:
private const string PageNamespace = nameof(MyApp.Pages);
我准备了一个演示这些建议的示例项目,您可以查看on my GitHub。
我正在编写一个 windows 10 UWP 应用程序并希望结合使用 NavigationView 和 BackRequested
事件处理程序来处理返回导航,但是 "GoBack" 不会更新选定的菜单项,这意味着当我使用后退按钮时,选定的菜单项不会改变。为了解决这个问题,我创建了一个丑陋的 foreach 循环,它使用标签在后退导航中选择 MenuItem
。这行得通,但我想知道是否有更优雅的方法来做到这一点,
GoBack
不会触发 ItemInvoked
或 SelectionChanged
事件,所以我似乎无法使用它们。
MainPage.xaml
<NavigationView x:Name="NavView"
CompactModeThresholdWidth="1920" ExpandedModeThresholdWidth="1920"
ItemInvoked="NavView_ItemInvoked"
SelectionChanged="NavView_SelectionChanged"
Loaded="NavView_Loaded"
Canvas.ZIndex="0">
<NavigationView.MenuItems>
<NavigationViewItem x:Uid="HomeNavItem" Content="Home" Tag="home">
<NavigationViewItem.Icon>
<FontIcon Glyph=""/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItemSeparator/>
</NavigationView.MenuItems>
<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"/>
</Grid>
</DataTemplate>
</NavigationView.HeaderTemplate>
<Frame x:Name="ContentFrame" Margin="24">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition/>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
</NavigationView>
MainPage.xaml.cs 片段:
public MainPage()
{
this.InitializeComponent();
// initial page for ContentFrame
ContentFrame.Navigate(typeof(HomePage));
ContentFrame.Navigated += MainFrame_Navigated;
SystemNavigationManager.GetForCurrentView().BackRequested += MainPage_BackRequested;
}
private void MainPage_BackRequested(object sender, BackRequestedEventArgs e)
{
string tag = null;
if (!ContentFrame.CanGoBack) return;
e.Handled = true;
ContentFrame.GoBack();
if (ContentFrame.SourcePageType == typeof(HomePage))
{
tag = "home";
}
foreach (var navViewMenuItem in NavView.MenuItems)
{
if (navViewMenuItem is NavigationViewItem item)
{
if (item.Tag.Equals(tag)) item.IsSelected = true;
}
}
}
private void MainFrame_Navigated(object sender, NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = ((Frame) sender).CanGoBack
? AppViewBackButtonVisibility.Visible
: AppViewBackButtonVisibility.Collapsed;
}
NavigationView
菜单项本身可以执行其他操作,而不仅仅是导航,因此控件具有 "no reason" 来跟踪后退导航并相应地更新。但是,您可以设置 MenuItems
的标签并将其用于 ItemInvoked
导航和后退导航。
NavigationView
菜单项 XAML 将包含与目标页面类型名称完全匹配的 Tag
:
<NavigationView Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<NavigationView.MenuItems>
<NavigationViewItem Content="First" Tag="FirstPage">
<NavigationViewItem.Icon>
<FontIcon Glyph="1" FontFamily="Segoe UI"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Second" Tag="SecondPage">
<NavigationViewItem.Icon>
<FontIcon Glyph="2" FontFamily="Segoe UI"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
...
</NavigationView.MenuItems>
</NavigationView>
现在,在 MainFrame_Navigated
方法中,我们可以执行以下操作:
//get the Type of the currently displayed page
var pageName = AppFrame.Content.GetType().Name;
//find menu item that has the matching tag
var menuItem = AppNavigationView.MenuItems
.OfType<NavigationViewItem>()
.Where(item => item.Tag.ToString() == pageName)
.First();
//select
AppNavigationView.SelectedItem = menuItem;
您也可以对 ItemInvoked
处理程序使用类似的方法:
var invokedMenuItem = sender.MenuItems
.OfType<NavigationViewItem>()
.Where(item =>
item.Content.ToString() ==
args.InvokedItem.ToString())
.First();
var pageTypeName = invokedMenuItem.Tag.ToString();
var pageType = Assembly.GetExecutingAssembly().GetType($"{PageNamespace}.{pageTypeName}");
AppFrame.Navigate(pageType);
其中 PageNamespace
是一个字符串常量,带有存储 Pages
的命名空间的名称。您可以使用 nameof
使其安全地保持最新,例如:
private const string PageNamespace = nameof(MyApp.Pages);
我准备了一个演示这些建议的示例项目,您可以查看on my GitHub。