User Interaction

In terms of the Model-View-Controller (MVC) paradigm, the controller part is the tie between the model and the view. It handles the user interaction and accordingly changes state of both model and view. In yFiles for Silverlight, controllers are so-called "input modes."

There is a variety of specialized input modes available that handle specific user interaction aspects ranging from general keyboard input to mouse gestures within well-defined contexts. The functionality provided by these specialized input modes is combined by general-purpose input modes that serve as composites which enable full-featured handling of user interaction. The most comprehensive input modes are:

Class GraphViewerInputMode

Class GraphViewerInputMode is a controller that provides convenient navigation-only support in a graph. It makes available the functionality of a set of specialized input modes.

In particular, through its input modes, GraphViewerInputMode transparently supports both mouse-based gestures and touch gestures.

Registering a GraphViewerInputMode instance with a GraphControl is done through the control's InputModes property, for example.

// 'gc' is of type yWorks.yFiles.UI.GraphControl.

// Add GraphViewerInputMode to the graph control.
gc.InputModes.Add(new GraphViewerInputMode());

Upon initialization, GraphViewerInputMode creates and installs the input modes listed in Table 4.19, “Input modes used by GraphViewerInputMode (sorted by input mode priority)” as concurrent input modes. Note that the input modes are sorted according to their priority (see also the section called “Input Mode Priorities”).

Table 4.19. Input modes used by GraphViewerInputMode (sorted by input mode priority)

Type Name Description
ClickInputMode Recognizes mouse clicks, including double clicks.
TapInputMode Provides touch support, recognizes taps and double taps.
MarqueeSelectionInputMode Provides the visual feedback for a rectangular selection box in the canvas.
ContextMenuInputMode Enables displaying context menus. See also below.
NavigationInputMode Enables navigation in the graph structure.
MouseHoverInputMode Displays a tooltip when the mouse rests in the canvas.
MoveViewportInputMode Enables dragging the viewport.
ItemHoverInputMode Provides mouse enter/mouse leave events for graph items and also item visualization change events for graph items under the mouse.
WaitInputMode Blocks user interaction and tries to cancel ongoing edits.

Each of the input modes can be obtained or replaced using a like-named property defined by GraphViewerInputMode. Also, a sorted list of input modes can be obtained via the GetSortedModes method.

Element States in Interactions

During a user interaction or as a result of a user interaction that is handled by GraphViewerInputMode, a graph element can take on different "states." There are two kinds of states, each indicated to the user by some visual decoration to a graph element:

  • Selection One or more elements can be selected at a time. Typically, an element is selected by clicking on it, using a marquee selection multiple elements can be selected at once. By default, a selected element is indicated using a checkered border around it as the decoration.
  • Focus Only one element at a time can be focused. The focused element is the CurrentItem of the graph. A node can become focused after selecting it and then clicking on another UIElement in the window. The selection indication goes away, but the focus stays. By default, a focused element is indicated using a thin dashed line around it as the decoration.

The visual decorations that are used to indicate an element's state can be customized as described in the section called “Customizing User Interaction Behavior”. They are managed by the ModelManager implementation classes SelectionPaintManager<T> and FocusPaintManager<T>, respectively. To prevent any selection or focus indications, each of these managers can be disabled.

Interaction Events

GraphViewerInputMode and its minor modes provide fine-grained events that are fired upon user interactions.

Note that these events are only fired due to direct user interaction with a graph. They are not fired due to programmatic changes to a graph or during graph I/O.

Table 4.20. GraphViewerInputMode-related events

Input Mode Event Name Description
GraphViewerInputMode ItemClicked, ItemLeftClicked, and ItemRightClicked Occurs when an item (node, edge, bend, label, port) has been (left/right) clicked. Corresponding events are available to cover double (left/right) clicks.
ItemSelected An event that will be triggered if an item changed its selection state from unselected to selected. Fired by the input mode's SelectionModel.
ItemDeselected An event that will be triggered if an item changed its selection state from selected to unselected. Fired by the input mode's SelectionModel.
MultiSelectionStarted An event that will be triggered if a single-select or multi-select operation has been started.
MultiSelectionFinished An event that will be triggered if a single-select or multi-select operation has been finished.
PopulateItemContextMenu Occurs when the context menu over an item (node, edge, bend, label, port) is about to be opened to determine the contents of the menu.
QueryItemToolTip Occurs when the mouse is hovering over an item (node, edge, bend, label, port) to determine the tool tip to display.
ClickInputMode Clicked and DoubleClicked The event handler that will be triggered once a (double) click has been detected.
TapInputMode Tapped and DoubleTapped The event handler that will be triggered once a (double) tap has been detected.
MarqueeSelectionInputMode MarqueeSelected An event that will be triggered once the marquee selection has been finished.
MouseHoverInputMode QueryToolTip Occurs when this mode queries the tool tip for a certain query location.
ContextMenuInputMode PopulateContextMenu An event that will be triggered when the context menu is about to be shown.
ItemHoverInputMode HoveredItemChanged Occurs when the item (node, edge, bend, label, port) that the mouse is hovering over changes.

Interaction Customization

Class GraphViewerInputMode provides various properties and callbacks that allow for fine-grained control over the support for navigation interaction. For example, for certain kinds of navigation gestures the set of graph element types that the input mode may act upon can be restricted to a specific subset of the available types.

Table 4.21, “GraphViewerInputMode customization” lists the customization properties of class GraphViewerInputMode. Most of the properties support that combinations of graph element types can be specified using the constants defined in the GraphItemTypes enumeration type.

Table 4.21. GraphViewerInputMode customization

Name Purpose
SelectableItems A combination of GraphItemTypes that specifies the set of graph element types that can be selected by the user.
MarqueeSelectableItems A combination of GraphItemTypes that specifies the set of graph element types that can be selected using the marquee selection tool.
ClickableItems A combination of GraphItemTypes that specifies the set of graph element types that can be clicked/tapped.
FocusableItems A combination of GraphItemTypes that specifies the set of graph element types that can have focus.
VoidStylesIgnored A boolean property that controls whether graph elements with void styles can be selected/focused using the keyboard.
ContextMenuItems A combination of GraphItemTypes that specifies the set of graph element types that provide context menus.
ToolTipItems A combination of GraphItemTypes that specifies the set of graph element types that provide tooltips.

