Customizing the map menu

The menu associated with the map display in the application is accessed through the MapControl class, which can be customized in the same way that as the other application menus. As with MobileApplication, the MapControl class has a MenuItems property, which is an ordered collection of objects. However, there can be more than one MapControl and, consequently, more than one map menu. The map menu can be customized for a single instance or for all instances.

Extending the map menu on only the View Map page

To customize the menu of a particular map control, you first need to determine which map control to customize and get a reference to it. For this example, you'll extend the menu of the map control on the View Map page. This particular map control is part of ViewMapPage, which is part of ViewMapTask. Start by getting ViewMapTask from the project:

ViewMapTask  viewMapTask = (ViewMapTask)MobileApplication.Current.Project.Tasks.GetFirstExtensionOfType(typeof(ViewMapTask));

Next, ViewMapPage is accessible as a property on ViewMapTask:

ViewMapPage viewMapPage = viewMapTask.ViewMapPage;

Finally, MapControl is accessible via a property on ViewMapPage:

MapControl mapControl = viewMapPage.MapControl;

You can now customize the map control's menu similar to the application menu.

NoteNote:

Since the ICommand/RelayCommand Execute delegate is not passed any parameters, retain a reference to MapControl when you add the menu so that you have access to MapControl in the Execute delegate:

class MyExtension :  ProjectExtension
{
    private MapControl _mapControl;

    protected override void OnOwnerInitialized()
    {
      ViewMapTask viewMapTask = (ViewMapTask)MobileApplication.Current.Project.Tasks.GetFirstExtensionOfType(typeof(ViewMapTask));
      if (viewMapTask == null)
        return;

      _mapControl = viewMapTask.ViewMapPage.MapControl;

      MenuItem menuItem = new MenuItem();
      menuItem.Header = "Hello";
      menuItem.Command = new RelayCommand(param => this.MyMapCommandExecute());
      _mapControl.MenuItems.Add(menuItem);
    }

    private void MyMapCommandExecute()
    {
      StringBuilder builder = new StringBuilder();
      builder.AppendLine("You clicked my menu item!");
      builder.AppendLine(_mapControl.Map.Extent.ToString());
      System.Windows.MessageBox.Show(builder.ToString());
    }
}

Another way to write this example is to use WPF RoutedUICommand instead of RelayCommand. One benefit of using RoutedUICommand is that the Execute delegate of the command binding is passed the control that raised the event as a parameter. This means, as in the previous code example, you do not need to retain a reference to MapControl as a member variable. This enables you to add menu items to multiple menus that all reference the same RoutedUICommand.

NoteNote:

In the following code example, the CommandTarget property of the menu item is set to ensure the command is routed correctly (otherwise, the command may not be enabled).

Here is the above example rewritten using RoutedUICommand:

class MyExtension :  ProjectExtension
{
    / Our (static) RoutedUICommand
    public static readonly RoutedUICommand MyRoutedMapCommand = new RoutedUICommand("Hello", "MyRoutedMapCommand", typeof(Extension));

    protected override void OnOwnerInitialized()
    {
      ViewMapTask viewMapTask = (ViewMapTask)MobileApplication.Current.Project.Tasks.GetFirstExtensionOfType(typeof(ViewMapTask));
      if (viewMapTask == null)
        return;

      MapControl mapControl = viewMapTask.ViewMapPage.MapControl;

      // Add a new item to the map control menu in the ViewMapPage
      MenuItem menuItem = new MenuItem();
      menuItem.Header = "Hello";
      menuItem.Command = MyRoutedMapCommand;
      menuItem.CommandTarget = mapControl;
      mapControl.MenuItems.Add(menuItem);

      // Now add a command binding for our RoutedUICommand to the map control
      CommandBinding commandBinding = new CommandBinding(MyRoutedMapCommand);
      commandBinding.Executed += new ExecutedRoutedEventHandler(RoutedWorkListPageCommandBinding_Executed);
      mapControl.CommandBindings.Add(commandBinding);
    }

    void RoutedWorkListPageCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      MapControl mapControl = sender as MapControl;

      StringBuilder builder = new StringBuilder();
      builder.AppendLine("You clicked my menu item!");
      builder.AppendLine(mapControl.Map.Extent.ToString());
      System.Windows.MessageBox.Show(builder.ToString());
    }
  
}

The above example can be extended to create and add another menu item associated with the same RoutedUICommand and add it to a different map control menu on a different page using the same Executed handler (RoutedWorkListPageCommandBinding_Executed).

Extending all map menus

The application framework allows the menu of all map control instances to be customized. MapControl has a static event (CreatingMapControlMenuItems) that is raised each time an instance of MapControl creates its collection of menu items. The EventArgs parameter passed to this event contains a reference to the MapControl instance that is creating its MenuItems collection.

public static event EventHandler<CreatingMapControlMenuItemsEventArgs> CreatingMapControlMenuItems;

To add a menu item to all map controls, subscribe to the CreatingMapControlMenuItems event and update the MenuItems collection of the MapControl instance passed to the event handler.

class MyExtension :  ProjectExtension
{
  public static readonly RoutedUICommand RoutedGlobalMapCommand =
    new RoutedUICommand("Hello ", "RoutedGlobalMapCommand", typeof(MyExtension));
 
  public MyExtension()
  {
    ESRI.ArcGIS.Mobile.Client.Controls.MapControl.CreatingMapControlMenuItems +=
      new EventHandler<CreatingMapControlMenuItemsEventArgs>(MapControl_CreatingMapControlMenuItems);
  }
 
  void MapControl_CreatingMapControlMenuItems(object sender, CreatingMapControlMenuItemsEventArgs e)
  {
    MenuItem menuItem = new MenuItem();
    menuItem.Header = "Hello";
    menuItem.Command = RoutedGlobalMapCommand;
    menuItem.CommandTarget = e.MapControl;
    e.MapControl.MenuItems.Add(menuItem);
 
    CommandBinding commandBinding = new CommandBinding(RoutedGlobalMapCommand);
    commandBinding.Executed +=new ExecutedRoutedEventHandler(RoutedGlobalMapCommandBinding_Executed);
    e.MapControl.CommandBindings.Add(commandBinding);
  }

  void RoutedGlobalMapCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
  {
    // Similar to previous examples
				// Perform some action when the menuitem is clicked
  }
 
  protected override void Uninitialize()
  {
    // Stop listening to events
    ESRI.ArcGIS.Mobile.Client.Controls.MapControl.CreatingMapControlMenuItems -=
      new EventHandler<CreatingMapControlMenuItemsEventArgs>(MapControl_CreatingMapControlMenuItems);
  }
}
1/7/2015