Show a context menu using MenuFlyout on Windows Phone 8.1

Show a context menu using MenuFlyout on Windows Phone 8.1

If you're used to developing apps for Windows Phone, then you probably used a ContextMenu as a part of your ListBox, LongListSelector or some other UI control at some point. In new, Windows Phone 8.1 WinRT apps, there's a much much easier way to get your context menu by using Flyouts - MenuFlyout to be exact, in the old-new ListView/GridView controls!

Let's start with a simple HubApp template which already hase a Hub defined with a couple of HubSections which contain ListViews/GridViews. The first ListView has a defined ItemTemplate:

<ListView.ItemTemplate>  
    <DataTemplate>
        <StackPanel>
            <TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
        </StackPanel>
    </DataTemplate>
</ListView.ItemTemplate>  

Now, instead of the old ContextMenus and MenuItems, we can use the Attached Flyout on the top panel (StackPanel in this case) like this:

<pre class="brush: csharp;"><ListView.ItemTemplate>  
    <DataTemplate>
        <StackPanel>
            <FlyoutBase.AttachedFlyout>
                <MenuFlyout>
                    <MenuFlyoutItem Text="Delete" />
                    <MenuFlyoutItem Text="Refresh" />
                    <MenuFlyoutItem Text="Share" />
                </MenuFlyout>
            </FlyoutBase.AttachedFlyout>
            <TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
        </StackPanel>
    </DataTemplate>
</ListView.ItemTemplate>  

Now we need a way to actually show the Flyout. We can do it on any event you like, such as Tapped or Holding. I kind of always expect context menus to open on hold, so let's add a holding event handler to the StackPanel

<ListView.ItemTemplate>  
    <DataTemplate>
        <StackPanel Holding="ListViewItem_Holding">
            <FlyoutBase.AttachedFlyout>
       .........

And in the code behind event handler we do the following to show the exact Flyout:

private void ListViewItem_Holding(object sender, HoldingRoutedEventArgs e)  
{
    FrameworkElement senderElement = sender as FrameworkElement;
    FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(senderElement);

    flyoutBase.ShowAt(senderElement);
}

And that's it - a working MenuFlyout on hold event. Have in mind that this works the same on other event handlers such as Tapped and also works the same on GridView!

The result:

Simple MenuFlyout context menu

MVVM approach

The first thing that might bother you is that this requires code-behind to open the Flyout, so we'll write an action to do it for us - that way the component is reusable. Start by adding the Behaviors reference to your project. Note that if you plan to create an action in Shared project (Universal app), you need to add Behaviors reference to both Windows Phone 8.1 and Windows 8.1 projects.

Add behaviors to support MVVM approach for MenuFlyout

Now we can write the action code. Let's do it in a separate public class called OpenMenuFlyoutAction:

public class OpenMenuFlyoutAction : DependencyObject, IAction  
{
    public object Execute(object sender, object parameter)
    {
        FrameworkElement senderElement = sender as FrameworkElement;
        FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(senderElement);

        flyoutBase.ShowAt(senderElement);

        return null;
    }
}

This looks fairly simple. It's a simple class that inherits from DependencyObject and implements IAction interface - meaning that it implements the Execute method. But how is it triggered?

It's triggered by using a behavior called EventTriggerBehavior. It's added to the DataTemplate panel instead of the Holding event handler we used earlier:

<ListView.ItemTemplate>  
    <DataTemplate>
        <StackPanel>
            <i:Interaction.Behaviors>
                <core:EventTriggerBehavior EventName="Holding">
                    <local:OpenMenuFlyoutAction />
                </core:EventTriggerBehavior>
            </i:Interaction.Behaviors>
            <FlyoutBase.AttachedFlyout>
          ............

This basically means - when Holding event occurs, call the Execute method on OpenMenuFlyoutAction. No more code-behind!

If you're wondering where the i: and core: come from - they are just namespaces from the Behaviors reference you added earlier which are defined in XAML:

xmlns:i="using:Microsoft.Xaml.Interactivity"  
xmlns:core="using:Microsoft.Xaml.Interactions.Core"  

Also, have in mind that the MenuFlyoutItem has a Command and CommandParameter properties, so you can use those to bind to underlying ViewModel and the ICommands which are defined in the underlying ViewModel, and give those commands the parameter they need to identify which item in the list was tapped/hold. There's a RelayCommand implementation of ICommand interface in the Hub app template for Windows Phone 8.1 which you can use to define your commands!

Igor Ralic

igor ralic

View Comments
Microsoft Certified Solutions Developer: Windows Store Apps in C#