Example 4.33, “Using the GraphItemTypes constants” shows how to use the GraphItemTypes constants to customize a GraphViewerInputMode instance.

Example 4.33. Using the GraphItemTypes constants

// 'gvim' is of type yWorks.yFiles.UI.Input.GraphViewerInputMode.

// Do not allow selection of any graph elements.
gvim.SelectableItems = GraphItemTypes.None;

// Tooltips are queried only for nodes and edges.
gvim.ToolTipItems = GraphItemTypes.Node | GraphItemTypes.Edge;

The PopulateItemContextMenu and QueryItemToolTip events can be used to attach appropriate event handler logic that provides either the contents of an item's context menu or tooltip.

Class GraphEditorInputMode

Class GraphEditorInputMode is a full-featured controller that makes available the functionality of a set of specialized input modes. It is a subtype of class MainInputMode that covers all aspects of user interaction with an IGraph instance displayed in a GraphControl.

In particular, through its input modes, GraphEditorInputMode transparently supports both mouse-based gestures and touch gestures.

Figure 4.31. GraphEditorInputMode type hierarchy

GraphEditorInputMode type hierarchy.

Registering a GraphEditorInputMode instance with a GraphControl is done through the control's InputModes property, for example. The graph that is displayed in the control is given to the input mode at creation time.

// 'gc' is of type yWorks.yFiles.UI.GraphControl.

// Add GraphEditorInputMode to the graph control.
gc.InputModes.Add(new GraphEditorInputMode());

General Features

GraphEditorInputMode provides convenient support for creating, modifying, and interacting with graph elements in an IGraph instance.

  • The IGraph instance that GraphEditorInputMode acts upon is accessible via the Graph property.
  • The HitTestEnumerator property can be conveniently used for performing hit-tests.
  • Direct notification of user interaction is provided by numerous events: Interaction Events.
  • Default behavior when interacting with graph elements can be easily customized even with respect to specific graph element types. Interaction Customization describes properties and callback methods available for customization.

GraphEditorInputMode also provides convenient support for grouped graphs, which includes, for example, grouping and ungrouping of nodes as well as re-parenting. Additional support for folding operations, like collapsing and expanding group nodes is available, too.

Tutorial demo applications SimpleEditorWindow and GraphEditorWindow show how GraphEditorInputMode is used with a GraphControl instance.

Upon initialization, GraphEditorInputMode creates and installs the input modes listed in Table 4.22, “Input modes used by GraphEditorInputMode (sorted by input mode priority)” as concurrent input modes. Note that the input modes are sorted according to their priority (see also the section called “Input Mode Priorities”).

Table 4.22. Input modes used by GraphEditorInputMode (sorted by input mode priority)

Type Name Description
WaitInputMode Blocks user interaction and tries to cancel ongoing edits.
KeyboardInputMode Recognizes key events.
ClickInputMode Recognizes mouse clicks, including double clicks.
TapInputMode Provides touch support, recognizes taps and double taps.
MoveLabelInputMode Specialized instance that handles moving of labels to label candidate positions.
MoveInputMode Handles moving of canvas objects.
CreateBendInputMode Governs the creation of additional bends in edge paths.
CreateEdgeInputMode Governs the creation of edges in an IGraph.
MarqueeSelectionInputMode Provides the visual feedback for a rectangular selection box in the canvas.
HandleInputMode Manages the dragging of "handles," including the detection of beginning and ending of a drag, and canceling a drag. Also provides the visual feedback for handles when dragged.
MoveViewportInputMode Handles panning the viewport, i.e., enables the currently visible part of the canvas to be dragged around.
NavigationInputMode Enables navigation in the graph structure.
ItemHoverInputMode Provides mouse enter/mouse leave events for graph items and also item visualization change events for graph items under the mouse.
ContextMenuInputMode Enables displaying context menus. See also below.
NodeDropInputMode Handles the drop part of a drap-n-drop gesture.
MouseHoverInputMode Displays a tooltip when the mouse rests in the canvas.
TextEditorInputMode Handles label editing.

Each of the input modes can be obtained or replaced using a like-named property defined by GraphEditorInputMode. Also, a sorted list of input modes can be obtained via the GetSortedModes method.

Graph element creation functionality is provided directly by GraphEditorInputMode as well as the input modes CreateBendInputMode and CreateEdgeInputMode. The former uses the method below whenever a node is created in the canvas by means of a mouse click/finger tap gesture. Using the NodeCreationAllowed and NodeCreator properties, the actual node creation behavior can be easily customized.

INode CreateNode(PointD clickPoint)
Description Mouse gesture/tap gesture node creation method.

Bend creation and edge creation are governed by CreateBendInputMode and CreateEdgeInputMode, respectively. However, CreateEdgeInputMode additionally exposes convenient bend-related customization capabilities. For example, the BendCreationAllowed property can be used to disallow bend creation in the canvas.

GraphEditorInputMode by default supports the keyboard shortcuts listed in the table below. Technically, all keyboard shortcuts trigger corresponding command bindings, which are mainly defined in class GraphCommands (hierarchy-related command bindings) and in class GraphControl.

Table 4.23. Keyboard shortcuts provided by GraphEditorInputMode

