简体   繁体   English

Windows 10 UWP,NavigationView在BackNavigation上更新选定的MenuItem

[英]Windows 10 UWP, NavigationView Update Selected MenuItem on BackNavigation

I am writing an windows 10 UWP app and want to use the NavigationView in combination with the BackRequested event handler to handle back navigation, however "GoBack" doesn't update the selected menu item, this means when I use the backbutton the selected menu item doesn't change. 我正在编写一个Windows 10 UWP应用程序,并希望将NavigationView与BackRequested事件处理程序结合使用来处理后退导航,但是“GoBack”不会更新所选菜单项,这意味着当我使用后退BackRequested时所选择的菜单项不会改变。 to fix this I have created an ugly foreach loop that selects the MenuItem on back navigation using a tag. 为了解决这个问题,我创建了一个丑陋的foreach循环,使用标记在后面导航中选择MenuItem This works but I was wondering if there is a more elegant way to do this, GoBack doesn't fire the ItemInvoked or SelectionChanged event so I can't seem to be able to use those. 这有效,但我想知道是否有更优雅的方法来做到这一点, GoBack不会触发ItemInvokedSelectionChanged事件,所以我似乎无法使用它们。

MainPage.xaml 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="&#xE10F;"/>
            </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 snippet: 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;
    }

The NavigationView menu items themselves could do other action than just navigation, hence the control has "no reason" to track the back navigation and update accordingly. NavigationView菜单项本身可以执行除导航之外的其他操作,因此控件“没有理由”跟踪后退导航并相应地更新。 What you can do however to set the tag of your MenuItems and use it for both ItemInvoked navigation and for back navigation. 但是,您可以设置MenuItems的标记,并将其用于ItemInvoked导航和后退导航。

NavigationView menu items XAML would include a Tag that exactly matches the target page type name: 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>

Now within the MainFrame_Navigated method we can do the following: 现在,在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;

You can also use similar approach for ItemInvoked handler: 您还可以对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);

Where PageNamespace is a string constant with the name of the namespace where your Pages are stored. 其中PageNamespace是一个字符串常量,其中包含存储Pages的命名空间的名称。 You can use nameof to keep it up to date safely, for example: 您可以使用nameof安全地更新它,例如:

private const string PageNamespace = nameof(MyApp.Pages);

I have prepared a sample project that demonstrates these suggestions, you can check it out on my GitHub . 我准备了一个演示这些建议的示例项目,您可以在我的GitHub上查看。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM