逐步解說:建立功能表提供者
這個逐步解說將示範如何為 Windows Presentation Foundation (WPF) 自訂控制項,建立設計階段功能表提供者。 您可以使用這個捷徑功能表項目,設定自訂按鈕控制項上 Background 屬性的值。 如需完整的程式碼清單,請參閱 WPF 設計工具擴充性範例網站上的<內容功能表提供者>範例 (英文)。
在這個逐步解說中,您會執行下列工作:
建立 WPF 自訂控制項程式庫專案。
為設計階段中繼資料建立個別組件。
實作功能表提供者。
在設計階段使用控制項。
完成時,您就知道要如何建立自訂控制項的功能表提供者。
注意
根據您目前使用的設定或版本,您所看到的對話方塊與功能表指令可能會與 [說明] 中描述的不同。若要變更設定,請從 [工具] 功能表中選擇 [匯入和匯出設定]。如需詳細資訊,請參閱 Visual Studio 設定。
必要條件
您需要下列元件才能完成此逐步解說:
- Visual Studio 2012 RC.
建立自訂控制項
第一個步驟是為自訂控制項建立專案。 這個控制項是一個具有少量設計階段程式碼的簡易按鈕,這個程式碼使用 GetIsInDesignMode 方法來實作設計階段行為。
建立自訂控制項
在 Visual Basic 或 Visual C# 中建立名為 CustomControlLibrary 的新 WPF 自訂控制項程式庫專案。
CustomControl1 的程式碼隨即在 [程式碼編輯器] 中開啟。
在 [方案總管] 中,將程式碼檔案的名稱變更為 ButtonWithDesignTime.cs 或 ButtonWithDesignTime.vb。 如果顯示訊息方塊詢問您是否要重新命名專案中的所有參考,請按一下 [是]。
在 [程式碼編輯器] 中開啟 ButtonWithDesignTime.cs 或 ButtonWithDesignTime.vb。
以下列程式碼取代自動產生的程式碼。 這個程式碼繼承自 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"; } } } }
將專案的輸出路徑設定為 "bin\"。
建置方案。
建立設計階段中繼資料組件
設計階段程式碼部署在特殊中繼資料組件中。 在本逐步解說中,內容功能表實作部署在名為 CustomControlLibrary.VisualStudio.Design 的組件中。 如需詳細資訊,請參閱 提供設計階段中繼資料。
若要建立設計階段中繼資料組件
在 Visual Basic 或 Visual C# 中,將名為 CustomControlLibrary.VisualStudio.Design 的新類別庫 (Class Library) 專案加入至方案。
將專案的輸出路徑設定為 ".. \CustomControlLibrary\bin\"。 這麼做會將控制項的組件和中繼資料組件保留在同一個資料夾中,讓設計工具可進行中繼資料探索。
加入下列 WPF 組件的參考。
PresentationCore
PresentationFramework
System.Xaml
WindowsBase
加入下列 WPF Designer組件的參考。
Microsoft.Windows.Design.Extensibility
Microsoft.Windows.Design.Interaction
加入 CustomControlLibrary 專案的參考。
在 [方案總管] 中,將 Class1 程式碼檔案的名稱變更為 Metadata.cs 或 Metadata.vb。 如果顯示訊息方塊詢問您是否要重新命名專案中的所有參考,請按一下 [是]。
以下列程式碼取代自動產生的程式碼。 這個程式碼會建立 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.Slid ' The ProvideMetadata assembly-level attribute indicates to designers ' that this assembly contains a class that provides an attribute table. <Assembly: ProvideMetadata(GetType(CustomControlLibrary.VisualStudio.Design.Metadata))> ' Container for any general design-time metadata to initialize. ' Designers look for a type in the design-time assembly that ' implements IProvideAttributeTable. If found, designers instantiate ' this class and access its AttributeTable property automatically. Friend Class Metadata Implements IProvideAttributeTable ' Accessed by the designer to register any design-time metadata. Public ReadOnly Property AttributeTable() As AttributeTable _ Implements IProvideAttributeTable.AttributeTable Get Dim builder As New AttributeTableBuilder() ' Add the menu provider to the design-time metadata. builder.AddCustomAttributes(GetType(ButtonWithDesignTime), _ New FeatureAttribute(GetType(CustomContextMenuProvider))) Return builder.CreateTable() End Get End Property 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 CustomControlLibrary.VisualStudio.Design; // The ProvideMetadata assembly-level attribute indicates to designers // that this assembly contains a class that provides an attribute table. [assembly: ProvideMetadata(typeof(CustomControlLibrary.VisualStudio.Design.Metadata))] namespace CustomControlLibrary.VisualStudio.Design { // Container for any general design-time metadata to initialize. // Designers look for a type in the design-time assembly that // implements IProvideAttributeTable. If found, designers instantiate // this class and access its AttributeTable property automatically. internal class Metadata : IProvideAttributeTable { // Accessed by the designer to register any design-time metadata. public AttributeTable AttributeTable { get { AttributeTableBuilder builder = new AttributeTableBuilder(); // Add the menu provider to the design-time metadata. builder.AddCustomAttributes( typeof(ButtonWithDesignTime), new FeatureAttribute(typeof(CustomContextMenuProvider))); return builder.CreateTable(); } } } }
儲存方案。
實作功能表提供者
功能表提供者實作在名為 CustomContextMenuProvider 的型別中。 提供的 MenuAction 可讓您在設計階段,設定控制項的 Background 屬性。
若要實作功能表提供者
將名為 CustomContextMenuProvider 的新類別,加入至 CustomControlLibrary.VisualStudio.Design 專案。
在 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("Background") ' 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("Background").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("Background").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 CustomControlLibrary.VisualStudio.Design { // 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["Background"]; // 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["Background"].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["Background"].SetValue(Brushes.Blue); } } }
建置方案。
測試設計階段實作
您可以使用 ButtonWithDesignTime 控制項,就像使用任何其他 WPF 控制項一樣。 WPF Designer會負責建立所有的設計階段物件。
若要測試設計階段實作
在 Visual Basic 或 Visual C# 中,將名為 DemoApplication 的新 WPF 應用程式專案加入至方案。
MainWindow.xaml 隨即在 WPF Designer中開啟。
加入 CustomControlLibrary 專案的參考。
在 [XAML] 檢視中,以下列 XAML 取代自動產生的 XAML。 這個 XAML 會加入 CustomControlLibrary 命名空間的參考,並加入 ButtonWithDesignTime 自訂控制項。 按鈕會顯示在 [設計] 檢視中,並顯示文字「設計模式作用中」,表示正在設計模式下。 如果按鈕不顯示,您可能需要按一下設計工具頂端的資訊列以重新載入檢視。
<Window x:Class="DemoApplication.MainWindow" 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>
在 [設計] 檢視中,按一下 ButtonWithDesignTime 控制項以選取該項目。
以滑鼠右鍵按一下 ButtonWithDesignTime 控制項、指向 [設定背景],然後選取 [藍色]。
控制項的背景就會設定成藍色。 在 [XAML] 檢視中,Background 屬性會設定為功能表動作所指定的值。
執行 DemoApplication 專案。
在執行階段,按鈕的背景是您使用捷徑功能表所設定的顏色。
後續步驟
您可以將多個自訂設計階段功能,加入至自訂控制項。
將自訂裝飾項加入至控制項的設計階段。 如需詳細資訊,請參閱逐步解說:建立設計階段裝飾項。
為自訂型別建立可以在 [屬性] 視窗中使用的編輯器。 如需詳細資訊,請參閱 HOW TO:建立值編輯器。
請參閱
參考
PrimarySelectionContextMenuProvider
其他資源
WPF 設計工具擴充性範例