Keyboard shortcut Description
F2 Initiates text editing of the selected label or the first label of the selected item. Creates a new label if the selected item has no label so far.
Shift + F2 Creates a new label for the selected graph item and initiates text editing of the new label.
Ctrl + X, Ctrl + C Cuts (copies) the selected items.
Ctrl + V Pastes the contents of the clipboard into the active diagram.
Ctrl + Z, Ctrl + Y Initiates undo (redo) of the last command.
Delete Deletes the selected items.
Ctrl + A, Ctrl + D Selects (deselects) all items.
Ctrl + Space Toggles the selection of the focused element.
Arrow key (Up, Down, Left, Right) Selects the next item in the specified direction. See also the description below.
Shift + Arrow key (Up, Down, Left, Right) Extends the selection by the next item in the specified direction. See also the description below.
Ctrl + Arrow key (Up, Down, Left, Right) Focuses the next item in the specified direction. See also the description below.
Page Up, Page Down Selects the parent node of the selected node or group node (one of the child nodes of the selected group node).
Ctrl + G Creates a new group encompassing the selected nodes.
Ctrl + U Removes each selected node from all of its parent group nodes. The group nodes are not deleted.
Ctrl + Subtract, Ctrl + Add Collapses (expands) the selected groups.
Ctrl + Enter Enters the selected group. The view shows only the child nodes of this group node and hides all other elements and the group node itself.
Ctrl + Backspace Exits the current group node. Available only when a group node was entered before.
Ctrl + Shift + G Resizes each selected group node to the bounding box of its child nodes.

The next item when using the arrow keys depends on several parameters:

  • 'Direction' refers to plain geometric locations, not to 'forward' or 'backward' edges between the nodes.
  • In any case, the reference point is the center of the focused item.
  • If there is no item in the specified direction, nothing happens.
  • If there are several possible items, a weighted average of the item's distance from the reference point and the angle between the specified direction and item's location is taken into consideration.

Element States in Interactions

During a user interaction or as a result of a user interaction, a graph element can take on different "states." There are three kinds of states, each indicated to the user by some visual decoration to a graph element:

  • Selection One or more elements can be selected at a time. Typically, an element is selected by clicking on it, using a marquee selection multiple elements can be selected at once. By default, a selected element is indicated using a checked border around it as the decoration.
  • Focus Only one element at a time can be focused. The focused element is the CurrentItem of the graph. A node can become focused after selecting it and then clicking on another UIElement in the window. The selection indication goes away, but the focus stays. By default, a focused element is indicated using a thin dashed line around it as the decoration.
  • Highlight An arbitrary number of elements can be highlighted at a time. An element can become highlighted during a user interaction. For instance, when creating an edge, any node that is a valid target node for the edge becomes highlighted when the yet unconnected edge end is over it. Highlight decorations for graph elements depend on the interaction gesture and the element to highlight.

Typically, highlighting an element is only a short-lived visual decoration that an input mode adds to indicate to the user some temporary special state of the element during the specific interaction gesture.

The visual decorations that are used to indicate an element's state can be customized as described in the section called “Customizing User Interaction Behavior”. They are managed by the ModelManager implementation classes SelectionPaintManager<T>, FocusPaintManager<T>, and HighlightPaintManager<T>, respectively. To prevent any selection, focus, or highlight indications, each of these managers can be disabled.

Interaction Events

GraphEditorInputMode and its minor modes provide fine-grained events that are fired upon user interactions. The events serve as callbacks to enable direct notification of any changes to the graph.

Note that these events are only fired due to direct user interaction with a graph. They are neither repeated during undo/redo operations nor are they fired due to programmatic changes to a graph or during graph I/O.

Table 4.24. GraphEditorInputMode-related events

Input Mode Event Name Description
GraphEditorInputMode NodeCreated Occurs when this mode has created a node in response to user interaction.
DeletedItem Occurs when an item has been deleted interactively by this mode.
ItemClicked, ItemLeftClicked, and ItemRightClicked Occurs when an item (node, edge, bend, label, port) has been (left/right) clicked. Corresponding events are available to cover double (left/right) clicks.
ItemSelected An event that will be triggered if an item changed its selection state from unselected to selected. Fired by the input mode's SelectionModel.
ItemDeselected An event that will be triggered if an item changed its selection state from selected to unselected. Fired by the input mode's SelectionModel.
MultiSelectionStarted An event that will be triggered if a single-select or multi-select operation has been started.
MultiSelectionFinished An event that will be triggered if a single-select or multi-select operation has been finished.
PopulateItemContextMenu Occurs when the context menu over an item (node, edge, bend, label, port) is about to be opened to determine the contents of the menu.
QueryItemToolTip Occurs when the mouse is hovering over an item (node, edge, bend, label, port) to determine the tool tip to display.
ValidateLabelText Event that can be used to validate the text of a label.
CreateEdgeInputMode EdgeCreated Event that is triggered after an edge has been created.
EdgeCreationStarted Occurs when the edge creation has started.
CreateBendInputMode BendCreated The event that will be triggered once a bend creation gesture has been recognized.
ClickInputMode Clicked and DoubleClicked The event handler that will be triggered once a (double) click has been detected.
TapInputMode Tapped and DoubleTapped The event handler that will be triggered once a (double) tap has been detected.
MoveInputMode DragStarted Event that will be triggered once the drag is initialized and has started.
Dragging Event that will be triggered for every drag.
DragFinished Event that will be triggered once the drag has been finished.
DragCanceled Event that will be triggered when the drag has been canceled.
HandleInputMode DragStarted Event that will be triggered once the drag is initialized and has started. Indicates a resize, bend move, etc. gesture, based on the type of handle.
Dragging Event that will be triggered for every drag. Indicates a resize, bend move, etc. gesture, based on the type of handle.
DragFinished Event that will be triggered once the drag has been finished. Indicates a resize, bend move, etc. gesture, based on the type of handle.
DragCanceled Event that will be triggered when the drag has been canceled. Indicates a resize, bend move, etc. gesture, based on the type of handle.
MarqueeSelectionInputMode MarqueeSelected An event that will be triggered once the marquee selection has been finished.
MouseHoverInputMode QueryToolTip Occurs when this mode queries the tool tip for a certain query location.
ContextMenuInputMode PopulateContextMenu An event that will be triggered when the context menu is about to be shown.
TextEditorInputMode TextEdited Triggered once the text has been edited.
NodeDropInputMode NodeCreated Fired when a new node gets created by a drag'n'drop gesture.
ItemHoverInputMode HoveredItemChanged Occurs when the item (node, edge, bend, label, port) that the mouse is hovering over changes.

Interaction Customization

