How to extend the context menu inside the rehosted workflow designer?

1k views Asked by At

We are using a rehosted designer (currently WF 4.0) with a lot of custom activities, all of them have custom designers. For a bunch of them, I would like to add entries to the context menu of the designer when in design mode. I'm talking about this menu:

enter image description here

E.g. for a XAML coded activity I would like to have an "Open source..." entry which will load the XAML source of that specific activity into a new designer. To do that I must add the entry to the menu, and when clicked figure out on which activity it was clicked. Both parts are unclear to me. How can I achieve that?

In WF 3 there was the ActivityDesignerVerb class to do that. In WF 4 there seems to be workflowDesigner.Context.Services.Publish<ICommandService>(...), but I can't figure out how to use that to add a custom action to the context menu. How can I do that?

This SO entry shows something for internal debugger commands, but I want to add a completely new command.

2

There are 2 answers

0
Venemo On BEST ANSWER

Solving it in the host

If you want to solve this on the workflow designer host, and not in the individual activities, it's quite simple and straightforward to do this.

When you host the workflow designer and create the workflow designer, you can simply access its ContextMenu property and modify its Items collection.

var wfd = new WorkflowDesigner();
wfd.ContextMenu.Items.Add(new MenuItem() { Header = "Hello", Command = yourCommand, });

If you want different menu items for each activity, you can subscribe to the SelectionChanged event:

wfd.Context.Items.Subscribe<Selection>(SelectionChanged);

And then implement your own logic:

private void SelectionChanged(Selection selection)
{
    // Remove old menu item
    if (oldMenuItem != null)
    {
        wfd.ContextMenu.Items.Remove(oldMenuItem);
        oldMenuItem = null;
    }

    var modelItem = selection.PrimarySelection;

    if (selection.SelectionCount == 1 && modelItem != null)
    {
        // Get activity type
        var activityType = modelItem.ItemType;

        var menuItem = new MenuItem() { /* ... */ };
        wfd.ContextMenu.Items.Add(menuItem);
        oldMenuItem = menuItem;
    }
}

Solving it in the activity designer

If you want to always show a specific context menu item regardless of where your workflow designer UI is hosted, you can create a custom item in your activity designer XAML:

<sap:ActivityDesigner.ContextMenu>
    <ContextMenu>
        <MenuItem Header="Show" Command="{Binding YourCommand}"/>
    </ContextMenu>
</sap:ActivityDesigner.ContextMenu>
0
DotNetHitMan On

OK so all you need to do is implement the ICommand interface on your custom activity.

So, for example - expose a custom command property from the customer activity class, then in the constructor apply a delegate event to the command handler -

/// <summary>
/// Custom activity
/// </summary>
public partial class CustomActivityDesigner
{
    /// <summary>
    /// Command used to display a dialog at design time
    /// </summary>
    public ICommand ShowCustomDialog{ get; set; }

    public CustomSchedulerDesigner()
    {
        InitializeComponent();

        ShowCustomDialog= new DelegateCommand(x => 
            //Do some stuff here that will display your dialog
            //you may want to consider passing the `this.ModelItem`
            //to your dialog so it can then interact with the ModelTrees etc
            //for example
            var dialog = new MyDialog(this.ModelItem);
            dialog.ShowDialog();
        );
    }

}

Finally, hook the new command up to the UI via the activity designer xaml.

<sap:ActivityDesigner.ContextMenu>
    <ContextMenu>
        <MenuItem Header="Show" Command="{Binding ShowCustomDialog}"/>
    </ContextMenu>
</sap:ActivityDesigner.ContextMenu>