如何:创建 MenuAction

更新:2007 年 11 月

下面的代码示例演示如何创建在设计时上下文菜单中使用的菜单操作。Visual Studio 中对此任务提供了广泛的支持。有关更多信息,请参见演练:创建 MenuAction

示例

下面的代码示例演示如何为 Windows Presentation Foundation (WPF) 自定义控件创建设计时菜单提供程序。可以使用此快捷菜单项在自定义按钮控件上设置 Background 属性的值。

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>

编译代码

在三个单独的程序集内编译上面的代码示例。

编译自定义控件

  1. 创建 ButtonWithDesignTime 类。

  2. 添加对下列程序集的引用。

    • PresentationCore

    • PresentationFramework

    • WindowsBase

  3. 在名为 CustomControlLibrary 的程序集中编译 ButtonWithDesignTime 类。

    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
    

编译自定义菜单提供程序

  1. 创建 CustomContextMenuProvider 和 Metadata 类。

  2. 添加对下列程序集的引用:

    • PresentationCore

    • PresentationFramework

    • WindowsBase

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  3. 添加对 CustomControlLibrary 程序集或项目的引用。

  4. 在名为 CustomControlLibrary.VisualStudio.Design 的单独程序集中编译 CustomContextMenuProvider 和 Metadata 类。将编译后的程序集定向到 CustomControlLibrary 程序集所在的文件夹中。

    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
    

编译测试应用程序

  1. 在 Visual Studio 中创建一个新的 WPF 应用程序项目。

  2. 添加对 CustomControlLibrary 程序集或项目的引用。

  3. 将 Window1.xaml 中的现有 XAML 替换为前面列出的 XAML。

    在“设计”视图中,右击 ButtonWithDesignTime 控件,指向“设置背景”,然后选择“蓝色”。

请参见

任务

演练:创建 MenuAction

参考

PrimarySelectionContextMenuProvider

其他资源

高级扩展性概念

WPF 设计器扩展性