Class GraphEditorInputMode provides various properties and callbacks that allow for fine-grained control over the editing functionality. For example, for certain kinds of editing gestures the set of graph element types that the input mode may act upon can be restricted to a specific subset of the available types.

Table 4.25, “GraphEditorInputMode customization” lists the customization properties of class GraphEditorInputMode. Most of the properties support that combinations of graph element types can be specified using the constants defined in the GraphItemTypes enumeration type.

Table 4.25. GraphEditorInputMode customization

Name Purpose
LabelEditingAllowed Whether interactive label editing is allowed. If set to true, label editing is triggered by the F2 key by default.
NodeCreationAllowed Whether the user is allowed to create nodes.
SelectableItems A combination of GraphItemTypes that specifies the set of graph element types that can be selected by the user.
MarqueeSelectableItems A combination of GraphItemTypes that specifies the set of graph element types that can be selected using the marquee selection tool.
ClickSelectableItems A combination of GraphItemTypes that specifies the set of graph element types that can be selected by mouse clicks/finger taps.
ClickableItems A combination of GraphItemTypes that specifies the set of graph element types that can be clicked/tapped by the user.
ShouldBeClicked Callback that determines whether the given model item may be clicked/tapped.
FocusableItems A combination of GraphItemTypes that specifies the set of graph element types that can have focus.
VoidStylesIgnored A boolean property that controls whether graph elements with void styles can be selected/focused using the keyboard or by using "Select all".
ShowHandleItems A combination of GraphItemTypes that specifies the set of graph element types that should show resize handles when selected.
ShouldShowHandles Callback that determines whether resize handles should be shown for the given model item.
DeletableItems A combination of GraphItemTypes that specifies the set of graph element types that will be deleted when the Delete key is pressed.
ShouldBeDeleted Callback that determines whether the given model item may be deleted.
MovableItems A combination of GraphItemTypes that specifies the set of graph element types that can be moved by the user.
ShouldBeMovable Callback that determines whether the given model item may be moved.

Example 4.34, “Using the GraphItemTypes constants” shows how to use the GraphItemTypes constants to customize a GraphEditorInputMode instance.

Example 4.34. Using the GraphItemTypes constants

// 'geim' is of type GraphEditorInputMode.

// Do not show resize handles for any graph elements.
geim.ShowHandleItems = GraphItemTypes.None;

// Only allow deletion of nodes and edges.
geim.DeletableItems = GraphItemTypes.Node | GraphItemTypes.Edge;

Interactive Editing of Orthogonal Edges

Support for orthogonal edge paths is an invaluable aid to a user for manual creation of orthogonal edge paths, but even more for maintaining orthogonal edge paths during manual editing operations. Without this support, moving a node can easily destroy orthogonality of incident edges thereby making a mess out of a once beautiful diagram.

GraphEditorInputMode, together with the specialized input modes it makes available, provides special support for orthogonal edge paths. Specifically, the following edge-related mouse gestures offer specialized behavior for this kind of paths:

  • edge creation (CreateEdgeInputMode, see below)
  • moving (orthogonal) edge segments and creating new bends/edge segments
  • moving the ports of an edge

Additionally, the following mouse gestures, which have an impact on edge paths, too, also offer specialized behavior:

  • resizing nodes
  • moving selected nodes/bends

To enable the support for orthogonal edge paths, an OrthogonalEdgeEditingContext can be set with GraphEditorInputMode by means of the following property:

OrthogonalEdgeEditingContext OrthogonalEdgeEditingContext { get; set; }
Description Convenience property for setting the orthogonal edge editing context and enabling support for orthogonal edge paths.

Support for orthogonal edge creation can be enabled independently on CreateEdgeInputMode using the following property:

bool OrthogonalEdgeCreation { get; set; }
Description Enables/disables orthogonal edge path support when creating an edge.

With the exception of CreateEdgeInputMode, class OrthogonalEdgeEditingContext handles orthogonal edge editing of all edges across the involved input modes. The actual edge editing behavior can be controlled using the following properties:

bool OrthogonalEdgeEditing { get; set; }
Description Enables/disables orthogonal edge path support.
bool MovePorts { get; set; }
Description Determines whether the source port (target port) should move along with the first (last) bend to retain orthogonality of the first (last) edge segment.

Individual edge editing behavior can be achieved by decorating the look-up of edges to return a custom IOrthogonalEdgeHelper implementation when this type is queried. Tutorial demo application OrthogonalEdgesWindow demonstrates this scheme.

Interactive Snapping of Graph Elements

Interactive snapping of graph elements supports a user in the manual creation of a diagram or when manually re-arranging a diagram. It greatly reduces the time for properly aligning graph elements and helps getting clear and concise diagrams where nodes are equally distant from each other. Also, it simplifies retouching edges and helps getting orthogonal edge paths almost instantly.

Class GraphEditorInputMode, together with the specialized input modes it makes available, comes with optional support for interactive snapping of graph elements. It provides visual and "perceptible" feedback during a mouse drag gesture when graph elements

  • are aligned (top, bottom, left, right, middle),
  • are equidistant,
  • have the same width/height, or
  • have some specified distances from each other.

Specifically, the following mouse gestures offer specialized behavior:

Figure 4.32, “Visual feedback during mouse drag gestures with snapping support enabled” illustrates the visual feedback that is given during mouse drag gestures.

Figure 4.32. Visual feedback during mouse drag gestures with snapping support enabled

Visual feedback.
Visual feedback.
Visual feedback.
Two nodes aligned at their center coordinates (moving a node). Equidistant between two nodes (moving a node). Same widths (resizing a node).

During a mouse drag gesture, the "perceptible" feedback can be experienced as

  • a small movement of the dragged element(s) towards a coordinate where they are aligned and
  • a short adherence to the current coordinate when dragging away from an aligned location.

We call such "aligned coordinates" snap lines even if their visualization is more complex than a simple straight line.

The interactive snapping of graph elements can be conveniently enabled on class GraphEditorInputMode by setting a GraphSnapContext using the following property:

