ElementMenu Control



The ElementMenu control that is included in the Microsoft Surface SDK provides a hierarchical menu with menu nodes that your application can associate various commands with.

The ElementMenu control expanded

An ElementMenu control expanded

When you use an ElementMenu control in your application, you associate it with another control that acts as the menu host. When a user touches the host control, the ElementMenu control is activated. You can also create an ElementMenu control that is active at all times.

The following code example shows how to create an ElementMenu control for an application. The ElementMenu control is hosted within a Grid control that resides at the bottom of the SurfaceWindow control. When a user touches the bottom of the Surface screen, the menu is activated.


<Grid Name="MenuGrid" Height="102" VerticalAlignment="Bottom" >

    <s:ElementMenu 
        Name="MainMenu"
        ActivationMode="AlwaysActive"
        ActivationHost="{Binding ElementName=MenuGrid}"
        >

        <s:ElementMenuItem Header="Menu 1"/>
        <s:ElementMenuItem Header="Menu 2"/>
        <s:ElementMenuItem Header="Menu 3">
            <s:ElementMenuItem Header="Menu 3.1"/>
            <s:ElementMenuItem Header="Menu 3.2"/>
            <s:ElementMenuItem Header="Menu 3.3"/>
        </s:ElementMenuItem>
    </s:ElementMenu>

</Grid>

Activation Mode

The ActivationMode property determines how an ElementMenu control is activated. This property accepts a member of the ElementMenuActivationMode enumeration, which has the following values:

 

Member Description

HostInteraction

The menu becomes active when the host element is touched. This mode requires that the ActivationHost property be set. This mode is the default activation mode.

AlwaysActive

The menu is always active. When a menu is active, it displays a small glowing circle. Users can then touch the circle to display the menu items themselves.

Activation Host

When the ActivationMode property is set to HostInteraction (the default value), your application must set the ActivationHost property to the control that you want to initiate menu activation. You can set the ActivationHost property in XAML. The ElementMenu created using the following code does not appear in your application until the Label is touched.


<Grid>
    <!-- TouchLabel is the host for the ElementMenu named: MainMenu. -->
    <Label Name="TouchLabel"
       Content="Touch here to activate menu" 
       HorizontalAlignment="Center" VerticalAlignment="Bottom"/>

    <s:ElementMenu
    Name="MainMenu"
    ActivationMode="HostInteraction" 
    ActivationHost="{Binding ElementName=TouchLabel}">
        <s:ElementMenuItem Header="Menu 1"/>
        <s:ElementMenuItem Header="Menu 2"/>
        <s:ElementMenuItem Header="Menu 3"/>
        <s:ElementMenuItem Header="Menu 4"/>
    </s:ElementMenu>

</Grid>

You can also set the ActivationHost property in code, as the following example shows.


protected override void OnInitialized(EventArgs e)
{
    base.OnInitialized(e);
    MainMenu.ActivationHost = TouchLabel;
}

Instead of referring to an element by name in the ActivationHost attribute, you can use a relative binding, as in the following example. In this example, the ElementMenu is displayed in a ScatterViewItem.


<s:ScatterView Name="mySV">
    <s:ScatterViewItem Name="TouchScatterViewItem">
        <!-- TouchScatterViewItem is the host for the ElementMenu named: MainMenu. -->
        <s:ElementMenu 
            Name="MainMenu" 
            ActivationMode="HostInteraction" 
            ActivationHost="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type s:ScatterViewItem}}}">
            <s:ElementMenuItem Header="Menu 1"/>
            <s:ElementMenuItem Header="Menu 2"/>
            <s:ElementMenuItem Header="Menu 3">
                <s:ElementMenuItem Header="Menu 3.1"/>
                <s:ElementMenuItem Header="Menu 3.2"/>
                <s:ElementMenuItem Header="Menu 3.3"/>
            </s:ElementMenuItem>
        </s:ElementMenu>
    </s:ScatterViewItem>
</s:ScatterView>

When you set the ActivationMode property to AlwaysInteractive, you do not have to set the ActivationHost property, as the following example shows.


<Grid>
<!-- 
ElementMenu does not require an ActivationHost because 
the ActivationMode property is not set to
ElementMenuActivationMode.HostInteraction
-->
    <s:ElementMenu 
    Name="MainMenu"
    ActivationMode="AlwaysActive">
        <s:ElementMenuItem Header="Menu 1"/>
        <s:ElementMenuItem Header="Menu 2"/>
        <s:ElementMenuItem Header="Menu 3"/>
        <s:ElementMenuItem Header="Menu 4"/>
    </s:ElementMenu>

</Grid>

Assigning Commands to Menu Nodes

When a user touches a menu node, that node typically either activates a submenu or performs a task that has been assigned to that menu node. There are two ways to assign a command to an ElementMenuItem object:

  • Listen to the Click event.

  • Establish a routed command.

The following code example shows an ElementMenu control with two nodes. The first node uses an event handler for the Click event to perform a task that is associated with that node. The second node references a routed command.


