.NET MAUI - Creating a XAML File Menu

·

4 min read

Introduction

In this article, I'm going to add a file menu to my .NET MAUI PDF Splitter application.

If you're following my PDF Splitter Application series, you will have a simple application based on the out-the-box .NET template which we will now start to build upon.

If not you can jump to the final code for the series here.

The Menu Bar

We are going to add a simple menu bar to our application, which has two top-level items (File and About) and some sub-items as outlined below:

  • File

    • Open

    • Close

    • [Separator]

    • Exit

  • About

    • About

To add these to our UI we can simply update our AppShell.xaml as follows:

<Shell.MenuBarItems>
        <MenuBarItem Text="File">
            <MenuFlyoutItem Text="Open" Command="{Binding OnMenuItemClickedCommand}" CommandParameter="Open" />
            <MenuFlyoutItem Text="Close" Command="{Binding OnMenuItemClosePdfClickedCommand}" CommandParameter="Close" />
            <MenuFlyoutSeparator />
            <MenuFlyoutItem Text="Exit" Command="{Binding OnMenuItemClickedCommand}" CommandParameter="Exit" />     
        </MenuBarItem>
        <MenuBarItem Text="About">
            <MenuFlyoutItem Text="About" Command="{Binding OnMenuItemAboutClickedCommand}" CommandParameter="About" />
        </MenuBarItem>
    </Shell.MenuBarItems>

As you can see, each of the items in the file menu (except the separator) is bound to a command. Some are bound to the same command, in this instance both Exit and Open are bound to the OnMenuItemClickedCommand, whereas others are bound to individual commands. The reason for this is dependent on what needs to happen when the command is triggered.

MAUI Commands and the ICommand Interface

Handling simple events that occur in the UI on the back end of an MAUI application can be done through the use of commands.

The ICommand interface allows us to define commands and what happens when a command is triggered.

For a command implementation, we must provide an implementation of what happens when we trigger that command, in the form of an action parameter.

We can additionally provide a second function parameter, CommandCanExecute which returns whether the command can be triggered or not. This option is used when we want to enable or disable a control based on the current application state. If we omit it, it will always be true.

Finally, we are also able to define a command parameter, which we can pass from the UI into the command itself.

I will use all three options below to define our commands for this application.

As our AppShell.xaml is bound to our AppShellViewModel (see previous article for more details) we need to add our command implementation to our AppShellViewModel.cs file as below:

public class AppShellViewModel
{
    public ICommand OnMenuItemClickedCommand { get; private set; }
    public ICommand OnMenuItemClosePdfClickedCommand { get; private set; }
    public ICommand OnMenuItemAboutClickedCommand { get; private set; }

    private bool pdfOpen = false;    

    public AppShellViewModel()
    {        

        OnMenuItemClickedCommand = new Command<string>(async (s) => await OnMenuItemClicked(s));
        OnMenuItemClosePdfClickedCommand = new Command<string>(async (s) => await OnMenuItemClicked(s), (s) => PdfOpen);

        OnMenuItemAboutClickedCommand = new Command(DisplayAbout);
    }     

    public async Task OnMenuItemClicked(string item)
    {
        switch (item) {
            case "Exit":
                Application.Current.Quit();
                break;
            case "Open":
                break;
            case "Close":
                break;
            default:
                break;
        }
    }

    public void DisplayAbout()
    {
        // Omitted for brevity
    }
}

Firstly we define three commands that will implement the ICommand interface.

The first 2 commands (OnMenuItemClickedCommand, OnMenuItemClosePdfClickedCommand), both receive a string command parameter and call the OnMenuItemClicked function, passing that parameter and following the path in the switch statement according to which CommandParameter value was passed in from the UI. For now these don't do anything but we will add more functionality in later stages.

The OnMenuItemClosePdfClickedCommand also provides a second function, which returns the value of the pdfOpen field. As this is initially false, this means that the 'Close' button on our file menu will be disabled when we initially launch our application. One thing to note, if we want to enable our command later, we have to set the pdfOpen field to 'true' but also tell our application to re-evaluate the status of the command by calling:

(OnMenuItemClosePdfClickedCommand as Command).ChangeCanExecute();

We will implement this later in the series when we start to look at opening files.

Finally, our last command OnMenuItemAboutClickedCommand simply calls the DisplayAbout function directly when triggered.

Now we should be able to launch our application and it should display a file menu. In the above code, you can see I have also implemented the 'Exit' code so selecting Exit should quit the application!

The next step is to implement some basic navigation!

Did you find this article valuable?

Support Dave K by becoming a sponsor. Any amount is appreciated!