【问题标题】:Windows 10 UWP, NavigationView Update Selected MenuItem on BackNavigationWindows 10 UWP,NavigationView 更新 BackNavigation 上的选定菜单项
【发布时间】:2018-06-29 21:54:47
【问题描述】:

我正在编写一个 Windows 10 UWP 应用程序,并希望结合使用 NavigationView 和 BackRequested 事件处理程序来处理返回导航,但是“GoBack”不会更新选定的菜单项,这意味着当我使用backbutton 选定的菜单项不会改变。为了解决这个问题,我创建了一个丑陋的 foreach 循环,它使用标签在后退导航中选择 MenuItem。这可行,但我想知道是否有更优雅的方式来做到这一点, GoBack 不会触发 ItemInvokedSelectionChanged 事件,所以我似乎无法使用它们。

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 sn-p:

        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;
    }

【问题讨论】:

    标签: c# xaml uwp navigationview


    【解决方案1】:

    NavigationView 菜单项本身可以执行除导航之外的其他操作,因此控件“没有理由”跟踪返回导航并相应地更新。但是,您可以设置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

    【讨论】:

    • 很好的答案!谢谢你。如果他在不同文件夹下有页面,则需要小心处理 {PageNamespace}.{pageTypeName}。我在标签中包含文件夹名称(例如 ViewGroup1.Page1、ViewGroup2.Page1...)并在它们前面加上应用程序的命名空间以获取类型。
    • 很棒的答案,尤其是编写整个示例应用程序的麻烦。不过,对于任何使用 GitHub 应用程序的人来说,请记住将代码添加到 NavigationView_ItemInvoked 方法以处理单击/点击后的 NavigationVeiw 设置按钮。您可以将当前存在的代码包含在 if(args.IsSettingsInvoked) { //Handle settings click }else { //Place existing github code here } 的 else 块中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 2016-10-06
    • 2015-11-07
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    • 2018-10-19
    相关资源
    最近更新 更多