<Grid>
    <!-- TouchLabel is the host for the ElementMenu named: MainMenu. -->
    <Label Name="TouchLabel"
       Content="Touch here to activate menu" 
       HorizontalAlignment="Center" VerticalAlignment="Bottom"/>

    <s:ElementMenu 
    Name="MainMenu"
    ActivationMode="HostInteraction"
    ActivationHost="{Binding ElementName=TouchLabel}">

        <!-- This item uses the Click event to run code for the menu node. -->
        <s:ElementMenuItem 
        Header="Menu 1" 
        Click="ElementMenuItem_Click"/>

        <!-- This item uses a routed command to run code for the menu node. -->
        <s:ElementMenuItem 
        Header="Menu 2"
        Command="{x:Static local:SurfaceWindow4.RoutedMenuCommand}" 
        CommandParameter="{Binding Path=Header, RelativeSource={x:Static RelativeSource.Self}}"/>
    </s:ElementMenu>

</Grid>

The Click event handler is straightforward, as the following example shows.


private void ElementMenuItem_Click(object sender, RoutedEventArgs e)
{
    // Run code for the Click event here.
}

The routed command pattern uses a static RoutedCommand object that is in turn bound to the code that is associated with the command. This approach offers more flexibility than simply listening to the Click event. The following code example shows the declaration of the static RoutedCommand object and its subsequent binding.


public static readonly RoutedCommand RoutedMenuCommand = new RoutedCommand();

protected override void OnInitialized(EventArgs e)
{
    base.OnInitialized(e);
    this.CommandBindings.Add(new CommandBinding(RoutedMenuCommand, MenuCommand));
}

private void MenuCommand(object sender, ExecutedRoutedEventArgs e)
{
    // Run code for the command here.
}

For more information about routed commands in Windows Presentation Foundation (WPF), see the Commanding Overview topic on the MSDN Web site.

Displaying Icons in Menu Nodes

You can use the Icon property to add an image to the lower-right corner of an ElementMenuItem control. For example, icons are displayed in the ElementMenu control in the Controls Box SDK sample, as in the following image.

Expanding an ElementMenu control that has icons

The following code example shows how to set the Icon property of ElementMenuItem controls to static resources. This code example comes from the Window1.xaml file in the Controls Box SDK sample.


<s:ScatterViewItem 
  Height="139" 
  Width="224" 
  Orientation="-23"
  Background="#FF787878">
  <s:ElementMenu 
    ActivationMode="AlwaysActive"
    HorizontalAlignment="Left" 
    VerticalAlignment="Top">
    <s:ElementMenuItem Header="{x:Static Resources:Resources.Photo}" Icon="{StaticResource IconPhoto}">
      <s:ElementMenuItem Header="{x:Static Resources:Resources.Copy}" Icon="{StaticResource IconPhotoCopy}"/>
      <s:ElementMenuItem Header="{x:Static Resources:Resources.Crop}" Icon="{StaticResource IconPhotoCrop}"/>
      <s:ElementMenuItem Header="{x:Static Resources:Resources.Delete}" Icon="{StaticResource IconPhotoDelete}"/>
      <s:ElementMenuItem Header="{x:Static Resources:Resources.Redeye_Correction}" Icon="{StaticResource IconPhotoRedeye}"/>
    </s:ElementMenuItem>
    <!-- ... more ElementMenuItem controls... -->
  </s:ElementMenu>
</s:ScatterViewItem>

The static resources are defined in the parent ScatterView control using the following code.


<s:ScatterView HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
  <s:ScatterView.Resources>
    <Image x:Shared="false" x:Key="IconPhoto" Source="Resources\Icons\photo.png"/>
    <Image x:Shared="false" x:Key="IconPhotoCopy" Source="Resources\Icons\photo - copy.png"/>
    <Image x:Shared="false" x:Key="IconPhotoCrop" Source="Resources\Icons\photo - crop.png"/>
    <Image x:Shared="false" x:Key="IconPhotoDelete" Source="Resources\Icons\photo - delete.png"/>
    <Image x:Shared="false" x:Key="IconPhotoRedeye" Source="Resources\Icons\photo - redeye correction.png"/>
    <!-- ... more resources ... -->
  </s:ScatterView.Resources>

You can use any of the icons in the Controls Box SDK sample in your own applications. For information about installing the SDK samples, see Extracting and Installing the Surface Samples.

Usability for ElementMenu Controls

If you use ElementMenu in your Surface application, keep the following usability guidelines in mind:

  • Place the menu on the host itself to reinforce the connection between its content and the target for its actions. The menu's design is optimized for placement on the topmost edge of its host.

  • Consider making the submenu open next to the host control so that the host control is not covered by the submenu. You can change the direction in which the submenu opens by using the Orientation property.

  • Thoroughly test all content in the control for visibility, legibility, line weight, and brightness at all possible sizes and angles.

  • Limit the number of options. Research has shown that users can target menu items most accurately at 45 degrees when they are working quickly. Therefore, each level should have a maximum of eight options.

  • Do not exceed two levels of depth.

  • Do not place the menu in a scrollable control, such as SurfaceListBox or LibraryBar. For situations where the content of such a container will contain an ElementMenu control, make users drag the item out of the list so that it turns into a ScatterViewItem object that contains the menu.

  • Do not use the Margin property of ElementMenuItem to position the ElementMenuItem control because it can distort the appearance of the menu.

  • Do not add more than 8 items to an ElementMenu control, nor more than 7 items to an ElementMenuItem control.

  • Do not modify the template of the ElementMenu or ElementMenuItem controls. You can change the appearance of the controls by using the relevant properties, but creating a customized template will result in unexpected behavior.

Did you find this information useful? Please send us your suggestions and comments.

© Microsoft Corporation. All rights reserved.
Show: