Adding MenuActions (think DesignerVerbs) to Cider's Right Click ContextMenu

[Attached a sample project that shows the setup for metadata assemblies as well as adds a couple of MenuActions] 

Now that you know how to add design time metadata vis Metadata Assemblies and how those Metadata Assemblies are found we can now move on to adding some extensibility features to your control.

Given a custom control, in this case, I'm just going to use a simple derived button:

    public class ButtonWithDesignTime : Button
    {
        public ButtonWithDesignTime()
        {
        }
    } 

When this ButtonWithDesignTime is loaded up in Cider and I right click on it, I want to add some items into the popup Context Menu so that it looks like this:

 

Where the SetBackground group and the Blue and Cleared items are the ones I added.

This menu items are called MenuActions and the grouping is called a MenuGroup.  These are classes in Cider's Microsoft.Windows.Design.Extensibility.dll under the Microsoft.Windows.Design.Interaction namespace.

The other class in the namespace and assembly that is going to help us is the PrimarySelectionContextMenuProvider class which is the class that you derive from to add MenuActions when your control is the primary selection and is right-clicked.

The implementation follows, you simply instantiate MenuActions, put them in a MenuGroup and add that MenuGroup to the Items property that is provided by the PrimarySelectionContextMenuProvider class you are deriving from.  Note that you can also add MenuActions directly to the Items collection.

    class CustomContextMenuProvider : PrimarySelectionContextMenuProvider
    {
        private MenuAction _SetBackgroundToBlueMenuAction = new MenuAction("Blue");
        private MenuAction _ClearBackgroundMenuAction = new MenuAction("Cleared");

        public CustomContextMenuProvider()
        {
            _SetBackgroundToBlueMenuAction.ImageUri = new Uri("pack://application:,,,/CustomControlLibrary.VisualStudio.Design;component/Images/live_logo.png", UriKind.Absolute);
            _SetBackgroundToBlueMenuAction.Execute += new EventHandler<MenuActionEventArgs>(SetBackgroundToBlue_Execute);

            _ClearBackgroundMenuAction.Execute += new EventHandler<MenuActionEventArgs>(ClearBackground_Execute);

            // Flyouts with actions
            MenuGroup backgroundFlyoutGroup = new MenuGroup("SetBackgroundsGroup", "Set Background");

            // if this is false, this group will not show up as a flyout but inline
            backgroundFlyoutGroup.HasDropDown = true;
            backgroundFlyoutGroup.Items.Add(_SetBackgroundToBlueMenuAction);
            backgroundFlyoutGroup.Items.Add(_ClearBackgroundMenuAction);
            this.Items.Add(backgroundFlyoutGroup);

            // Called right before this provider shows its tabs, opportunity to set states
            UpdateItemStatus += new EventHandler<MenuActionEventArgs>(CustomContextMenuProvider_UpdateItemStatus);
        }

        void CustomContextMenuProvider_UpdateItemStatus(object sender, MenuActionEventArgs e)
        {
                 // your opportunity to update state, make changes before your context menu items are shown
        }

        void ClearBackground_Execute(object sender, MenuActionEventArgs e)
        {
            ModelItem selectedControl = e.Selection.PrimarySelection;
            selectedControl.Properties[Control.BackgroundProperty].ClearValue();
        }

        void SetBackgroundToBlue_Execute(object sender, MenuActionEventArgs e)
        {
            ModelItem selectedControl = e.Selection.PrimarySelection;
            selectedControl.Properties[Control.BackgroundProperty].SetValue(Brushes.Blue);
        }
    }

 Now all you have to do is tie up this CustomContextMenuProvider to the ButtonWithDesignTime.  Since you already know how to add metadata, you simply have to do the following in your implementation of IRegisterMetadata:

            builder.AddCustomAttributes(typeof(ButtonWithDesignTime), new FeatureAttribute(typeof(CustomContextMenuProvider)));

Which is essentially:

[Feature(typeof(CustomContextMenuProvider))]
public class ButtonWithDesignTime {. . .}

Of course, as described in my metadata postings, you can't do that because that would require that you make references to the Cider assemblies from your runtime assembly.

MenuActionSample.zip