SnapContext SnapContext { get; set; }
Description Property for setting the snap context and enabling snapping support.

By default, snapping support then covers alignment, equidistance, and same node widths/heights, for example. Note that the snapping of labels to their respective owner is enabled and configured separately with class LabelSnapContext. This is described below in more details.

Further customization, like setting preferred distances between graph elements, can be done through properties of GraphSnapContext:

To conveniently adjust the visual feedback, custom resources can be registered using ResourceKeys. For instance, the color of all types of snap lines can be adjusted using SnapLineColorKey:

<SolidColorBrush x:Key="{x:Static GraphInput:SnapLine.SnapLineColorKey}" 
                 Color="Green"/>

The visualizations for equidistance, same node widths, etc. are covered by SnapLineEqualDistanceBetweenBoundsKey, SnapLineEqualWidthKey, and other ResourceKeys in class SnapLine that register <Style> resources.

Class GraphSnapContext handles interactive snapping of graph elements across the involved input modes. Technically, when a drag gesture is recognized, GraphSnapContext determines fixed and moved graph elements and queries the look-up of the former for implementations of interface ISnapLineProvider to collect possible snap lines. The look-up of the latter set of graph elements gets queried for implementations of snap result providers, which enable selection of "matching" snap lines from the set of collected possible snap lines. See also Table 4.29, “User gestures and interfaces implementations in the look-up”.

Customizing the interactive snapping behavior beyond the GraphSnapContext properties can be done by decorating the look-up of model items to return custom implementations of snap line providers and/or snap result providers. Tutorial demo application CustomSnappingWindow shows how custom variants of both snap line and snap result providers can be added using the decorator scheme.

Customizing interactive snapping behavior during edge creation can be done by overriding the following method in CreatedEdgeInputMode:

GraphSnapContext also supports snapping of graph elements to a grid. The following properties can be used to set IGridConstraintProvider<T> implementations for model items in order to control their grid snapping behavior:

Example 4.35, “Enabling grid snapping” shows the setup for grid snapping support from tutorial demo application SnapLinesWindow. The GridInfo class conveniently holds the properties of a grid, such as spacing and origin.

Example 4.35. Enabling grid snapping

// 'gc' is of type yWorks.yFiles.UI.GraphControl.

// Grid visual representation.
GridVisualCreator grid = new GridVisualCreator(30, 30);
ICanvasObject gridDescriptor = gc.Add(
    grid, CanvasObjectDescriptor.DynamicDirtyInstance, gc.BackgroundGroup);
gridDescriptor.Dirty = true;

// Enabling grid snapping for nodes and bends.
GraphSnapContext snapContext = new GraphSnapContext();
snapContext.NodeGridConstraintProvider =
    new SimpleGridConstraintProvider<INode>(30, 30);
snapContext.BendGridConstraintProvider =
    new SimpleGridConstraintProvider<IBend>(30, 30);

// Enabling snapping for graph elements.
GraphEditorInputMode graphEditorInputMode = new GraphEditorInputMode();
graphEditorInputMode.SnapContext = snapContext;

gc.InputModes.Add(graphEditorInputMode);
Snapping of Labels

In addition to the general snapping of graph items described above, some label models support snapping of labels. Typically, these are the models that allow free interactive placement and therefore don't show label candidate positions during movements. To allow users to position labels at properly aligned positions nevertheless, these label models support the snapping of labels to snap lines. By default, these snap lines can be

  • orthogonal to the label's initial position (with respect to its rotation angle),
  • aligned with the center or the border of its node,
  • at the same distance from the border of its node as its initial position, as another label of this node, or as a label of any other node,
  • on the path of its edge,
  • at the same distance from the line segments of its edge as its initial position, as another label of this edge, or as a label of any other edge.

Label snapping is supported by the label models FreeNodeLabelModel, SmartEdgeLabelModel, and FreeEdgeLabelModel.

The behavior of label snapping during user interaction is very similar to the general snapping. Since its suitable configuration settings and snap lines are different, it has to be enabled separately. You can enable and configure it by setting an instance of LabelSnapContext to the property LabelSnapContext of the GraphEditorInputMode.

Tutorial Demo Code

The following tutorial demo applications present both setup as well as customization of interactive snapping support:

Edge-to-Edge Connections

Interactive creation of a new edge is handled by input mode class CreateEdgeInputMode. This input mode also provides support for edge-to-edge connections, which can be enabled with the following property:

In addition to enabling the support, it is also necessary that any edges that shall be available for other edges to connect to, return appropriate IPortCandidateProvider implementations in their look-up. Tutorial demo application EdgeToEdgeWindow presents this scheme with port candidates generated using port location models that provide port locations along an edge path.

Note

Edge-to-edge connections are not supported by automatic layout algorithms. Before a layout algorithm is invoked, any edge-to-edge connection in a given IGraph is replaced by CopiedLayoutIGraph/LayoutGraphAdapter using a dummy node.

Edge-to-edge connections are also not supported in folding-enabled graphs.

Class GraphCommands

The GraphCommands class makes available a number of commands that can be used for WPF-like command binding from sources like, e.g., buttons in the UI, or model items, like, e.g., nodes. The provided commands cover selection and deselection of model items (particularly nodes and edges), as well as label editing and regrouping of nodes in graph.

The commands rely on a commanding infrastructure very similar in concept and usage to that present in Windows Presentation Foundation. The classes that make up this support are CommandManager, CommandBinding, and RoutedCommand from the yWorks.Support.Windows namespace. Together, they realize the command pattern and the necessary command binding support for WPF-like commands in yFiles for Silverlight.

Example 4.36, “Command binding in XAML” shows the XAML definition for a command binding that connects a button to the label editing command provided by GraphCommands.

Example 4.36. Command binding in XAML

<Button Command="{x:Static y:GraphCommands.EditLabelCommand}" 
        Content="Edit" CommandParameter="{Binding Label}"/>

Table 4.26, “GraphCommands commands” lists the commands available with class GraphCommands.

Table 4.26. GraphCommands commands

