Share via


How to: Create a MenuAction

The following code example shows how to create a menu action for use in a design-time context menu. There is extensive support for this task in Visual Studio. For more information, see Walkthrough: Creating a MenuAction.

Example

The following code example shows how to create a design-time menu provider for a Windows Presentation Foundation (WPF) custom control. You can use this shortcut menu item to set the value of the Background property on a custom button control.

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.ComponentModel

Public Class ButtonWithDesignTime
    Inherits Button

    Public Sub New()
        ' The GetIsInDesignMode check and the following design-time  
        ' code are optional and shown only for demonstration. 
        If DesignerProperties.GetIsInDesignMode(Me) Then
            Content = "Design mode active" 
        End If 

    End Sub 
End Class
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.ComponentModel;

namespace CustomControlLibrary
{
    public class ButtonWithDesignTime : Button
    {
        public ButtonWithDesignTime()
        {
            // The GetIsInDesignMode check and the following design-time  
            // code are optional and shown only for demonstration. 
            if (DesignerProperties.GetIsInDesignMode(this))
            {
                Content = "Design mode active";
            }
        }
    }
}
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports Microsoft.Windows.Design.Interaction
Imports System.Windows
Imports Microsoft.Windows.Design.Model
Imports System.Windows.Controls
Imports System.Windows.Media

' The CustomContextMenuProvider class provides two context menu items 
' at design time. These are implemented with the MenuAction class. 
Class CustomContextMenuProvider
    Inherits PrimarySelectionContextMenuProvider

    Private setBackgroundToBlueMenuAction As MenuAction
    Private clearBackgroundMenuAction As MenuAction

    ' The provider's constructor sets up the MenuAction objects  
    ' and the the MenuGroup which holds them. 
    Public Sub New()

        ' Set up the MenuAction which sets the control's  
        ' background to Blue.
        setBackgroundToBlueMenuAction = New MenuAction("Blue")
        setBackgroundToBlueMenuAction.Checkable = True 
        AddHandler setBackgroundToBlueMenuAction.Execute, AddressOf SetBackgroundToBlue_Execute

        ' Set up the MenuAction which sets the control's  
        ' background to its default value.
        clearBackgroundMenuAction = New MenuAction("Cleared")
        clearBackgroundMenuAction.Checkable = True 
        AddHandler clearBackgroundMenuAction.Execute, AddressOf ClearBackground_Execute

        ' Set up the MenuGroup which holds the MenuAction items. 
        Dim backgroundFlyoutGroup As New MenuGroup("SetBackgroundsGroup", "Set Background")

        ' If HasDropDown is false, the group appears inline,  
        ' instead of as a flyout. Set to true.
        backgroundFlyoutGroup.HasDropDown = True
        backgroundFlyoutGroup.Items.Add(setBackgroundToBlueMenuAction)
        backgroundFlyoutGroup.Items.Add(clearBackgroundMenuAction)
        Me.Items.Add(backgroundFlyoutGroup)

        ' The UpdateItemStatus event is raised immediately before  
        ' this provider shows its tabs, which provides the opportunity  
        ' to set states. 
        AddHandler UpdateItemStatus, AddressOf CustomContextMenuProvider_UpdateItemStatus

    End Sub 

    ' The following method handles the UpdateItemStatus event. 
    ' It sets the MenuAction states according to the state 
    ' of the control's Background property. This method is 
    ' called before the context menu is shown. 
    Sub CustomContextMenuProvider_UpdateItemStatus( _
        ByVal sender As Object, _
        ByVal e As MenuActionEventArgs)

        ' Turn everything on, and then based on the value  
        ' of the BackgroundProperty, selectively turn some off.
        clearBackgroundMenuAction.Checked = False
        clearBackgroundMenuAction.Enabled = True
        setBackgroundToBlueMenuAction.Checked = False
        setBackgroundToBlueMenuAction.Enabled = True 

        ' Get a ModelItem which represents the selected control.  
        Dim selectedControl As ModelItem = _
            e.Selection.PrimarySelection

        ' Get the value of the Background property from the ModelItem. 
        Dim backgroundProperty As ModelProperty = _
            selectedControl.Properties(Control.BackgroundProperty)

        ' Set the MenuAction items appropriately. 
        If Not backgroundProperty.IsSet Then
            clearBackgroundMenuAction.Checked = True
            clearBackgroundMenuAction.Enabled = False 
        ElseIf backgroundProperty.ComputedValue.Equals(Brushes.Blue) Then
            setBackgroundToBlueMenuAction.Checked = True
            setBackgroundToBlueMenuAction.Enabled = False 
        End If 

    End Sub 

    ' The following method handles the Execute event.  
    ' It sets the Background property to its default value. 
    Sub ClearBackground_Execute( _
        ByVal sender As Object, _
        ByVal e As MenuActionEventArgs)

        Dim selectedControl As ModelItem = e.Selection.PrimarySelection
        selectedControl.Properties(Control.BackgroundProperty).ClearValue()

    End Sub 

    ' The following method handles the Execute event.  
    ' It sets the Background property to Brushes.Blue. 
    Sub SetBackgroundToBlue_Execute( _
        ByVal sender As Object, _
        ByVal e As MenuActionEventArgs)

        Dim selectedControl As ModelItem = e.Selection.PrimarySelection
        selectedControl.Properties(Control.BackgroundProperty).SetValue(Brushes.Blue)

    End Sub 

