XAML Fundamentals for Web & Mobile: Building a Data Bound Menu

WinUI contains classes for menus belonging to a Window and context menus attached to other controls. Users will be familiar with menus in traditional desktop applications and mobile devices. Unlike previous Windows APIs, the WinUI MenuBar and MenuBarItem do not support data binding, so you must build your menu tree from MenuFlyoutItem, MenuFlyoutSubItem, and MenuFlyoutSeparator, either in code or directly in your XAML. 

The two types of items cover all the menu scenarios since the MenuFlyoutSubItem can contain additional menu items. A static menu might look something like this:

				
					<MenuBar> 
        <MenuBarItem Title="File"> 
                <MenuFlyoutItem Text="New"/>
                <MenuFlyoutItem Text="Open..."/> 
                <MenuFlyoutItem Text="Save"/> 
                <MenuFlyoutItem Text="Exit"/> 
        </MenuBarItem> 
</MenuBar> 
				
			

Data-Bindings Menu

Sometimes, you may want to populate a menu dynamically from a data source rather than hard-coding them. In this case, there is a little more work to achieve the desired results. There are a couple of ways you could present a grouped collection in a menu – you could choose to display each group using a MenuFlyoutSubItem and have the items nested below this.  

While technically, you can continue to nest multiple levels with the MenuFlyoutSubItem, in practice, more than two layers become challenging to navigate, especially on smaller screens. Given a single-level grouped collection, you can write code like the following to populate a top-level MenuBarItem from the groups:

				
					var groupedBirds = Birds.GroupBy(x => x.Family); 

foreach (var group in groupedBirds) 
{ 
    var menuGroup = new MenuFlyoutSubItem() { Text = group.Key }; 
    GroupedMenu.Items.Add(menuGroup); 

    foreach (var bird in group) 
    { 
        var item = new MenuFlyoutItem() { Text = bird.CommonName }; 
        item.DataContext = bird; 
        menuGroup.Items.Add(item); 
    } 
} 
				
			



This produces a menu which looks like this on Android and Windows, respectively:

Figure 1. Nested Menus on Android
Figure 2. Nested Menus on Windows 11

Separating Groups of Menu Items

The code above works but adds some unnecessary noise to the menu (especially when the groups themselves are not actionable and there are not too many items in total). Instead, we can modify this code to display all the items at the same level but with separators between the groups. 

				
					var groupedBirds = Birds.GroupBy(x => x.Family);
var template = Resources["MenuItemTemplate"] as DataTemplate;

foreach (var group in groupedBirds)
{
    foreach (var bird in group)
    {
        var item = template.LoadContent() as MenuFlyoutItem;
        item.DataContext = bird;
        SeparatedMenu.Items.Add(item);
    }
    // add separator after last item in group
    SeparatedMenu.Items.Add(new MenuFlyoutSeparator());
}

if (SeparatedMenu.Items.Count > 0)
{
    // remove trailing separator (if items added)
    SeparatedMenu.Items.RemoveAt(SeparatedMenu.Items.Count - 1);
}

				
			

Adding the original bird item as the DataContext of the menuFlyoutItem allows us to get the items when responding to a menu selection. The other reason is to use a template populated from the data item. 

Define the Appearance with a DataTemplate

It’s perfectly possible to fully create the menu items from code. However, if you want to make minor changes to the appearance at a later stage, you have to dig into the code. In the example above, we added a custom Icon to the menu items, and we may decide in the future to change this. A solution to provide clearer separation is to create a DataTemplate in XAML, which defines the appearance of the MenuFlyoutItem given the specific data-bound item. For our bird example, we’ve used the following named template, which we can refer to from the code when creating new menu items there are not too many items in total). Instead, we can modify this code to display all the items at the same level but with separators between the groups. 

				
					<DataTemplate x:Key="MenuItemTemplate">
    <MenuFlyoutItem Text="{Binding CommonName}">
        <MenuFlyoutItem.Icon>
            <FontIcon Glyph="&#x0001F426;"/>
        </MenuFlyoutItem.Icon>
    </MenuFlyoutItem>
</DataTemplate>

				
			

While the MenuFlyoutItem doesn’t contain a lot of visual customization, it may change in the future, and the template could be adapted accordingly. The separated groups rendered with a template defining a custom item look like this on Android and Windows devices:

Figure 3. Separated Menus on Android
Figure 4. Separated Menus on Wiondows 11
About Uno Platform

For those new to Uno Platform – it allows for creation of pixel-perfect, single-source C# and XAML apps which run natively on Windows, iOS, Android, macOS, Linux and Web via WebAssembly. It offers Figma integration for design-development handoff, and a set of extensions to bootstrap your projects. Uno Platform is free and Open Source (Apache 2.0) and available on GitHub.

Next Steps

You can view the full class details of MenuBarItem and related classes in the WinUI documentation. All of the MenuBar/MenuFlyout classes are supported in Uno 4.6. 

We’ve made the code sample available here. Explore our samples and discover how you can Get Started with Uno Platform to build your desktop, mobile, and web apps. 

Tags:

Share this post:
Tune in Today at 12 PM EST for our free Uno Platform 5.0 Live Webinar
Watch Here