The following forum(s) have migrated to Microsoft Q&A (Preview): Developing Universal Windows apps!
Visit Microsoft Q&A (Preview) to post new questions.

Learn More

 locked
[UWP][C#] NavigationView Code Example Infinite Loop? RRS feed

  • Question

  • Hi,

    I'm relatively new to c# and uwp in general. I'm trying to build the code example from the microsoft docs navigationview#code-example

    This is my HomePage.xaml

    <Page
        x:Class="AdminTools.HomePage"
        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"
        xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    
        <Grid>
            <muxc:NavigationView x:Name="NavView"
                             Loaded="NavView_Loaded"
                             ItemInvoked="NavView_ItemInvoked"
                             BackRequested="NavView_BackRequested">
                <muxc:NavigationView.MenuItems>
                    <muxc:NavigationViewItem Tag="home" Icon="Home" Content="Home"/>
                    <muxc:NavigationViewItemSeparator/>
                    <muxc:NavigationViewItemHeader x:Name="MainPagesHeader"
                                               Content="Main pages"/>
                    <muxc:NavigationViewItem Tag="apps" Content="Apps">
                        <muxc:NavigationViewItem.Icon>
                            <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEB3C;"/>
                        </muxc:NavigationViewItem.Icon>
                    </muxc:NavigationViewItem>
                    <muxc:NavigationViewItem Tag="games" Content="Games">
                        <muxc:NavigationViewItem.Icon>
                            <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE7FC;"/>
                        </muxc:NavigationViewItem.Icon>
                    </muxc:NavigationViewItem>
                    <muxc:NavigationViewItem Tag="music" Icon="Audio" Content="Music"/>
                </muxc:NavigationView.MenuItems>
    
                <muxc:NavigationView.AutoSuggestBox>
                    <!-- See AutoSuggestBox documentation for
                     more info about how to implement search. -->
                    <AutoSuggestBox x:Name="NavViewSearchBox" QueryIcon="Find"/>
                </muxc:NavigationView.AutoSuggestBox>
    
                <ScrollViewer>
                    <Frame x:Name="ContentFrame" Padding="12,0,12,24" IsTabStop="True"
                       NavigationFailed="ContentFrame_NavigationFailed"/>
                </ScrollViewer>
            </muxc:NavigationView>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup>
                    <VisualState>
                        <VisualState.StateTriggers>
                            <AdaptiveTrigger
                            MinWindowWidth="{x:Bind NavView.CompactModeThresholdWidth}"/>
                        </VisualState.StateTriggers>
                        <VisualState.Setters>
                            <!-- Leave the next line for left-only navigation. -->
                            <Setter Target="ContentFrame.Padding" Value="24,0,24,24"/>
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Grid>
    </Page>

    And here is my HomePage.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices.WindowsRuntime;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.System;
    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.Media.Animation;
    using Windows.UI.Xaml.Navigation;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
    
    namespace AdminTools
    {
        using muxc = Microsoft.UI.Xaml.Controls;
        /// <summary>
        /// An empty page that can be used on its own or navigated to within a Frame.
        /// </summary>
        public sealed partial class HomePage : Page
        {
            public HomePage()
            {
                this.InitializeComponent();
            }
    
            private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
            {
                throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
            }
    
            // List of ValueTuple holding the Navigation Tag and the relative Navigation Page
            private readonly List<(string Tag, Type Page)> _pages = new List<(string Tag, Type Page)>
    {
        ("home", typeof(HomePage)),
        ("apps", typeof(WebDevPage)),
        ("games", typeof(RDPPage)),
        ("music", typeof(ChatPage)),
    };
    
            private void NavView_Loaded(object sender, RoutedEventArgs e)
            {
    
                // Add handler for ContentFrame navigation.
                ContentFrame.Navigated += On_Navigated;
    
                // 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.
                NavView_Navigate("home", new EntranceNavigationTransitionInfo());
    
                // Add keyboard accelerators for backwards navigation.
                var goBack = new KeyboardAccelerator { Key = VirtualKey.GoBack };
                goBack.Invoked += BackInvoked;
                this.KeyboardAccelerators.Add(goBack);
    
                // ALT routes here
                var altLeft = new KeyboardAccelerator
                {
                    Key = VirtualKey.Left,
                    Modifiers = VirtualKeyModifiers.Menu
                };
                altLeft.Invoked += BackInvoked;
                this.KeyboardAccelerators.Add(altLeft);
            }
    
            private void NavView_ItemInvoked(muxc.NavigationView sender,
                                             muxc.NavigationViewItemInvokedEventArgs args)
            {
                if (args.IsSettingsInvoked == true)
                {
                    NavView_Navigate("settings", args.RecommendedNavigationTransitionInfo);
                }
                else if (args.InvokedItemContainer != null)
                {
                    var navItemTag = args.InvokedItemContainer.Tag.ToString();
                    NavView_Navigate(navItemTag, args.RecommendedNavigationTransitionInfo);
                }
            }
    
            private void NavView_Navigate(string navItemTag, NavigationTransitionInfo transitionInfo)
            {
                Type _page = null;
                if (navItemTag == "settings")
                {
                    _page = typeof(SettingsPage);
                }
                else
                {
                    var item = _pages.FirstOrDefault(p => p.Tag.Equals(navItemTag));
                    _page = item.Page;
                }
                // Get the page type before navigation so you can prevent duplicate
                // entries in the backstack.
                var preNavPageType = ContentFrame.CurrentSourcePageType;
    
                // Only navigate if the selected page isn't currently loaded.
                if (!(_page is null) && !Type.Equals(preNavPageType, _page))
                {
                    ContentFrame.Navigate(_page, null, transitionInfo);
                }
            }
    
            private void NavView_BackRequested(muxc.NavigationView sender,
                                               muxc.NavigationViewBackRequestedEventArgs args)
            {
                On_BackRequested();
            }
    
            private void BackInvoked(KeyboardAccelerator sender,
                                     KeyboardAcceleratorInvokedEventArgs args)
            {
                On_BackRequested();
                args.Handled = true;
            }
    
            private bool On_BackRequested()
            {
                if (!ContentFrame.CanGoBack)
                    return false;
    
                ContentFrame.GoBack();
                return true;
            }
    
            private void On_Navigated(object sender, NavigationEventArgs e)
            {
                NavView.IsBackEnabled = ContentFrame.CanGoBack;
    
                if (ContentFrame.SourcePageType == typeof(SettingsPage))
                {
                    // SettingsItem is not part of NavView.MenuItems, and doesn't have a Tag.
                    NavView.SelectedItem = (muxc.NavigationViewItem)NavView.SettingsItem;
                    NavView.Header = "Settings";
                }
                else if (ContentFrame.SourcePageType != null)
                {
                    var item = _pages.FirstOrDefault(p => p.Page == e.SourcePageType);
    
                    NavView.SelectedItem = NavView.MenuItems
                        .OfType<muxc.NavigationViewItem>()
                        .FirstOrDefault(n => n.Tag.Equals(item.Tag));
    
                    NavView.Header =
                        ((muxc.NavigationViewItem)NavView.SelectedItem)?.Content?.ToString();
                }
            }
        }
    }

    It compiles successfully but the debugger crashes because the app is producing navigationview menus in a loop. Anyone know why?

    Regards,

    Michael



    • Edited by Michael.KSmith Tuesday, May 21, 2019 2:07 PM added [C#] to subject
    Tuesday, May 21, 2019 2:06 PM

Answers

  • Hi,

    I have a question here, what's the OS version of your device? And also what's the target version of your app?

    I could reproduce your problem here. The problem is that you are calling this method of code in  NavView_Loaded event. 

     NavView_Navigate("home", new EntranceNavigationTransitionInfo());

    In the NavView_Navigate, the frame in the scrollviewer will continue to navigate to Home page in the frame. In this line of code:

     if (!(_page is null) && !Type.Equals(preNavPageType, _page))
                    {
                        ContentFrame.Navigate(_page, null, transitionInfo);
                    }

    Because at the beginning, the preNavPageType will always be null so homepage is always different with it. So when the new home page is loaded in the frame, it will call the NavView_Loaded event again and the loop will last until the crash happens.

    My suggestion is to make a bool flag before you navigate, the flag will indicate if it is the first time to load home page before you navigate. Then check it like this:

     //if isfirst is ture, it means this is the first time. If not, then please go ahead
                    if (!(_page is null) && !Type.Equals(preNavPageType, _page)&&!isfirst)
                    {
                        ContentFrame.Navigate(_page, null, transitionInfo);
                    }


    Best regards,

    Roy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, May 22, 2019 3:09 AM
    Moderator

All replies

  • Hi,

    I have a question here, what's the OS version of your device? And also what's the target version of your app?

    I could reproduce your problem here. The problem is that you are calling this method of code in  NavView_Loaded event. 

     NavView_Navigate("home", new EntranceNavigationTransitionInfo());

    In the NavView_Navigate, the frame in the scrollviewer will continue to navigate to Home page in the frame. In this line of code:

     if (!(_page is null) && !Type.Equals(preNavPageType, _page))
                    {
                        ContentFrame.Navigate(_page, null, transitionInfo);
                    }

    Because at the beginning, the preNavPageType will always be null so homepage is always different with it. So when the new home page is loaded in the frame, it will call the NavView_Loaded event again and the loop will last until the crash happens.

    My suggestion is to make a bool flag before you navigate, the flag will indicate if it is the first time to load home page before you navigate. Then check it like this:

     //if isfirst is ture, it means this is the first time. If not, then please go ahead
                    if (!(_page is null) && !Type.Equals(preNavPageType, _page)&&!isfirst)
                    {
                        ContentFrame.Navigate(_page, null, transitionInfo);
                    }


    Best regards,

    Roy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, May 22, 2019 3:09 AM
    Moderator
  • Hi,

    I have a question here, what's the OS version of your device? And also what's the target version of your app?

    I could reproduce your problem here. The problem is that you are calling this method of code in  NavView_Loaded event. 

     NavView_Navigate("home", new EntranceNavigationTransitionInfo());

    In the NavView_Navigate, the frame in the scrollviewer will continue to navigate to Home page in the frame. In this line of code:

     if (!(_page is null) && !Type.Equals(preNavPageType, _page))
                    {
                        ContentFrame.Navigate(_page, null, transitionInfo);
                    }

    Because at the beginning, the preNavPageType will always be null so homepage is always different with it. So when the new home page is loaded in the frame, it will call the NavView_Loaded event again and the loop will last until the crash happens.

    My suggestion is to make a bool flag before you navigate, the flag will indicate if it is the first time to load home page before you navigate. Then check it like this:

     //if isfirst is ture, it means this is the first time. If not, then please go ahead
                    if (!(_page is null) && !Type.Equals(preNavPageType, _page)&&!isfirst)
                    {
                        ContentFrame.Navigate(_page, null, transitionInfo);
                    }


    Best regards,

    Roy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact.

    Hi Roy,

    it's working now, thank you :)

    The os version of my device is 17763.503 (Windows 10 Pro 1809) and the target version (as well as the min version) of my app is Windows 10, version 1809 (10.0; Build 17763)

    Best regards,

    Michael

    Wednesday, May 22, 2019 8:56 AM