Context Menu Support for Stencil in WPF Diagram

18 Nov 201823 minutes to read

The Stencil ships with default context menu items that make common symbol actions easy to run.

Default Context Menu for Stencil

Enable or disable context menu items by toggling the ContextMenu flag on StencilConstraints. By default, context menu items such as Cut, Copy, and Paste are displayed.

  • C#
  • // Enable the context menu.
    stencil.StencilConstraints |= StencilConstraints.ContextMenu;
    
    // Disable the context menu.
    stencil.StencilConstraints &= ~StencilConstraints.ContextMenu;

    Default context menu on a Stencil symbol

    Properties

    Property Description Type Default
    Menu Context menu shown for symbols in the entire Stencil. DiagramMenu null
    SymbolGroupMenu Context menu applied to every Symbol Group in the Stencil. Overridden by SymbolGroupViewModel.Menu if set. DiagramMenu null
    DiagramMenuItem.Content Display text of the menu item. object null
    DiagramMenuItem.Icon Icon shown next to the menu item. object null
    DiagramMenuItem.Command ICommand invoked when the item is clicked. ICommand null
    DiagramMenuItem.CommandParameter Parameter passed to Command. object null
    DiagramMenuItem.IsSeparator When true, renders the item as a horizontal divider instead of a clickable entry. bool false

    Built-in commands

    Use the built-in StencilCommands for the default symbol actions:

    Command Description
    StencilCommands.Cut Cuts the selected symbols from the Symbol Group.
    StencilCommands.Copy Copies the selected symbols to the clipboard.
    StencilCommands.Paste Pastes the clipboard symbols into the Symbol Group.
    StencilCommands.Delete Deletes the selected symbols.

    Custom Context Menu for Stencil

    Add extra menu items to stencil symbols by using the Menu property of the Stencil class. Define the additional menu items and add them to the MenuItems collection.

    The custom menu items have the following properties:

    Property Description
    Content Sets the display text of the menu item.
    Icon Sets the icon shown next to the menu item.
    Command Defines the command invoked when the item is clicked.
    CommandParameter Defines the parameter passed to the command.
    IsSeparator When true, renders the item as a horizontal divider instead of a clickable menu entry.

    The following example defines a custom context menu for the Stencil. The Rename command is implemented with a simple RelayCommand because there is no built-in StencilCommands.Rename.

  • C#
  • using System.Collections.ObjectModel;
    using System.Windows.Input;
    using Syncfusion.UI.Xaml.Diagram;
    using Syncfusion.UI.Xaml.Diagram.Stencil;
    
    public partial class MainWindow
    {
        // Simple ICommand implementation used by the Rename menu item.
        public ICommand RenameCommand { get; } = new RelayCommand(p => RenameSymbol(p));
    
        private static void RenameSymbol(object parameter)
        {
            // Rename logic here.
        }
    
        public MainWindow()
        {
            InitializeComponent();
    
            var diagram = new SfDiagram();
    
            var BasicStencil = new Stencil
            {
                ShowDisplayModeToggleButton = false,
                ShowSearchTextBox = false,
                ExpandMode = ExpandMode.All,
                Constraints = StencilConstraints.Default | StencilConstraints.AllowDragDrop
            };
    
            BasicStencil.SymbolGroups = new SymbolGroups
            {
                new SymbolGroupProvider { MappingName = "Key" }
            };
    
            BasicStencil.Menu = new DiagramMenu
            {
                MenuItems = new ObservableCollection<DiagramMenuItem>
                {
                    new DiagramMenuItem
                    {
                        Content = "Cut",
                        Command = StencilCommands.Cut,
                        Icon = @"pack://application:,,,/Icons/Cut.png"
                    },
                    new DiagramMenuItem
                    {
                        Content = "Copy",
                        Command = StencilCommands.Copy,
                        Icon = @"pack://application:,,,/Icons/Copy.png"
                    },
                    new DiagramMenuItem
                    {
                        Content = "Paste",
                        Command = StencilCommands.Paste,
                        Icon = @"pack://application:,,,/Icons/Paste.png"
                    },
                    new DiagramMenuItem
                    {
                        Content = "Delete",
                        Command = StencilCommands.Delete,
                        Icon = @"pack://application:,,,/Icons/Delete.png"
                    },
                    new DiagramMenuItem
                    {
                        Content = "Rename",
                        Command = RenameCommand,
                        Icon = @"pack://application:,,,/Icons/Rename.png"
                    }
                }
            };
    
            BasicStencil.SymbolSource = new SymbolCollection
            {
                new NodeViewModel
                {
                    UnitWidth = 100,
                    UnitHeight = 100,
                    Shape = this.Resources["Ellipse"],
                    Key = "Basic Shapes"
                },
                new SymbolViewModel
                {
                    Symbol = "Diamond",
                    Key = "Basic Shapes",
                    SymbolTemplate = this.Resources["Diamond"] as DataTemplate
                }
            };
        }
    }

    Custom context menu on a Stencil symbol

    Custom Context Menu for Symbols in Stencil

    Define per-symbol menu items by setting Menu on each symbol. Right-click a symbol in the Stencil to open its context menu. Per-symbol menu items appear in addition to the Stencil-level Menu, not as a replacement.

  • C#
  • using System.Collections.ObjectModel;
    using Syncfusion.UI.Xaml.Diagram;
    using Syncfusion.UI.Xaml.Diagram.Stencil;
    
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
    
            BasicStencil.SymbolSource = new SymbolCollection
            {
                new NodeViewModel
                {
                    UnitWidth = 100,
                    UnitHeight = 100,
                    Shape = this.Resources["Ellipse"],
                    Key = "Basic Shapes",
                    Menu = new DiagramMenu
                    {
                        MenuItems = new ObservableCollection<DiagramMenuItem>
                        {
                            new DiagramMenuItem
                            {
                                Content = "Cut",
                                Command = StencilCommands.Cut,
                                Icon = @"pack://application:,,,/Icons/Cut.png"
                            }
                        }
                    }
                },
                new SymbolViewModel
                {
                    Symbol = "Diamond",
                    Key = "Basic Shapes",
                    SymbolTemplate = this.Resources["Diamond"] as DataTemplate,
                    Menu = new DiagramMenu
                    {
                        MenuItems = new ObservableCollection<DiagramMenuItem>
                        {
                            new DiagramMenuItem
                            {
                                Content = "Delete",
                                Command = StencilCommands.Delete,
                                Icon = @"pack://application:,,,/Icons/Delete.png"
                            }
                        }
                    }
                },
                new NodeViewModel
                {
                    UnitWidth = 100,
                    UnitHeight = 100,
                    Shape = this.Resources["Rectangle"],
                    Key = "Basic Shapes"
                }
            };
        }
    }

    Per-symbol custom context menu items

    View Sample in GitHub

    Context Menu for SymbolGroup in Stencil

    Use SymbolGroupViewModel.Menu to define a context menu for a specific Symbol Group. Use Stencil.SymbolGroupMenu to apply the same menu to every Symbol Group. When both are set, SymbolGroupViewModel.Menu takes precedence for that group.

    <Window x:Class="StencilSample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
            xmlns:stencil="clr-namespace:Syncfusion.UI.Xaml.Diagram.Stencil;assembly=Syncfusion.SfDiagram.WPF"
            Title="Symbol Group context menu" Height="600" Width="900">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="250"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
    
            <stencil:Stencil x:Name="stencil"
                             Grid.Column="0"
                             ExpandMode="ZeroOrMore"
                             BorderBrush="#dfdfdf" BorderThickness="1">
                <stencil:Stencil.SymbolGroups>
                    <stencil:SymbolGroups>
                        <stencil:SymbolGroupViewModel Name="Basic Shapes" CategorySource="{StaticResource BasicShapes}">
                            <stencil:SymbolGroupViewModel.Menu>
                                <syncfusion:DiagramMenu>
                                    <syncfusion:DiagramMenu.MenuItems>
                                        <syncfusion:DiagramMenuItem Content="Delete"
                                                                    Icon="pack://application:,,,/Images/Delete.png"/>
                                    </syncfusion:DiagramMenu.MenuItems>
                                </syncfusion:DiagramMenu>
                            </stencil:SymbolGroupViewModel.Menu>
                        </stencil:SymbolGroupViewModel>
                        <stencil:SymbolGroupViewModel Name="Flow Shapes" CategorySource="{StaticResource FlowShapes}"/>
                        <stencil:SymbolGroupViewModel Name="Arrow Shapes" CategorySource="{StaticResource ArrowShapes}"/>
                        <stencil:SymbolGroupViewModel Name="DataFlow Shapes" CategorySource="{StaticResource DataFlowShapes}"/>
                    </stencil:SymbolGroups>
                </stencil:Stencil.SymbolGroups>
                <stencil:Stencil.SymbolGroupMenu>
                    <syncfusion:DiagramMenu>
                        <syncfusion:DiagramMenu.MenuItems>
                            <syncfusion:DiagramMenuItem Content="Move Up"
                                                        Icon="pack://application:,,,/Images/ArrowUp.png"/>
                            <syncfusion:DiagramMenuItem Content="Move Down"
                                                        Icon="pack://application:,,,/Images/ArrowDown.png"/>
                        </syncfusion:DiagramMenu.MenuItems>
                    </syncfusion:DiagramMenu>
                </stencil:Stencil.SymbolGroupMenu>
            </stencil:Stencil>
    
            <syncfusion:SfDiagram x:Name="diagram" Grid.Column="1"/>
        </Grid>
    </Window>
    // Wire all groups to the same menu.
    stencil.SymbolGroupMenu = new DiagramMenu
    {
        MenuItems = new ObservableCollection<DiagramMenuItem>
        {
            new DiagramMenuItem { Content = "Move Up" },
            new DiagramMenuItem { Content = "Move Down" }
        }
    };

    SymbolGroup-level and Stencil-level menus combined

    View Sample in GitHub

    Troubleshooting

    Symptom Likely cause
    Icons do not appear The Icon URI cannot be resolved at runtime. Ensure the path is correct and the image file is included in the assembly (build action Resource, or use pack://application:,,,/... for embedded resources).
    Command does not fire The CommandParameter is wrong, or CanExecute returns false. Test by setting CommandParameter to a known value.
    A custom menu item does not appear The ContextMenu constraint was disabled. Re-enable StencilConstraints.ContextMenu.
    SymbolGroupViewModel.Menu is ignored Stencil.SymbolGroupMenu is also set and overrides it. Remove the Stencil-level menu or rely on the precedence rule above.

    See Also

    How to restrict the symbol dropping from the SymbolPalette?

    How to enable or disable Stencil symbols in WPF Diagram?

    How to refresh the stencil with a new collection or new symbol?