Command Name Description
SelectItemCommand Sets the selection state of a model item. The model item is given by means of the command parameter.
ToggleItemSelectionCommand Changes the selection state of a model item. The model item is given by means of the command parameter.
DeselectItemCommand Resets the selection state of a model item. The model item is given by means of the command parameter.
DeselectAllCommand Resets the selection state of all currently selected model items.
EditLabelCommand Begins editing the text of a label. The label is given by means of the command parameter.
GroupSelectionCommand Creates a new group node that contains all currently selected nodes.
UngroupSelectionCommand Regroups all currently selected nodes from their respective group nodes into the root graph.
BeginEdgeCreationCommand Begins creating an edge. The command parameter needs to hold either an INode, an IPort, or an IPortCandidate object that is used as the source for the edge.

By default, the BeginEdgeCreationCommand command is used for command binding by CreateEdgeInputMode, all other commands are used for command binding by GraphEditorInputMode. The commands are bound upon installation, and are unbound when the respective input mode is uninstalled.

Class MainInputMode

Class MainInputMode defines a powerful basis for controller implementations that need to handle a broad range of user gestures happening in the view. It makes available the functionality of a set of specialized input modes that are installed concurrently with the canvas.

In particular, through its input modes, MainInputMode transparently supports both mouse-based gestures and touch gestures.

Figure 4.33. MainInputMode type hierarchy

MainInputMode type hierarchy.

The direct base type of class MainInputMode is MultiplexingInputMode, an input mode that enables input modes to be installed with the canvas and be executed concurrently. As part of the concurrency amongst these input modes, MultiplexingInputMode can grant an input mode exclusive control over all canvas interaction.

Input modes that support concurrency are of type IConcurrentInputMode and are also referred to as "concurrent input modes." They can be added to the set of input modes that are managed by MultiplexingInputMode by means of the following methods:

void AddConcurrent(IConcurrentInputMode inputMode)
void AddConcurrent(IConcurrentInputMode inputMode, int priority)
Description Adding concurrent input modes to a MultiplexingInputMode's concurrency controller.

Note that MultiplexingInputMode itself is also a concurrent input mode. This allows, for example, to have several full-featured, however differently configured, MainInputMode instances installed side by side.

Input Mode Priorities

MultiplexingInputMode also introduces the notion of priority with the input modes it installs into the canvas. The priority value of an input mode determines when it is installed, which in turn defines its position in the queue of input modes that are delivered user events. A low priority value means that an input mode comes early in this queue and thus processes an event prior to other input modes with a higher priority value that are also registered with that event.

Upon initialization, MainInputMode creates and installs the input modes listed in Table 4.27, “Input modes used by MainInputMode (sorted by input mode priority)” as concurrent input modes. Note that the input modes are sorted according to their priority.

Table 4.27. Input modes used by MainInputMode (sorted by input mode priority)

Type Name Description
WaitInputMode Blocks user interaction and tries to cancel ongoing edits.
KeyboardInputMode Recognizes key events.
ClickInputMode Recognizes mouse clicks, including double clicks.
TapInputMode Provides touch support, recognizes taps and double taps.
MoveInputMode Handles moving of canvas objects.
MarqueeSelectionInputMode Provides the visual feedback for a rectangular selection box in the canvas.
HandleInputMode Manages the dragging of "handles," including the detection of beginning and ending of a drag, and canceling a drag. Also provides the visual feedback for handles when dragged.
MoveViewportInputMode Handles panning the viewport, i.e., enables the currently visible part of the canvas to be dragged around.
ContextMenuInputMode Enables displaying context menus. See also below.
MouseHoverInputMode Displays a tooltip when the mouse rests in the canvas.

Each of the input modes can be obtained and changed using a like-named property defined by class MainInputMode. Also, a sorted list of input modes can be obtained by means of the GetSortedModes method.

Class MoveViewportInputMode

Class MoveViewportInputMode enables moving of the viewport by means of a simple mouse move gesture.

GraphEditorInputMode and GraphViewerInputMode by default carry an instance of MoveViewportInputMode that manages moving of the viewport.

Customizing Input Modes

The behavior of input modes can be easily customized by means of their properties, using custom callback methods, or by replacing specialized input modes by customized implementations thereof.

For example, to customize the text of the tooltip that is displayed by MouseHoverInputMode when the mouse hovers over an item, a delegate can be registered with the QueryItemToolTip event.

Example 4.37. Registering a delegate that provides text for the tooltips displayed by MouseHoverInputMode

// 'geim' is of type yWorks.yFiles.UI.Input.GraphEditorInputMode.

geim.QueryItemToolTip +=
  delegate(object src, QueryItemToolTipEventArgs<IModelItem> eventArgs) {
    if (eventArgs.Handled) {
      // A tooltip has already been assigned -> nothing to do.
      return;
    }

    if (eventArgs.Item is ILabeledItem) {
      ILabeledItem item = eventArgs.Item as ILabeledItem;
      if (item.Labels.Count > 0) {
        // Set the tooltip.
        eventArgs.ToolTip =
          "Text of first label is: '" + item.Labels[0].Text + "'";
        eventArgs.Handled = true;
      }
    }
    else if (eventArgs.Item is ILabel) {
      ILabel label = eventArgs.Item as ILabel;
      // Set the tooltip.
      eventArgs.ToolTip = "Directly over label: '" + label.Text + "'";
      eventArgs.Handled = true;
    }
  };

If needed, the visualization of the tooltip itself can be adjusted using a custom <DataTemplate> resource that is registered with the ResourceKey ToolTipTemplateKey.

The context menu that is displayed by ContextMenuInputMode can be specified as a whole using the Menu property, for example. Alternatively, the actual content of a menu can also be given dynamically by means of a callback registered with the PopulateContextMenu event. The latter is used in the following tutorial demo applications:

Note

Since the core Silverlight SDK provides no support for context menus, the yFiles for Silverlight demos use the context menu implementation from the Microsoft Silverlight Toolkit Codeplex project. Generally, however, ContextMenuInputMode should work with any 3rd party context menu implementation as well.

Customizing User Interaction Behavior

