| Comments

I’m continuing in my series of helping to provide Callisto migration tips to use new Windows 8.1 features. In a recent post I talked about the Flyout control and provided the path to the platform-provided features. In Callisto, the Menu control was provided as sort of a prescribed content for the Flyout control. In fact you really couldn’t use Menu without Flyout.

Menu control sample image

This guide will help you change to the platform-provided MenuFlyout now available in Windows 8.1.

API Differences

On the public surface area, there aren’t actually many changes here. Windows 8.1 MenuFlyout provides more functionality as it derives from FlyoutBase, which is the base for Flyout as well. So you get the same ShowAttachedFlyout capability that you have there. Both have an Items property that is a collection of the menu items you’d put in there. For these purposes I’m not detailing out the minutiae of differences between FlyoutBase and Menu here as it isn’t relevant to migration but is useful later as I’ll demonstrate. The main reason is that as I noted earlier, you actually can’t use Menu in Callisto without using Flyout, hence the lack of a significant delta here at the Menu level.

Change to the MenuFlyout

As with the other examples, I’m going to use the Callisto test app code here to show migration. Since Menu needed Flyout, you had more of a code-focused approach in ideal Callisto usage. We believe that the main use cases for Menus are also in Button invoke scenarios. Here’s an example of showing a Menu in Callisto:

private void ShowFlyoutMenu(object sender, RoutedEventArgs e)
{
    Callisto.Controls.Flyout f = new Callisto.Controls.Flyout();
    f.PlacementTarget = sender as UIElement;
    f.Placement = PlacementMode.Top;
    f.Closed += (x, y) =>
    {
        LogEvent("Event: Closed");
    };
 
    Menu menu = new Menu();
 
    MenuItem mi = new MenuItem();
    mi.Tag = "Easy";
    mi.Tapped += ItemClicked;
    mi.Text = "Easy Game";
    mi.MenuTextMargin = new Thickness(28, 10, 28, 12);
 
    MenuItem mi2 = new MenuItem();
    mi2.Text = "Medium Game";
    mi2.Tag = "Medium";
    mi2.Tapped += ItemClicked;
    mi2.MenuTextMargin = new Thickness(28, 10, 28, 12);
 
    ToggleMenuItem tmi = new ToggleMenuItem();
    tmi.Text = "Enable Logging";
    tmi.IsChecked = chk;
    tmi.Tapped += (a, b) =>
        {
            chk = !chk;
        };
 
    menu.Items.Add(mi);
    menu.Items.Add(mi2);
    menu.Items.Add(new MenuItemSeparator());
    menu.Items.Add(new MenuItem() { Text = "Foobar something really long", Tag = "Long menu option", MenuTextMargin = new Thickness(28,10,28,12) });
    menu.Items.Add(tmi);
 
    f.HostMargin = new Thickness(0); // on menu flyouts set HostMargin to 0
    f.Content = menu;
    f.IsOpen = true;
}

You will have to understand some of the events and variables are examples here (LogEvent and chk). Notice how you have to create a Flyout first, then put the Menu in it with all the items. Here is how you would migrate that code to provide immediate migration to the platform control:

private void ShowMenuFlyout3(object sender, RoutedEventArgs e)
{
    MenuFlyout mf = new MenuFlyout();
    MenuFlyout.SetAttachedFlyout(sender as FrameworkElement, mf);
    mf.Closed += (x, y) =>
        {
            LogEvent("Event: Closed");
        };
 
    MenuFlyoutItem mi = new MenuFlyoutItem();
    mi.Tag = "Easy";
    mi.Tapped += ItemClicked;
    mi.Text = "Easy Game";
 
    MenuFlyoutItem mi2 = new MenuFlyoutItem();
    mi2.Text = "Medium Game";
    mi2.Tag = "Medium";
    mi2.Tapped += ItemClicked;
 
    ToggleMenuFlyoutItem tmi = new ToggleMenuFlyoutItem();
    tmi.Text = "Enable Logging";
    tmi.IsChecked = chk;
    tmi.Tapped += (a, b) =>
        {
            chk = !chk;
        };
 
    mf.Items.Add(mi);
    mf.Items.Add(mi2);
    mf.Items.Add(new MenuFlyoutSeparator());
    mf.Items.Add(tmi);
 
    MenuFlyout.ShowAttachedFlyout(sender as FrameworkElement);
}

Now notice how the shape of the items is similar so helping with some migration. You create a MenuFlyout, MenuFlyoutItems (notice the separator and ToggleMenuFlyoutItem), then add them to the MenuFlyout and show it. But just like Flyout in Windows 8.1 we believe there was an easier way we could provide creating and using MenuFlyout.

A better way to use MenuFlyout

Much like Flyout we believe the primary use case for MenuFlyout will be from ButtonBase invocations. Let’s look at the declarative approach to the code above:

<AppBarButton Icon="Add" Label="New Game">
     <AppBarButton.Flyout>
         <MenuFlyout>
             <MenuFlyoutItem Tag="Easy" Text="Easy Game" Tapped="ItemClicked" />
             <MenuFlyoutItem Tag="Medium" Text="Medium Game" Tapped="ItemClicked" />
             <MenuFlyoutSeparator />
             <ToggleMenuFlyoutItem Text="Enable Logging" IsChecked="True" />
         </MenuFlyout>
     </AppBarButton.Flyout>
 </AppBarButton>

This allows us to provide an automatic way to show the menu when the button is clicked. If we aren’t using a Button we can still use the Set/ShowAttachedFlyout method as demonstrated above.

Summary

Moving to the new MenuFlyout control will again gain you better performance, compliance with UI guidelines, declarative model and accessibility features. As you can see there is a short-term migration approach using the the ShowAttachedFlyout method to allow you to very quickly take advantage of the new control if you were using the Callisto code method. Your app can then decide if it makes sense to move to the declarative model. Either way, the new control is great and you should use it! We also have a Windows 8.1 MenuFlyout SDK Sample that you can examine to play around with the API.

Hope this helps!

Please enjoy some of these other recent posts...

Comments