The Hamburger Menu with Prism Forms

How many times have you heard someone ask about a Hamburger menu in Xamarin Forms? It's a topic that comes up fairly frequently and it seems there are two distinct camps. Those who will tell you it's drop dead simple, and those who are stuck trying to figure out why if it's so simple, they can't figure it out. Honestly there are already a ton of YouTube videos and Blog Posts on the topic, so much so that I didn't want to touch the subject. However there is still a ton of confusion about the "Secret Sauce".

 

I would like to think the reality is somewhere in between. So often I find the major reason for these types of disagreement, has more to do with mis-managed expectations. For those stuck trying to figure out how to implement the Hamburger Menu, I think there are two key "gotcha's".

 

I've seen a number of blogs on the topic, but it seems like they're quick to say just use a MasterDetailPage. Ok you're done, you don't have to go home, but don't stay here. But that isn't the whole story. I've seen some blogs that do make more of a point to tell you that your Detail Page must be wrapped in a NavigationPage. But again, that just isn't the whole story.

 

So how on earth do you get that hamburger menu? Well for starters, you don't go to McDonalds (or for those in my neck of the woods, In N Out). When people ask about the "hamburger menu" they aren't asking how do you implement a slide out menu in your app. But that's what we keep telling people. In order to get the "hamburger menu", you need images. See people kept telling you it was easy. The secret sauce is to add an Icon to the Master page of the MasterDetailPage. Xamarin actually does this in their sample, but seems to gloss over the importance.

 

Since I'm a Prism guy though, let me go over the creation of a Prism App with a Hamburger Menu. I will assume you have the basic Prism App setup.

 

App.xaml.cs
public partial class App : PrismApplication
{
    public App( IPlatformInitializer initializer = null ) 
        : base( initializer )
    {

    }

    protected override void OnInitialized()
    {
        InitializeComponent():
        NavigationService.NavigateAsync("MainPage/NavigationPage/ViewA");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<NavigationPage>();
        Container.RegisterTypeForNavigation<MainPage>();
        Container.RegisterTypeForNavigation<ViewA>();
        // So on and so forth...
    }
}
You'll notice here that there are three View's I'm registering. The first is just simply the Xamarin Forms NavigationPage. There's no magic here. The next is my MainPage, which I will go more into detail. And lastly I register ViewA which is just some View that I will have as a Detail Page.

MainPage.xaml
<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="HamburgerMenu.Views.MainPage">
    <MasterDetailPage.Master>
        <!-- Hamburger Menu Secret Sauce... Add an Icon!!!! Make sure it's in your resources for your Platform Project -->
        <NavigationPage Title="Required Foo" Icon="hamburger.png">
            <x:Arguments>
                <ContentPage Title="Menu">
                    <StackLayout Padding="40">
                        <Label Text="{Binding UserName,StringFormat='Hello, {0}'}" />
                        <Button Text="View A" Command="{Binding NavigateCommand}" CommandParameter="Navigation/ViewA?message=Did%20you%20see%20the%20secret%20sauce%3F" />
                        <Button Text="View B" Command="{Binding NavigateCommand}" CommandParameter="Navigation/ViewB?message=Told%20you%20Prism%20Rocks%21%21%21" />
                        <Button Text="View C" Command="{Binding NavigateCommand}" CommandParameter="Navigation/ViewC?message=Does%20the%20hamburger%20make%20you%20hungry%3F%3F%3F" />
                    </StackLayout>
                </ContentPage>
            </x:Arguments>
        </NavigationPage>
    </MasterDetailPage.Master>
</MasterDetailPage>
All code means stuff, and there's a bit going on. Whether I'm coding or not, I'm generally a very light hearted kind of guy that likes to joke around. So you'll notice here the Navigation Page that I have as the MasterDetailPage.Master, has a title of "Required Foo". That is because Title is a required field for the Master, while the Icon is optional. The icon when supplied hides the title. I mentioned that a NavigationPage is a requirement for the "Hamburger Menu", but that is for the Detail, NOT the Master. I am choosing to use the NavigationPage in my Master in this sample, not because I expect actual navigation within the 'Menu', but rather because it quickly gives me the ability to add a nice Header and Toolbar Menu Items.

Now before you go all crazy trying to figure it out. You can download this zip for the Hamburger Icon assets for Android and iOS.

Prism Forms 6.3.0 Highlights

For those following Prism 6.3, it's been a while coming, but there is a lot there. Here are a few helpful things to get you going.

 

Behaviors

One of my favorite additions to Prism Forms 6.3.0 is the addition of Behaviors. First of all Prism gives you a great BehaviorBase<T> class you can use for all of your custom behaviors. But we finally have an EventToCommandBehavior that allows us to execute our ViewModel Commands when an event is triggered, and the control doesn't directly support Commands for that event. This is great for things like attaching to something like a ListView where we might want to work with the ItemTapped or ItemSelected events. You have a wide degree of flexibility here where you can choose to directly accept the EventArgs in your command or you can use a custom converter to grab the item from the EventArgs.

NavigationParameters

One of the breaking API changes you may notice is with the NavigationParameters. In the past, the NavigationParameters was based on a Dictionary which gave us the limitation that a key could only be used once in the querystring. While most of the time this was fine, there are so many cases where you just need to pass a list of something. Along with the new implementation are some great helpers including both a GetValue<T> and GetValues<T>. These are also safe to use if the key didn't actually exist so there's no more need for if( parameters.ContainsKey("foobar")) FooBar = (Foo)parameters["foobar"]. Naturally you will get a default value, so do check for `null`.

 

INavigationAware