Input modes that handle specific mouse gestures when a user interacts with the graph elements often either directly or indirectly use the look-up mechanism to query additional information in relation to the respective gesture. This information generally also affects the look and feel of the elements, i.e., the rendering and the behavior of graph elements whenever a user is interacting with them.

To conveniently adjust the default visual decorations that indicate the selected, focused, or highlighted state of graph elements, the following alternatives are supported:

For instance, a DataTemplate resource like in the following example modifies the selection color of nodes:

Example 4.38. Customizing the selection color of node selections

<!-- The value of the Key attribute is constructed from the fully qualified name 
     of a static field according to the following scheme:
  1) the namespace of the class that defines the static field with dots ('.') 
     replaced by underscores ('_')
  2) a colon (':')
  3) the name of the class
  4) a dot ('.')
  5) the name of the field
-->
<DataTemplate x:Key="yWorks_Canvas_Drawing:RectangularSelectionPaintable.TemplateKey">
  <Border BorderBrush="Yellow" BorderThickness="4"/>
</DataTemplate>

For a description of the selected, focused, and highlighted state of graph elements, see also the section called “Element States in Interactions”.

Table 4.28. Predefined ResourceKeys for customization of visual decorations

Decoration ResourceKeys
Selection RectangularSelectionPaintable.TemplateKey (INode); EdgeSelectionRenderer.PenKey (the Pen of an IEdge), EdgeSelectionRenderer.BendTemplateKey (how IBends of a selected edge are visualized); OrientedRectangleSelectionPaintable.TemplateKey (ILabel)
SelectedStripeTemplateKey (IStripe)
MarqueeSelectionInputMode.MarqueeRectangleTemplateKey (marquee rectangle)
HandleDrawingInvisibleKey, HandleDrawingResizeKey, HandleDrawingMoveKey, and similar ResourceKeys in input mode class HandleInputMode can be used to adjust the visualization of handles
Focus RectangularFocusPaintable.TemplateKey (INode); EdgeFocusIndicatorRenderer.PenKey (the Pen of an IEdge), EdgeFocusIndicatorRenderer.BendTemplateKey (how IBends of a focused edge are visualized); OrientedRectangleFocusPaintable.TemplateKey (ILabel)
CandidateDrawingValidFocusedKey and CandidateDrawingInvalidFocusedKey (how port candidates are visualized); similar ResourceKeys are available for non-focused port candidates
Highlight RectangularHighlightPaintable.TemplateKey (INode); EdgeHighlightRenderer.PenKey (the Pen of an IEdge), EdgeHighlightRenderer.BendTemplateKey (how IBends of a highlighted edge are visualized); OrientedRectangleHighlightPaintable.TemplateKey (ILabel)
LabelPositionHandler.CandidateTemplateKey (how rectangles that indicate label candidates are visualized), LabelPositionHandler.HighlightTemplateKey (how the rectangle of the currently active label candidate is visualized)
ResizeStripeTemplateKey, DragSourceStripeTemplateKey, and DropTargetStripeTemplateKey (IStripe)

The wrapper classes NodeStyleDecorationInstaller, EdgeStyleDecorationInstaller, and LabelStyleDecorationInstaller enable convenient decoration of the look-up for user gestures that change the selected, focused, or highlighted state of graph elements. The classes can be used to install proper INodeStyle, IEdgeStyle, and ILabelStyle implementations, respectively, that render the visual decoration to indicate the respective state of the graph elements.

Along the lines of Example 4.40, “Decorating the look-up for nodes”, installing a node style via the NodeStyleDecorationInstaller wrapper class for rendering the selection indication of nodes looks like:

Example 4.39. Installing a node style via a convenience wrapper for rendering the selection indication of nodes

var nodeDecorationInstaller = 
    new NodeStyleDecorationInstaller {
        NodeStyle = new ShapeNodeStyle(ShapeNodeShape.Rectangle, 
                                       Pens.DeepSkyBlue, 
                                       Brushes.Transparent), 
        Margin = new InsetsD(4.0), 
      };

decorator.Add<INode, ISelectionInstaller>(node => nodeDecorationInstaller);

The SelectionStylingDemo demo application shows how these wrapper classes can be used to decorate the selection indication of nodes, edges, and labels.

Decorating the Look-up

By decorating the look-up, further customizations of the look and feel of an application are possible. For instance, the resizing behavior of nodes can be changed to obey only discrete steps, simply by adding appropriate interface implementations to the look-up mechanism.

Example 4.40, “Decorating the look-up for nodes” shows how the look-up for nodes is decorated using the ILookupDecorator returned by the graph. A custom look-up chain link, which replaces the default look-up logic for nodes, is added to the look-up chain that is maintained by the graph. Whenever a node gets selected, the new logic then returns a custom ISelectionInstaller implementation.

More information on the look-up support provided by the graph structure implementation can be found in the section called “Look-up Support”.

Example 4.40. Decorating the look-up for nodes

// 'graph' is of type yWorks.yFiles.UI.Model.IGraph.

// Decorate the look-up for nodes to change their default behavior.
ILookupDecorator decorator = graph.Get<ILookupDecorator>();
decorator.Add<INode, ISelectionInstaller>(
  node => new MyCustomSelectionInstaller()
);

Table 4.29, “User gestures and interfaces implementations in the look-up” gives an overview on the interface implementations that are queried when certain user gestures are handled.

Table 4.29. User gestures and interfaces implementations in the look-up

Gesture Type Name Description
Edge creation IPortCandidateProvider Returns collections of ports that an edge can connect to. When a new edge is created, CreateEdgeInputMode queries the look-up of the source node and any possible target node/edge that the mouse hovers over for implementations of this interface.

Implementations of this interface include: ExistingPortsCandidateProvider (by default in the look-up for IEdge instances), EmptyPortsCandidateProvider, NodeCenterPortCandidateProvider, UnoccupiedPortsCandidateProvider, PortCandidateProvider, and ShapeGeometryPortCandidateProvider.

Abstract class AbstractPortCandidateProvider is a convenience implementation of this interface.