End Class
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Windows.Design.Interaction;
using System.Windows;
using Microsoft.Windows.Design.Model;
using System.Windows.Controls;
using System.Windows.Media;

namespace SliderAdornerLib
{
    // The CustomContextMenuProvider class provides two context menu items 
    // at design time. These are implemented with the MenuAction class. 
    class CustomContextMenuProvider : PrimarySelectionContextMenuProvider
    {
        private MenuAction setBackgroundToBlueMenuAction;
        private MenuAction clearBackgroundMenuAction;

        // The provider's constructor sets up the MenuAction objects  
        // and the the MenuGroup which holds them. 
        public CustomContextMenuProvider()
        {   
            // Set up the MenuAction which sets the control's  
            // background to Blue.
            setBackgroundToBlueMenuAction = new MenuAction("Blue");
            setBackgroundToBlueMenuAction.Checkable = true;
            setBackgroundToBlueMenuAction.Execute += 
                new EventHandler<MenuActionEventArgs>(SetBackgroundToBlue_Execute);

            // Set up the MenuAction which sets the control's  
            // background to its default value.
            clearBackgroundMenuAction = new MenuAction("Cleared");
            clearBackgroundMenuAction.Checkable = true;
            clearBackgroundMenuAction.Execute += 
                new EventHandler<MenuActionEventArgs>(ClearBackground_Execute);

            // Set up the MenuGroup which holds the MenuAction items.
            MenuGroup backgroundFlyoutGroup = 
                new MenuGroup("SetBackgroundsGroup", "Set Background");

            // If HasDropDown is false, the group appears inline,  
            // instead of as a flyout. Set to true.
            backgroundFlyoutGroup.HasDropDown = true;
            backgroundFlyoutGroup.Items.Add(setBackgroundToBlueMenuAction);
            backgroundFlyoutGroup.Items.Add(clearBackgroundMenuAction);
            this.Items.Add(backgroundFlyoutGroup);

            // The UpdateItemStatus event is raised immediately before  
            // this provider shows its tabs, which provides the opportunity  
            // to set states.
            UpdateItemStatus += 
                new EventHandler<MenuActionEventArgs>(
                    CustomContextMenuProvider_UpdateItemStatus);
        }

        // The following method handles the UpdateItemStatus event. 
        // It sets the MenuAction states according to the state 
        // of the control's Background property. This method is 
        // called before the context menu is shown. 
        void CustomContextMenuProvider_UpdateItemStatus(
            object sender, 
            MenuActionEventArgs e)
        {
            // Turn everything on, and then based on the value  
            // of the BackgroundProperty, selectively turn some off.
            clearBackgroundMenuAction.Checked = false;
            clearBackgroundMenuAction.Enabled = true;
            setBackgroundToBlueMenuAction.Checked = false;
            setBackgroundToBlueMenuAction.Enabled = true;

            // Get a ModelItem which represents the selected control. 
            ModelItem selectedControl = e.Selection.PrimarySelection;

            // Get the value of the Background property from the ModelItem.
            ModelProperty backgroundProperty = 
                selectedControl.Properties[Control.BackgroundProperty];

            // Set the MenuAction items appropriately. 
            if (!backgroundProperty.IsSet)
            {
                clearBackgroundMenuAction.Checked = true;
                clearBackgroundMenuAction.Enabled = false;
            }
            else if (backgroundProperty.ComputedValue == Brushes.Blue)
            {
                setBackgroundToBlueMenuAction.Checked = true;
                setBackgroundToBlueMenuAction.Enabled = false;
            }
        }

        // The following method handles the Execute event.  
        // It sets the Background property to its default value. 
        void ClearBackground_Execute(
            object sender, 
            MenuActionEventArgs e)
        {
            ModelItem selectedControl = e.Selection.PrimarySelection;
            selectedControl.Properties[Control.BackgroundProperty].ClearValue();
        }

        // The following method handles the Execute event.  
        // It sets the Background property to Brushes.Blue. 
        void SetBackgroundToBlue_Execute(
            object sender, 
            MenuActionEventArgs e)
        {
            ModelItem selectedControl = e.Selection.PrimarySelection;
            selectedControl.Properties[Control.BackgroundProperty].SetValue(Brushes.Blue);
        }
    }
}
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.ComponentModel
Imports System.Windows.Media
Imports System.Windows.Controls
Imports System.Windows
Imports CustomControlLibrary
Imports Microsoft.Windows.Design.Features
Imports Microsoft.Windows.Design.Metadata
Imports CustomControlLibrary.VisualStudio.Design.SliderAdornerLib

