Tutorial: Crear MenuAction
Actualización: noviembre 2007
En este tutorial se muestra cómo crear un proveedor de menú en tiempo de diseño para un control personalizado de Windows Presentation Foundation (WPF). Puede utilizar este elemento de menú de acceso directo para establecer el valor de la propiedad Background en un control de botón personalizado. Hay un ejemplo de código completo en Cómo: Crear MenuAction.
En este tutorial realizará las siguientes tareas:
Crear un proyecto de biblioteca de controles personalizados de WPF.
Crear un ensamblado independiente para los metadatos en tiempo de diseño.
Implementar el proveedor de menú.
Utilizar el control en tiempo de diseño.
Cuando haya finalizado, sabrá crear un proveedor de menú para un control personalizado.
Nota: |
---|
Los cuadros de diálogo y comandos de menú que se ven pueden diferir de los descritos en la Ayuda, dependiendo de los valores de configuración o de edición activos. Para cambiar la configuración, elija Importar y exportar configuraciones en el menú Herramientas. Para obtener más información, vea Valores de configuración de Visual Studio. |
Requisitos previos
Necesita los componentes siguientes para completar este tutorial:
- Visual Studio 2008.
Crear el control personalizado
El primer paso consiste en crear el proyecto para el control personalizado. El control es un botón simple con poco código en tiempo de diseño, que utiliza el método GetIsInDesignMode para implementar un comportamiento en tiempo de diseño.
Para crear el control personalizado
Cree un nuevo proyecto de biblioteca de controles personalizados de WPF en Visual Basic o Visual C# denominado CustomControlLibrary.
El código de CustomControl1 se abre en el Editor de código.
En el Explorador de soluciones, cambie el nombre del archivo de código a ButtonWithDesignTime.cs o ButtonWithDesignTime.vb. Si se muestra un cuadro de mensaje que le pregunta si desea cambiar el nombre de todas las referencias de este proyecto, haga clic en Sí.
En el Explorador de soluciones, expanda la carpeta Themes.
Haga doble clic en Generic.xaml.
Generic.xaml se abre en WPF Designer.
En la vista XAML, reemplace todas las apariciones de "CustomControl1" por "ButtonWithDesignTime".
Abra ButtonWithDesignTime.cs o ButtonWithDesignTime.vb en el Editor de código.
Reemplace el código generado automáticamente por el código siguiente. Este código hereda de Button y muestra el texto "Design mode active" cuando el botón aparece en el diseñador.
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"; } } } }
Establezca la ruta de acceso de salida del proyecto en "bin\".
Genere la solución.
Crear el ensamblado de metadatos en tiempo de diseño
El código en tiempo de diseño se implementa en ensamblados de metadatos especiales. Para este tutorial, la implementación de menú contextual se implementa en un ensamblado denominado a CustomControlLibrary.VisualStudio.Design.
Para crear el ensamblado de metadatos en tiempo de diseño
Agregue un nuevo proyecto de biblioteca de clases en Visual Basic o Visual C# denominado CustomControlLibrary.VisualStudio.Design a la solución.
Establezca la ruta de acceso de salida del proyecto en ".. \CustomControlLibrary\bin\". De este modo, el ensamblado del control y el ensamblado de metadatos permanecen en la misma carpeta, lo que permite que los diseñadores detecten los metadatos.
Agregue referencias a los ensamblados de WPF siguientes.
PresentationCore
PresentationFramework
WindowsBase
Agregue referencias a los ensamblados de WPF Designer siguientes.
Microsoft.Windows.Design
Microsoft.Windows.Design.Extensibility
Microsoft.Windows.Design.Interaction
Agregue una referencia al proyecto CustomControlLibrary.
En el Explorador de soluciones, cambie el nombre del archivo de código Class1 a Metadata.cs o Metadata.vb. Si se muestra un cuadro de mensaje que le pregunta si desea cambiar el nombre de todas las referencias de este proyecto, haga clic en Sí.
Reemplace el código generado automáticamente por el código siguiente. Este código crea un objeto AttributeTable que asocia la implementación en tiempo de diseño personalizada a la clase 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()); } } }
Guarde la solución.
Implementar el proveedor de menú
El proveedor de menú se implementa en un tipo denominado CustomContextMenuProvider. El objeto MenuAction proporcionado permite establecer la propiedad Background del control en tiempo de diseño.
Para implementar el proveedor de menú
Agregue una nueva clase denominada CustomContextMenuProvider al proyecto CustomControlLibrary.VisualStudio.Design.
En el Editor de código para CustomContextMenuProvider, reemplace el código generado automáticamente con el código siguiente. Este código implementa un objeto PrimarySelectionContextMenuProvider que proporciona un objeto MenuAction personalizado.
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); } } }
Genere la solución.
Probar la implementación en tiempo de diseño
Puede utilizar el control ButtonWithDesignTime como cualquier otro control de WPF. WPF Designer administra la creación de todos los objetos de tiempo de diseño.
Para probar la implementación en tiempo de diseño
Agregue un nuevo proyecto de aplicación de WPF en Visual Basic o Visual C# denominado DemoApplication a la solución.
Window1.xaml se abrirá en el WPF Designer.
Agregue una referencia al proyecto CustomControlLibrary.
En la vista XAML, reemplace el XAML generado automáticamente por lo siguiente. Este XAML agrega una referencia al espacio de nombres CustomControlLibrary y agrega el control personalizado ButtonWithDesignTime. El botón aparece en la vista Diseño con el texto "Design mode active", que indica que se encuentra en modo de diseño. Si el botón no aparece, puede que sea necesario hacer clic en la barra de información situada en la parte superior del diseñador para volver a cargar la vista.
<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>
En la vista Diseño, haga clic en el control ButtonWithDesignTime para seleccionarlo.
Haga clic con el botón secundario en el control ButtonWithDesignTime, elija Establecer fondo y seleccione Azul.
El fondo del control se establece en azul. En la vista XAML, la propiedad Background se establece en el valor especificado por la acción de menú.
Ejecute el proyecto DemoApplication.
En tiempo de ejecución, el botón tiene el fondo que estableció mediante el menú de acceso directo.
Pasos siguientes
Puede agregar más características personalizadas en tiempo de diseño a los controles personalizados.
Agregue un adorno personalizado en tiempo de diseño del control. Para obtener más información, vea Tutorial: Crear un adorno en tiempo de diseño.
Cree un editor para un tipo personalizado que puede utilizar en la ventana Propiedades. Para obtener más información, vea Cómo: Crear un editor de valores.
Vea también
Tareas
Referencia
PrimarySelectionContextMenuProvider