共用方式為


逐步解說:建立 MenuAction

更新:2007 年 11 月

這個逐步解說將示範如何為 Windows Presentation Foundation (WPF) 自訂控制項,建立設計階段功能表提供者。您可以使用這個快速鍵功能表項目,設定自訂按鈕控制項上 Background 屬性的值。如需完整的程式碼清單,請參閱 HOW TO:建立 MenuAction

在這個逐步解說中,您會執行下列工作:

  • 建立 WPF 自訂控制項程式庫專案。

  • 為設計階段中繼資料建立個別組件。

  • 實作功能表提供者。

  • 在設計階段使用控制項。

完成時,您就知道要如何建立自訂控制項的功能表提供者。

注意事項:

根據您目前使用的設定或版本,您所看到的對話方塊與功能表命令可能會與 [說明] 中描述的不同。若要變更設定,請從 [工具] 功能表中選擇 [匯入和匯出設定]。如需詳細資訊,請參閱 Visual Studio 設定

必要條件

您需要下列元件才能完成此逐步解說:

  • Visual Studio 2008.

建立自訂控制項

第一個步驟是為自訂控制項建立專案。這個控制項是一個具有少量設計階段程式碼的簡易按鈕,這個程式碼使用 GetIsInDesignMode 方法來實作設計階段行為。

建立自訂控制項

  1. 在 Visual Basic 或 Visual C# 中建立名為 CustomControlLibrary 的新 WPF 自訂控制項程式庫專案。

    CustomControl1 的程式碼隨即在 [程式碼編輯器] 中開啟。

  2. 在 [方案總管] 中,將程式碼檔案的名稱變更為 ButtonWithDesignTime.cs 或 ButtonWithDesignTime.vb。如果顯示訊息方塊詢問您是否要重新命名專案中的所有參考,請按一下 [是]。

  3. 展開 [方案總管] 中的 [Themes] 資料夾。

  4. 按兩下 [Generic.xaml]。

    Generic.xaml 會在 WPF 設計工具中開啟。

  5. 在 [XAML] 檢視中,以 "ButtonWithDesignTime" 取代 "CustomControl1" 的所有項目。

  6. 在 [程式碼編輯器] 中開啟 ButtonWithDesignTime.cs 或 ButtonWithDesignTime.vb。

  7. 以下列程式碼取代自動產生的程式碼。這個程式碼繼承自 Button,且當按鈕出現在設計工具中時會顯示文字「設計模式作用中」。

    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";
                }
            }
        }
    }
    
  8. 將專案的輸出路徑設定為 "bin\"。

  9. 建置方案。

建立設計階段中繼資料組件

設計階段程式碼部署在特殊中繼資料組件中。在本逐步解說中,內容功能表實作部署在名為 CustomControlLibrary.VisualStudio.Design 的組件中。

若要建立設計階段中繼資料組件

  1. 在 Visual Basic 或 Visual C# 中,將名為 CustomControlLibrary.VisualStudio.Design 的新類別庫 (Class Library) 專案加入至方案。

  2. 將專案的輸出路徑設定為 "..\CustomControlLibrary\bin\"。這麼做會將控制項的組件和中繼資料組件保留在同一個資料夾中,讓設計工具可進行中繼資料探索。

  3. 加入下列 WPF 組件的參考。

    • PresentationCore

    • PresentationFramework

    • WindowsBase

  4. 加入下列 WPF 設計工具組件的參考。

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  5. 加入 CustomControlLibrary 專案的參考。

  6. 在 [方案總管] 中,將 Class1 程式碼檔案的名稱變更為 Metadata.cs 或 Metadata.vb。如果顯示訊息方塊詢問您是否要重新命名專案中的所有參考,請按一下 [是]。

  7. 以下列程式碼取代自動產生的程式碼。這個程式碼會建立 AttributeTable,會將自訂設計階段實作附加至 ButtonWithDesignTime 類別。

    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());
            }
        }
    }
    
  8. 儲存方案。

實作功能表提供者

功能表提供者實作在名為 CustomContextMenuProvider 的型別中。提供的 MenuAction 可讓您在設計階段,設定控制項的 Background 屬性。

若要實作功能表提供者

  1. 將名為 CustomContextMenuProvider 的新類別,加入至 CustomControlLibrary.VisualStudio.Design 專案。

  2. 在 CustomContextMenuProvider 的 [程式碼編輯器] 中,以下列程式碼取代自動產生的程式碼。這個程式碼會實作一個 PrimarySelectionContextMenuProvider,它會提供自訂的 MenuAction

    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);
            }
        }
    }
    
  3. 建置方案。

測試設計階段實作

您可以使用 ButtonWithDesignTime 控制項,就像使用任何其他 WPF 控制項一樣。WPF 設計工具會負責建立所有的設計階段物件。

若要測試設計階段實作

  1. 在 Visual Basic 或 Visual C# 中,將名為 DemoApplication 的新 WPF 應用程式專案加入至方案。

    Window1.xaml 隨即在 WPF 設計工具中開啟。

  2. 加入 CustomControlLibrary 專案的參考。

  3. 在 [XAML] 檢視中,以下列 XAML 取代自動產生的 XAML。這個 XAML 會加入 CustomControlLibrary 命名空間的參考,並加入 ButtonWithDesignTime 自訂控制項。按鈕會顯示在 [設計] 檢視中,並顯示文字「設計模式作用中」,表示正在設計模式下。如果按鈕不顯示,您可能需要按一下設計工具頂端的資訊列以重新載入檢視。

    <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>
    
  4. 在 [設計] 檢視中,按一下 ButtonWithDesignTime 控制項以選取該項目。

  5. 以滑鼠右鍵按一下 ButtonWithDesignTime 控制項、指向 [設定背景],然後選取 [藍色]。

    控制項的背景就會設定成藍色。在 [XAML] 檢視中,Background 屬性會設定為功能表動作所指定的值。

  6. 執行 DemoApplication 專案。

    在執行階段,按鈕的背景是您使用快速鍵功能表所設定的顏色。

後續步驟

您可以將多個自訂設計階段功能,加入至自訂控制項。

請參閱

工作

HOW TO:建立 MenuAction

參考

PrimarySelectionContextMenuProvider

其他資源

進階擴充性概念

WPF 設計工具擴充性