Probably one of the most used interfaces in my Prism Forms apps, is INavigationAware. This is a major breaking change. That said, it's worth the frustration of the breaking change here. First of all INavigationAware is no longer a standalone interface. It is now actually the combination of two concepts INavigatingAware and INavigatedAware. As the verbs imply, one is based on Navigation that is about to occur, while the other is about Navigation that has occurred. One of the complaints I often heard, and frankly had myself was that with OnNavigatedTo, there was a visible UI update as my ViewModel was updating the Values that were bound on the UI. INavigatingAware with it's singular OnNavigatingTo really helps to address this problem.

 

The reason why we were seeing the UI changes was that the ViewModel never had a chance to load before we pushed the page onto the Navigation Stack. OnNavigatingTo is only called once, and only before we actually push the page to the stack. Like the sample below shows, we may have some default value that is really only there to alert the developer of a problem or is there for the design time. With the OnNavigatingTo, this value will no longer appear when the the page is actually pushed as the value of Message will update to whatever was in the NavigationParameters.
 
public class FooBarViewModel : BindableBase, INavigatingAware
{
	private INavigationService _navigationService { get; }

	public FooBarViewModel( INavigationService navigationService )
	{
		_navigationService = navigationService;
	}

	private string _message = "some default value"
	public string Message
	{
		get { return _message; }
		set { SetProperty( ref _message, value ); }
	}

	public void OnNavigatingTo( NavigationParameters parameters )
	{
		Message = parameters.GetValue<string>( "message" );
	}
}

BindableBase Update

So this one got snuck in last minute. BindableBase now allows you to specify an action when the value is changed. Also changed was the change up to call RaisePropertyChanged when a property has been changed. This becomes highly useful in a variety of situations like the with the following:
public class Person : BindableBase
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set { SetProperty( ref _firstName, value, () => RaisePropertyChanged( nameof( Name ) ) ); }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set { SetProperty( ref _lastName, value, () => RaisePropertyChanged( nameof( Name ) ) ); }
    }

    public string Name => $"{FirstName} {LastName}";
}

IActiveAware

For long time Prism users, IActiveAware is nothing new. In fact it's been there the whole time. But for Prism Forms, it's really been useless until 6.3.0. With the addition of behaviors, 6.3.0 adds a new behavior to help with one of the major problems that we have when using any MultiPage such as a TabbedPage or CarouselPage in our application. That problem of course, how on earth do you figure out when the user is actually on your page. How to handle the Children of a MultiPage is something that we will be seeing some additional work on before the next release. But in the mean time the IActiveAware behavior really gives us a great tool. Going forward with 6.3.0, I expect we will see a lot of developers adopting a pattern of making ViewModels for children of TabbedPages like the following:
public class TabbedChildPageAViewModel : BindableBase, INavigationAware, IActiveAware
{
	private bool isInitialized = false;

	public event EventHandler IsActiveChanged;

    private bool _isActive;
	public bool IsActive
    {
        get { return _isActive; }
        set { SetProperty( ref _isActive, value, OnIsActiveChanged ); }
    }

	public void OnNavigatingTo( NavigationParameters parameters )
	{
		if( isInitialized ) return;
		isInitialized = true;

		// Implement loading logic here
	}

    private void OnIsActiveChanged()
    {
        // Do Foo
    }
}
with a TabbedPage like the following:
public partial class MyTabbedPage : TabbedPage, INavigatingAware
{
	public MyTabbedPage()
    {
        InitializeComponent();
    }

    public void OnNavigatingTo( NavigationParameters parameters )
    {
        foreach( var child in Children )
        {
            // You only need to do this on the child if any of your child pages actually implement this.
            ( child as INavigatingAware )?.OnNavigatingTo( parameters );
            ( child?.BindingContext as INavigatingAware )?.OnNavigatingTo( parameters );
        }
    }
}
With this strategy you can now both initialize your Tabbed Page Children, and handle the Activation/Deactivation events that occur when the user changes the tab. You can check out a complete example of this in the Prism Samples.

Using Popup Pages with Prism for Xamarin Forms

So often as mobile developers we use some sort of Popup view. Really the reasons why we want to do this simple task are pretty endless. For too long it's been something that wasn't an option for Xamarin Forms. Then came one of my favorite new packages Rg.Plugins.Popup. The only problem is that the library requires navigation through their Popup Navigation Service instead of being integrated in with the Xamarin Forms.

This creates an issue for Prism Applications. How do you navigate to Popup Pages while maintaining a proper MVVM pattern? The solution, Prism.Plugin.Popups. With Prism.Plugin.Popups, Prism based apps can now navigate to Popup Pages using the Prism INavigationService that you're already using. Best of all, there is no configuration required. The plugin adds several new extensions in the Prism.Navigation namespace, so simply adding the INavigationService to your ViewModel and using the Prism.Navigation namespace is all you need to do.
 
using Prism.Navigation;
using Prism.Commands;
using Prism.Mvvm;

namespace MyApp.ViewModels
{
	public class MainPage : BindableBase
	{
		public MainPage( INavigationService navigationService )
		{
			_navigationService = navigationService;

			NavigateCommand = new DelegateCommand( OnNavigateCommandExecuted );
		}

		INavigationService _navigationService { get; }

		DelegateCommand NavigateCommand { get; }

		private async void OnNavigateCommandExecuted() =>
			_navigationService.PushPopupPageAsync( "MyPopupPage" );
	}
}
As mentioned before we're using the INavigationService, and just like the INavigationService you'll need to register your View and/or ViewModel the same as if you're registering any other pages for your application. One caveat to this, in order to function as an extension of the INavigationService it requires specific knowledge of the Container you're using as we have to use your container to resolve the View. As a result there is a container specific implementation for each of the public containers for Prism for Xamarin Forms.