Resizing IReshapeHandler Enables handling the overall process of resizing a model item (INode).
IReshapeHandleProvider Offers control over the resize behavior for a model item that is displayed in the canvas. When a model item (INode) gets resized, HandleInputMode queries the item's look-up for implementations of this interface.

Class ReshapeableHandles is a convenience implementation of this interface.

ISizeConstraintProvider<T> Enables definition of minimum and maximum size constraints for items of the given type T. In a grouped graph, the size of group nodes is affected by implementations of this interface.

Class SizeConstraintProvider<T> is a convenient default implementation that allows to specify minimum and maximum size constraints for items of the given type T. This type is in the look-up for non-leaf nodes in a grouped graph.

ISnapLineProvider Adds possible snap lines for a model item. When interactive snapping support is enabled (i.e., when GraphSnapContext is available in the input mode context), GraphSnapContext queries the look-up of all model items (INode, IEdge, IPort) that do not get resized for an implementation of this interface. The gathered information is then filtered to include only those of visible model items.

Implementations of this interface include: NodeSnapLineProvider (by default in the look-up for INode instances) and EdgeSnapLineProvider (by default in the look-up for IEdge instances).

INodeReshapeSnapResultProvider Enables selection of "matching" snap lines from the set of collected possible snap lines. When interactive snapping support is enabled, GraphSnapContext queries the look-up of all nodes that get resized for implementations of this interface.
IOrthogonalEdgeHelper Offers control over orthogonal edge editing behavior. When orthogonal edge editing is enabled (i.e., when OrthogonalEdgeEditingContext is available in the input mode context), OrthogonalEdgeEditingContext queries the look-up of all edges incident to nodes that get resized for an implementation of this interface.

Class OrthogonalEdgeHelper is a convenient default implementation of this interface.

Selecting ISelectionInstaller Allows to install any number of ICanvasObject instances that make up the selection decoration for a model item that is displayed in the canvas. Whenever a model item gets selected, its look-up is queried by the SelectionPaintManager for implementations of this interface.

Implementations of this interface include: OrientedRectangleSelectionPaintable (by default in the look-up for ILabel instances), RectangularHighlightPaintable, and RectangularSelectionPaintable (by default in the look-up for INode instances).

The wrapper classes NodeStyleDecorationInstaller, EdgeStyleDecorationInstaller, and LabelStyleDecorationInstaller also implement this interface.

Highlighting, changing focus IFocusIndicatorInstaller and IHighlightInstaller Enable installation of any number of ICanvasObject instances that make up the focus, respectively highlight decoration for a model item that is displayed in the canvas. Whenever a model item becomes focus, its look-up is queried by the FocusPaintManager for IFocusIndicatorInstaller implementations. Similarly, whenever a model item is highlighted, its look-up is queried by the HighlightPaintManager for IHighlightInstaller implementations.

Implementations of both these interfaces include: OrientedRectangleSelectionPaintable (by default in the look-up for ILabel instances), RectangularHighlightPaintable, and RectangularSelectionPaintable (by default in the look-up for INode instances).

The wrapper classes NodeStyleDecorationInstaller, EdgeStyleDecorationInstaller, and LabelStyleDecorationInstaller also implement both these interfaces.

Edge reconnecting, port relocating IEdgePortCandidateProvider Returns collections of ports that an edge can connect to. When either end of an edge gets relocated, the look-up of the edge is queried for implementations of this interface.

Implementations of this interface include: DefaultEdgePortsCandidateProvider (by default in the look-up for IEdge instances), CurrentEdgePortsCandidateProvider, and AllCandidatesEdgePortCandidateProvider.

ISnapLineProvider Adds possible snap lines for a model item. When interactive snapping support is enabled (i.e., when GraphSnapContext is available in the input mode context), GraphSnapContext queries the look-up of all model items (INode, IEdge, IPort) that do not get moved for an implementation of this interface. The gathered information is then filtered to include only those of visible model items.

Implementations of this interface include: NodeSnapLineProvider (by default in the look-up for INode instances) and EdgeSnapLineProvider (by default in the look-up for IEdge instances).

IPortSnapResultProvider Enables selection of "matching" snap lines from the set of collected possible snap lines. When interactive snapping support is enabled, GraphSnapContext queries the look-up of the ports for implementations of this interface.
Moving IPositionHandler Inherits from interface IDragHandler which provides callback methods that allow to control all parts of a mouse drag gesture. When a model item (INode, IPort, IBend, ILabel) gets moved, MoveInputMode and MoveLabelInputMode query the item's look-up for implementations of this interface.

Class DefaultPositionHandler is a convenient default implementation of this interface.

ISnapLineProvider Adds possible snap lines for a model item. When interactive snapping support is enabled (i.e., when GraphSnapContext is available in the input mode context), GraphSnapContext queries the look-up of all model items (INode, IEdge, IPort) that do not get moved for an implementation of this interface. The gathered information is then filtered to include only those of visible model items.

Implementations of this interface include: NodeSnapLineProvider (by default in the look-up for INode instances) and EdgeSnapLineProvider (by default in the look-up for IEdge instances).

INodeSnapResultProvider, IEdgeSnapResultProvider, and IBendSnapResultProvider Enable selection of "matching" snap lines from the set of collected possible snap lines. When interactive snapping support is enabled, GraphSnapContext queries the look-up of all model items (INode, IEdge, IBend) that get moved for implementations of the corresponding interface.
Moving an edge segment (orthogonal edge editing) IOrthogonalEdgeHelper Offers control over orthogonal edge editing behavior. When orthogonal edge editing is enabled (i.e., when OrthogonalEdgeEditingContext is available in the input mode context), OrthogonalEdgeEditingContext queries the look-up of all edges where segments get moved for an implementation of this interface.

Class OrthogonalEdgeHelper is a convenient default implementation of this interface.

Customization of the re-parenting gesture in a grouped graph, which can be controlled using interface IReparentNodeHandler, is described in the section called “Class GraphEditorInputMode”.

Further examples that show how the look and feel of items in the canvas can be customized are presented in the following tutorial demo applications: