UWP XAML dynamically add Navigation View items using a menu selection

Douglas Harris 40 Reputation points
2023-05-11T19:01:29.34+00:00

Looking into creating a way to dynamically add navigation view items either using a page with drop downs or flyout menu and didn't know if it would be possible or should I look at using tree view vs navigation view.

Menu

Universal Windows Platform (UWP)
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,006 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
814 questions
0 comments No comments
{count} votes

Accepted answer
  1. Junjie Zhu - MSFT 18,476 Reputation points Microsoft Vendor
    2023-05-12T06:15:07.74+00:00

    Hi @Douglas Harris Welcome to Microsoft Q&A!

    You can dynamically add Navigation View items using NavigationView.MenuItems.

    Here is a minimal sample written according to your needs, you can refer to it.

    The NavigationView used in the sample is a WinUI control, you need to install the latest version Microsoft.UI.Xaml in the NuGet Package Manager.

    MainPage.xaml

    // xmlns:muxc="using:Microsoft.UI.Xaml.Controls"    
    <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="9*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
            <muxc:NavigationView Grid.Column="0" x:Name="NavigationViewControl" ItemInvoked="NavigationViewControl_ItemInvoked_1">
                <muxc:NavigationView.MenuItems>
                    <muxc:NavigationViewItem  Icon="Home" Content="Home"/>
                    <muxc:NavigationViewItemSeparator/>
                    <muxc:NavigationViewItem  Icon="Keyboard" Content="Main Item">
                        <muxc:NavigationViewItem.MenuItems>
                            <muxc:NavigationViewItem Content="Item"/>
                            <muxc:NavigationViewItem Content="Sub Item"/>
    
                        </muxc:NavigationViewItem.MenuItems>
                    </muxc:NavigationViewItem>
                </muxc:NavigationView.MenuItems>
            </muxc:NavigationView>
    
            <StackPanel x:Name="SettingPanel" Background="HotPink"  Grid.Column="1" Orientation="Vertical" Visibility="Collapsed">
                <Button Click="Button_Click">AddSubItem</Button>
            </StackPanel>
      
        </Grid>
    

    MainPage.xaml.cs

    // using MUXC = Microsoft.UI.Xaml.Controls;
    private void NavigationViewControl_ItemInvoked_1(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args)
    {
        if (args.IsSettingsInvoked)
        {
            if (SettingPanel.Visibility == Visibility.Collapsed) 
            {
                SettingPanel.Visibility = Visibility.Visible;
            }
            else
            {
                SettingPanel.Visibility = Visibility.Collapsed;
            }
        }
    }
    
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MUXC.NavigationViewItem newSubItem = new MUXC.NavigationViewItem();
        newSubItem.Content = "newSubItem";
                
        foreach (var item  in NavigationViewControl.MenuItems)
        {
            var menuItem = item as MUXC.NavigationViewItem;
            var selectItem = NavigationViewControl.SelectedItem as MUXC.NavigationViewItem;
            //find selectedItem
            if (menuItem!=null &&
                selectItem!=null &&
                menuItem.Content.ToString() == selectItem.Content.ToString()) 
            {
                menuItem.MenuItems.Add(newSubItem);
            }
        }
                    
    }
    

    Click the Setting button, AddSubItem Button will show on the right. Then select the MenuItem which you want to add sub-items and click AddSubItem Button.

    Thank you,

    Junjie


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


1 additional answer

