演练:创建菜单提供程序
[本文档仅供预览,在以后的发行版中可能会发生更改。包含的空白主题用作占位符。]
本演练演示如何创建 windows presentation foundation 自定义控件的一个设计 (WPF)时菜单提供程序。 可以使用此快捷菜单项设置 Background 属性的值在自定义按钮控件上。 有关完整的代码清单,请参见从站点的上下文菜单提供程序示例。 WPF 设计器扩展性示例
在本演练中,您将执行下列任务:
创建一个 WPF 自定义控件库项目。
创建设计时元数据的一个单独的程序集。
实现菜单提供程序。
使用控件在设计时。
完成后,您将知道如何创建自定义控件的菜单提供程序。
备注
您看到的对话框和菜单命令可能会与 " 帮助 " 中的描述不同具体取决于您现用的设置或版本。若要更改设置,请选择在 工具 菜单的 导入和导出设置 。有关更多信息,请参见 Visual Studio 设置。
系统必备
您需要以下组件来完成本演练:
- Visual Studio 2012 RC.
创建自定义控件
第一步是为自定义控件创建项目。 该控件是带有少量设计时代码的一个简单的按钮,使用 GetIsInDesignMode 方法实现设计时行为。
创建自定义控件
创建新 WPF 自定义控件库名为 CustomControlLibrary的项目在 Visual Basic 或 Visual C#。
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 中添加个新的类库名为 CustomControlLibrary.VisualStudio.Design 的项目或 Visual c# 为解决方案。
将项目的输出路径设置为 “ \ CustomControlLibrary \ bin \”。 这在同一文件夹使控件的程序集和元数据程序集,使设计器的元数据发现。
添加对下列 WPF 程序集。
PresentationCore
PresentationFramework
System.Xaml
WindowsBase
添加对以下 WPF Designer 程序集。
Microsoft.Windows.Design.Extensibility
Microsoft.Windows.Design.Interaction
添加对 CustomControlLibrary 项目。
在 解决方案资源管理器,将 Class1 代码文件的名称改为 Metadata.cs 或 Metadata.vb。 如果此项目请求的出现消息框是要执行重命名所有引用,单击 是。
用下面的代码替换自动生成的代码。 将自定义设计时实现附加到 ButtonWithDesignTime 类的此代码创建 AttributeTable 。
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的代码编辑器中,用以下代码替换自动生成的代码。 提供自定义 MenuAction的此代码实现 PrimarySelectionContextMenuProvider 。
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); } } }
生成解决方案。
测试设计时实现
代码,就象使用任何其他 WPF 控件,可以使用 ButtonWithDesignTime 控件。 WPF Designer 处理所有设计时对象的创建。
测试设计时实现
添加在 Visual Basic 中的新 WPF 名为 DemoApplication 的应用程序项目或 Visual c# 为解决方案。
在 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 项目。
在运行时,该按钮具有背景将使用快捷菜单。
后续步骤
可以添加更多的自定义设计时功能。您的自定义控件。
添加自定义装饰器添加到控件的设计时。 有关更多信息,请参见 演练:创建设计时装饰器。
创建自定义类型的一个编辑器,可在 " 属性 " 窗口中使用。 有关更多信息,请参见 如何:创建值编辑器。
请参见
参考
PrimarySelectionContextMenuProvider