Search code examples
data-bindinguwpwindows-10uwp-xamlwinui

UWP: NavigationView.MenuItems results empty if populated programmatically


I created a new UWP project with a NavigationView (winui 2.4) in MainPage.xaml.

I proceeded by binding a hierarchical ObservableCollection to populate the NavigationView menu items (1 parent, 4 children)

Launching the application, the hierarchical structure renders as expected, and seem to be working fine.

NavigationView hierarchy renders correctly

My next objective would be to collapse every expanded menu item clicking on a button. To do so, the docs suggest using NavigationView.Collapse(NavigationViewItem): my intention would be to iterate through NavigationView.MenuItems and collapse them.

The issue is that it seems NavigationView.MenuItems returns empty and I cannot figure out why. I included a Button that prints NavigationView.MenuItems.Count(), which returns 0.

On the other hand, hard-coding the hierarchical menu items and repeating said procedure seem to work fine.

MainPage.xaml

<Grid>
    <muxc:NavigationView x:Name="MainNavigation" MenuItemsSource="{x:Bind categories, Mode=OneWay}">
        <muxc:NavigationView.MenuItemTemplate>
            <DataTemplate x:DataType="data:Category" >
                <muxc:NavigationViewItem Content="{x:Bind Name}" MenuItemsSource="{x:Bind Children}" />
            </DataTemplate>
        </muxc:NavigationView.MenuItemTemplate>
        <Button Content="Do Something" Click="Button_Click" />
    </muxc:NavigationView>
</Grid>

MainPage.xaml.cs

public sealed partial class MainPage : Page
    {
        ObservableCollection<Category> categories = new ObservableCollection<Category>();
        public MainPage()
        {
            this.InitializeComponent();

            categories = PopulateHierarchy();
        }

        private ObservableCollection<Category> PopulateHierarchy()
        {
            ObservableCollection<Category> list = new ObservableCollection<Category>();
            ObservableCollection<Category> children = new ObservableCollection<Category>();

            children.Add(new Category { Name = "Child 1" });
            children.Add(new Category { Name = "Child 2" });
            children.Add(new Category { Name = "Child 3" });
            children.Add(new Category { Name = "Child 4" });

            list.Add(new Category { Name = "Test1", Children=children });


            return list;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            int itemsCount = MainNavigation.MenuItems.Count();
            Debug.WriteLine(itemsCount);
        }
    }

Category.cs

public class Category
{
    public string Name { get; set; }
    public ObservableCollection<Category> Children { get; set; }
}

Edit: it seems like this is a known bug, I found a closed issue on GitHub but the problem persists.


Solution

  • UWP: NavigationView.MenuItems results empty if populated programmatically

    I can reproduce your problem that MenuItems.Count is zero. As your provide link said, you could also get the items with MenuItemsSource property.

    The parameter of Collapse method is NavigationViewItem, and we could not pass MenuItems element (data source type) into it directly. We need use the data source to find the matched NavigationViewItem, the ContainerFromMenuItem method is right choice for getting NavigationViewItem with data source. And then MenuItems is not necessary for this scenario. Because categories has been decaled previously. we could use it directly. So the code could be written like below.

    private void Button_Click(object sender, RoutedEventArgs e)
    {    
        var container = MainNavigation.ContainerFromMenuItem(categories.First()) as Microsoft.UI.Xaml.Controls.NavigationViewItem;
        MainNavigation.Collapse(container);    
    }