Sort by: Most helpful
  1. Junjie Zhu - MSFT 18,476 Reputation points Microsoft Vendor
    2023-05-15T08:39:45.9733333+00:00

    Hi @Douglas Harris In the following example, it use Frame.Navigate to send the navigationView object to SettingPage, and use FrameworkElement.Tag to save the URL in SubItem, and finally use Frame.Navigate again to send the URL to WebviewPage.

    MainPage.xaml

    <!--xmlns:muxc="using:Microsoft.UI.Xaml.Controls"-->
    <Grid>
        <muxc:NavigationView  x:Name="NavigationViewControl" ItemInvoked="NavigationViewControl_ItemInvoked_1" >
            <muxc:NavigationView.MenuItems>
                <muxc:NavigationViewItem  Icon="Home" Content="Home"/>
                <muxc:NavigationViewItemSeparator/>
                <muxc:NavigationViewItem  Icon="Keyboard" Content="Main Item">
                    <muxc:NavigationViewItem.MenuItems>
                        <muxc:NavigationViewItem Content="Item"/>
                        <muxc:NavigationViewItem Content="Sub Item"/>
    
                    </muxc:NavigationViewItem.MenuItems>
                </muxc:NavigationViewItem>
            </muxc:NavigationView.MenuItems>
            <ScrollViewer>
                <Frame x:Name="ContentFrame"/>
            </ScrollViewer>
        </muxc:NavigationView>
    
    </Grid>
    

    MainPage.xaml.cs

    private void NavigationViewControl_ItemInvoked_1(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args)
    {
        if (args.IsSettingsInvoked)
        {
            ContentFrame.Navigate(typeof(SettingPage), sender);
        }
        else if (args.InvokedItem.ToString() == "C#" || args.InvokedItem.ToString() == "XAML")
        {             
            var selectItem = NavigationViewControl.SelectedItem as MUXC.NavigationViewItem;
            var strURL = selectItem.Tag.ToString();
                   
            ContentFrame.Navigate(typeof(WebView2Page), strURL);
        }
               
    }
    
    
    

    SettingPage.xaml

    <Grid x:Name="SettingGrid" Background="HotPink" >
        <ComboBox x:Name="CB1" Header="Main Menu"  PlaceholderText="Location Settings" Width="314" Margin="50,109,0,0">
        </ComboBox>
    
        <ComboBox x:Name="CB2"  Header="Item" PlaceholderText="Pick a Item" Width="314" Margin="50,195,0,0">
            <x:String>Coding</x:String>
            <x:String>Github</x:String>
        </ComboBox>
    
        <ComboBox x:Name="CB3"  Header="Sub-Item" PlaceholderText="Pick a Product" Width="314" Margin="50,283,0,0">
            <x:String>C#</x:String>
            <x:String>XAML</x:String>
        </ComboBox>
    
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Margin="48,384,0,0" TextWrapping="Wrap" PlaceholderText="Type in site Url here" VerticalAlignment="Top" Width="1046"/>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="50,365,0,0" TextWrapping="Wrap" Text="Site Url" VerticalAlignment="Top" />
        <Button x:Name="button" Content="Create" Margin="50,455,0,0" VerticalAlignment="Top" Click="button_Click" />
    </Grid>
    
    

    SettingPage.xaml.cs

    List<string> Cb1List= new List<string>();
    MUXC.NavigationView navigationView = null;
    int NewItemCount= 0;
           
    public SettingPage()
    {
        this.InitializeComponent();
                
    }
    
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    
        base.OnNavigatedTo(e);
    
        navigationView = e.Parameter as MUXC.NavigationView;
    
        if (navigationView != null)
        {
            Cb1List.Clear();
    
            foreach (var item in navigationView.MenuItems)
            {
                var menuItem = item as MUXC.NavigationViewItem;
                if (menuItem != null)
                {
                    Cb1List.Add(menuItem.Content.ToString());
                }
            }
            Cb1List.Add("New Location");
        }
    
        CB1.ItemsSource = Cb1List;
    }
    
    private void button_Click(object sender, RoutedEventArgs e)
    {
        if (navigationView == null) return;
    
        if (CB1.SelectionBoxItem==null || CB2.SelectionBoxItem== null || CB3.SelectionBoxItem == null || textBox.Text == null)
        {
            Debug.WriteLine("invalid value");
            return;
        }
    
        string strMenuItem = CB1.SelectionBoxItem.ToString();
        string strItem     = CB2.SelectionBoxItem.ToString();
        string strSubItem  = CB3.SelectionBoxItem.ToString();
        string strURL      = textBox.Text.ToString();
    
        MUXC.NavigationViewItem newItem = new MUXC.NavigationViewItem();
        newItem.Content = strItem;
        //define the newSubItem Tag
        MUXC.NavigationViewItem newSubItem = new MUXC.NavigationViewItem();
        newSubItem.Content = strSubItem;
    
        try
        {
            Uri targetUri = new Uri(strURL); 
            newSubItem.Tag = strURL;
        }
        catch (Exception)
        {
            Debug.WriteLine("invalid URL");
        }
    
                
        if (strMenuItem== "New Location")
        {
            //Add new menuItems
            NewItemCount++;
            strMenuItem = strMenuItem + "_" + NewItemCount.ToString(); //New Location_x
            MUXC.NavigationViewItem newMenuItem = new MUXC.NavigationViewItem();
            newMenuItem.Content = strMenuItem ;
    
            navigationView.MenuItems.Add(newMenuItem);
    
            foreach (var item in navigationView.MenuItems)
            {
                       
                var menuItem = item as MUXC.NavigationViewItem;
                //find selectedItem
                if (menuItem != null && menuItem.Content.ToString()== strMenuItem)
                {
                    menuItem.MenuItems.Add(newItem);
                    newItem.MenuItems.Add(newSubItem);
                    break;
                }
            }
        }
        else
        {
            //Add new Items in selected Item
            foreach (var item in navigationView.MenuItems)
            {
                var menuItem = item as MUXC.NavigationViewItem;
                //find selectedItem
                if (menuItem != null && menuItem.Content.ToString() == strMenuItem)
                {
                    menuItem.MenuItems.Add(newItem);
                    newItem.MenuItems.Add(newSubItem);
                    break;
                }
            }
        }
    
                
    
    }
    
    

    WebView2Page.xaml

    
    <Grid>
            <muxc:WebView2 x:Name="webview2"></muxc:WebView2>
        </Grid>
    
    

    WebView2Page.xaml.cs

    public WebView2Page()
    {
        this.InitializeComponent();
    }
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
    
        var strURL = e.Parameter as string;
    
        try
        {
            Uri targetUri = new Uri(strURL);              
            webview2.Source = targetUri;
        }
        catch (Exception)
        {
            Debug.WriteLine("invalid URL");
        }
               
    }
    
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.