How to Use the Context Menu Feature of Silverlight 4

Tips & Tricks

Summary

This article describes a possible implementation for an IInputMode that can be used side by side with other input modes to manage a context menu that is available in Silverlight 4 using the Silverlight Toolkit.

This article was written for an older version. It is only online as a reference for customers using this old version. The information it contains is probably out of date.

The latest information can be found in the yFiles documentation

Description

Since yFiles for Silverlight 1.0 has been created for Silverlight 3 before version 4 of the runtime was released, it does not have integrated support for the Silverlight 4 Toolkit's context menu. Nevertheless, the context menu feature can be used with the 1.0 version of yFiles for Silverlight using the following example code.

yFiles for Silverlight 2.0 and higher provide an input mode for context menus out of the box. Please refer to the yFiles for Silverlight Developer's Guide for further information.

Make sure you have referenced the optional Silverlight Toolkit from Codeplex that contains the ContextMenu implementation. The toolkit can be downloaded from here: http://silverlight.codeplex.com

MainInputMode, or its subclass GraphEditorInputMode can host a specialized child input mode easily: var editorInputMode = new GraphEditorInputMode(); var contextMenuInputMode = new ContextMenuInputMode() { Menu = new ContextMenu() { Items = { new MenuItem() {Header = "Test"} } }}; editorInputMode.AddConcurrent(contextMenuInputMode);

Below is the implementation of the input mode used in the above snippet. /// <summary> /// An implementation of the <see cref="IInputMode"/> interface that will /// display a <see cref="ContextMenu"/> when the user right clicks on the /// <see cref="CanvasControl"/>. /// </summary> public class ContextMenuInputMode : AbstractConcurrentInputMode { private ContextMenu menu; private MouseEventArgs lastMouseEventArgs; /// <summary> /// Gets or sets the menu to show. /// </summary> /// <remarks> /// If no menu has been configured with this instance this will /// create the menu using the <see cref="CreateMenu"/> callback. /// </remarks> [CanBeNull] public ContextMenu Menu { get { if (menu == null) { menu = CreateMenu(); menu.Opened += Menu_OnOpen; menu.Closed += Menu_OnClosed; } return menu; } set { if (menu != null) { if (menu.IsOpen) { menu.IsOpen = false; ReleaseMutex(); } menu.Opened -= Menu_OnOpen; menu.Closed -= Menu_OnClosed; } menu = value; if (menu != null) { menu.Opened += Menu_OnOpen; menu.Closed += Menu_OnClosed; if (Installed) { ContextMenuService.SetContextMenu(Canvas, menu); } } } } private void Menu_OnOpen(object sender, RoutedEventArgs e) { ContextMenu menu = sender as ContextMenu; if (menu != null && Canvas != null) { if (CanRequestMutex()) { if (lastMouseEventArgs != null) { var position = lastMouseEventArgs.GetPosition(Canvas.GetContentHost()); var worldCoordinates = Canvas.ToWorldCoordinates(position); bool cancel = !OnPopulateContextMenu(menu, worldCoordinates); if (!cancel) { RequestMutex(); return; } } } menu.IsOpen = false; Canvas.Focus(); } } private void Menu_OnClosed(object sender, RoutedEventArgs routedEventArgs) { ReleaseMutex(); if (Canvas != null) { Canvas.Focus(); } } /// <summary> /// This will populate the context menu for the given world coordinate. /// </summary> /// <param name="menu">The menu to optionally populate with items.</param> /// <param name="position">The position in the world coordinate system for which /// the context menu has been invoked.</param> /// <returns>Whether to show the context menu.</returns> protected virtual bool OnPopulateContextMenu(ContextMenu menu, PointD position) { return true; } /// <summary> /// Creates a new instance with no initial context menu. /// </summary> /// <seealso cref="CreateMenu"/> /// <seealso cref="Menu"/> public ContextMenuInputMode() : this(null) { } /// <summary> /// Creates a new instance using the provided menu. /// </summary> /// <param name="menu">The menu to show.</param> public ContextMenuInputMode([CanBeNull] ContextMenu menu) { Menu = menu; } /// <summary> /// Factory method that creates the initial menu strip. /// </summary> /// <remarks> /// Subclasses may override this with more sophisticated implementations. /// </remarks> /// <returns>An empty <see cref="ContextMenu"/></returns> /// <seealso cref="Menu"/> protected virtual ContextMenu CreateMenu() { return new ContextMenu(); } /// <summary> /// Installs this mode in the canvas, registering the <see cref="Menu"/> /// as the canvas' <see cref="ContextMenu"/> /// </summary> /// <param name="context">The canvas to install this mode into.</param> public override void Install(IInputModeContext context) { base.Install(context); ContextMenuService.SetContextMenu(Canvas, Menu); Canvas.MouseMove += OnMouseMoved; } void OnMouseMoved(object sender, MouseEventArgs me) { lastMouseEventArgs = me; } /// <summary> /// Makes the menu invisible. /// </summary> public override void Cancel() { if (menu != null) { menu.IsOpen = false; } base.Cancel(); } /// <summary> /// Makes the menu invisible. /// </summary> /// <returns><c>base.Stop()</c></returns> public override bool Stop() { if (menu != null) { menu.IsOpen = false; } return base.Stop(); } /// <summary> /// Removes the menu from the context and replaces it with the old instance. /// </summary> /// <param name="context">The context to uninstall this mode from.</param> public override void Uninstall(IInputModeContext context) { Canvas.MouseMove -= OnMouseMoved; ContextMenuService.SetContextMenu(Canvas, null); base.Uninstall(context); } }

Categories this article belongs to:
yFiles for Silverlight > yFiles for Silverlight Viewer > Displaying and Editing Graphs > User Interaction
Applies to:
yFiles for Silverlight: 1.0, 1.0.1
Keywords:
context menu - right click - menu - Silverlight 4 - ContextMenuService - ContextMenu