' Container for any general design-time metadata to initialize. 
' Designers look for a type in the design-time assembly that  
' implements IRegisterMetadata. If found, designers instantiate  
' this class and call its Register() method automatically. 
Friend Class Metadata
    Implements IRegisterMetadata

    ' Called by the designer to register any design-time metadata. 
    Public Sub Register() Implements IRegisterMetadata.Register
        Dim builder As New AttributeTableBuilder()

        ' Add the menu provider to the design-time metadata.
        builder.AddCustomAttributes(GetType(ButtonWithDesignTime), _
                                    New FeatureAttribute(GetType(CustomContextMenuProvider)))

        MetadataStore.AddAttributeTable(builder.CreateTable())
    End Sub 

End Class
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows;

using CustomControlLibrary;
using Microsoft.Windows.Design.Features;
using Microsoft.Windows.Design.Metadata;
using SliderAdornerLib;

namespace CiderPropertiesTester
{
    // Container for any general design-time metadata to initialize. 
    // Designers look for a type in the design-time assembly that  
    // implements IRegisterMetadata. If found, designers instantiate  
    // this class and call its Register() method automatically. 
    internal class Metadata : IRegisterMetadata
    {
        // Called by the designer to register any design-time metadata. 
        public void Register()
        {
            AttributeTableBuilder builder = new AttributeTableBuilder();

            // Add the menu provider to the design-time metadata.
            builder.AddCustomAttributes(
                typeof(ButtonWithDesignTime), 
                new FeatureAttribute(typeof(CustomContextMenuProvider)));

            MetadataStore.AddAttributeTable(builder.CreateTable());
        }
    }
}
<Window x:Class="DemoApplication.Window1"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cc="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <cc:ButtonWithDesignTime Margin="30,30,30,30" Background="#FFD4D0C8"></cc:ButtonWithDesignTime>
    </Grid>
</Window>
<Window x:Class="DemoApplication.Window1"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cc="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <cc:ButtonWithDesignTime Margin="30,30,30,30" Background="#FFD4D0C8"></cc:ButtonWithDesignTime>
    </Grid>
</Window>

Compiling the Code

Compile the previous example code in three separate assemblies.

Compiling the Custom Control

  1. Create the ButtonWithDesignTime class.

  2. Add references to the following assemblies.

    • PresentationCore

    • PresentationFramework

    • WindowsBase

  3. Compile the ButtonWithDesignTime class in an assembly named CustomControlLibrary.

    vbc /r:PresentationCore.dll /r:PresentationFramework.dll /r:WindowsBase.dll /t:library /out:CustomControlLibrary.dll ButtonWithDesignTime.vb
    
    csc /r:PresentationCore.dll /r:PresentationFramework.dll /r:WindowsBase.dll /t:library /out:CustomControlLibrary.dll ButtonWithDesignTime.cs
    

Compiling the Custom Menu Provider

  1. Create the CustomContextMenuProvider and Metadata classes.

  2. Add references to the following assemblies:

    • PresentationCore

    • PresentationFramework

    • WindowsBase

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  3. Add a reference to the CustomControlLibrary assembly or project.

  4. Compile the CustomContextMenuProvider and Metadata classes in a separate assembly named CustomControlLibrary.VisualStudio.Design. Direct the compiled assembly to the same folder as the CustomControlLibrary assembly.

    vbc /r:PresentationCore.dll /r:PresentationFramework.dll /r:WindowsBase.dll /r:Microsoft.Windows.Design.dll /r:Microsoft.Windows.Design.Extensibility.dll /r:Microsoft.Windows.Design.Interaction.dll /r:CustomControlLibrary.dll /t:library /out:CustomControlLibrary.VisualStudio.Design.dll CustomContextMenuProvider.vb Metadata.vb
    
    csc /r:PresentationCore.dll /r:PresentationFramework.dll /r:WindowsBase.dll /r:Microsoft.Windows.Design.dll /r:Microsoft.Windows.Design.Extensibility.dll /r:Microsoft.Windows.Design.Interaction.dll /r:CustomControlLibrary.dll /t:library /out:CustomControlLibrary.VisualStudio.Design.dll CustomContextMenuProvider.cs Metadata.cs
    

Compiling the Test Application

  1. In Visual Studio, create a new WPF Application project.

  2. Add a reference to the CustomControlLibrary assembly or project.

  3. Replace the existing XAML in Window1.xaml with the XAML listed earlier.

    In Design view, right-click the ButtonWithDesignTime control, point to Set Background, and select Blue.

See Also

Tasks

Walkthrough: Creating a MenuAction

Reference

PrimarySelectionContextMenuProvider

Other Resources

Advanced Extensibility Concepts

WPF Designer Extensibility