Procédure pas à pas : création d'un MenuAction
Mise à jour : novembre 2007
Cette procédure pas à pas indique comment créer un fournisseur de menus au moment du design pour un contrôle personnalisé Windows Presentation Foundation (WPF). Vous pouvez utiliser cet élément de menu contextuel pour définir la valeur de la propriété Background sur un contrôle bouton personnalisé. Pour obtenir l'intégralité du code, consultez Comment : créer un MenuAction.
Dans cette procédure pas à pas, vous exécutez les tâches suivantes :
créer un projet de bibliothèque de contrôle personnalisé WPF ;
créer un assembly séparé pour les métadonnées au moment du design ;
implémenter le fournisseur de menus ;
utiliser le contrôle au moment du design.
Lorsque vous aurez terminé, vous saurez comment créer un fournisseur de menus pour un contrôle personnalisé.
Remarque : |
---|
Les boîtes de dialogue et les commandes de menu qui s'affichent peuvent être différentes de celles qui sont décrites dans l'aide, en fonction de vos paramètres actifs ou de l'édition utilisée. Pour modifier vos paramètres, choisissez Importation et exportation de paramètres dans le menu Outils. Pour plus d'informations, consultez Paramètres Visual Studio. |
Composants requis
Vous avez besoin des composants suivants pour exécuter cette procédure pas à pas :
- Visual Studio 2008.
Création du contrôle personnalisé
La première étape consiste à créer le projet pour le contrôle personnalisé. Le contrôle est un bouton simple avec une petite portion de code au moment du design, qui utilise la méthode GetIsInDesignMode pour implémenter un comportement au moment du design.
Pour créer le contrôle personnalisé
Créez un nouveau projet Bibliothèque de contrôles personnalisés WPF dans Visual Basic ou Visual C# nommé CustomControlLibrary.
Le code pour CustomControl1 s'ouvre dans l'Éditeur de code.
Dans l'Explorateur de solutions, remplacez le nom du fichier de code par ButtonWithDesignTime.cs ou ButtonWithDesignTime.vb. Si un message s'affiche demandant si vous souhaitez renommer toutes les références dans ce projet, cliquez sur Oui.
Dans l'Explorateur de solutions, développez le dossier Thèmes.
Double-cliquez sur Generic.xaml.
Generic.xaml s'ouvre dans le Concepteur WPF.
En mode XAML, remplacez toutes les occurrences de "CustomControl1" par "ButtonWithDesignTime".
Ouvrez ButtonWithDesignTime.cs ou ButtonWithDesignTime.vb dans l'éditeur de code.
Remplacez le code généré automatiquement par le code suivant. Ce code hérite de Button et affiche le texte « Actif en mode Design » lorsque le bouton apparaît dans le concepteur.
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"; } } } }
Le chemin de sortie du projet doit être "bin\".
Générez la solution.
Création de l'assembly de métadonnées au moment du design
Le code au moment du design est déployé dans des assemblys de métadonnées spéciaux. Pour cette procédure pas à pas, l'implémentation du menu contextuel est déployée dans un assembly appelé CustomControlLibrary.VisualStudio.Design.
Pour créer l'assembly de métadonnées au moment du design
Ajoutez à la solution un nouveau projet de bibliothèque de classes dans Visual Basic ou Visual C# nommé CustomControlLibrary.VisualStudio.Design.
Le chemin de sortie du projet doit être "..\CustomControlLibrary\bin\". Cela permet de garder l'assembly du contrôle et l'assembly de métadonnées dans le même dossier, ce qui active la découverte de métadonnées pour les concepteurs.
Ajoutez des références aux assemblys WPF suivants.
PresentationCore
PresentationFramework
WindowsBase
Ajoutez des références aux assemblys du Concepteur WPF suivants.
Microsoft.Windows.Design
Microsoft.Windows.Design.Extensibility
Microsoft.Windows.Design.Interaction
Ajoutez une référence au projet CustomControlLibrary.
Dans l'Explorateur de solutions, modifiez le nom du fichier de code Class1 en Metadata.cs ou Metadata.vb. Si un message s'affiche demandant si vous souhaitez renommer toutes les références dans ce projet, cliquez sur Oui.
Remplacez le code généré automatiquement par le code suivant. Ce code crée un AttributeTable qui lie l'implémentation au moment du design personnalisée à la classe 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()); } } }
Enregistrez la solution.
Implémentation du fournisseur de menus
Le fournisseur de menus est implémenté dans un type nommé CustomContextMenuProvider. Le MenuAction fourni permet la définition de la propriété Background du contrôle au moment du design.
Pour implémenter le fournisseur de menus
Ajoutez une nouvelle classe nommée CustomContextMenuProvider au projet CustomControlLibrary.VisualStudio.Design.
Dans l'éditeur de code pour CustomContextMenuProvider, remplacez le code généré automatiquement par le code suivant. Ce code implémente un PrimarySelectionContextMenuProvider qui fournit un MenuActionpersonnalisé.
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); } } }
Générez la solution.
Test de l'implémentation au moment du design
Vous pouvez utiliser le contrôle ButtonWithDesignTime comme vous utiliseriez tout autre contrôle WPF. Le Concepteur WPF gère la création de tous les objets au moment du design.
Pour tester l'implémentation au moment du design
Ajoutez à la solution un nouveau projet Application WPF dans Visual Basic ou Visual C# nommé DemoApplication.
Window1.xaml s'ouvre dans le Concepteur WPF.
Ajoutez une référence au projet CustomControlLibrary.
En mode XAML, remplacez le code XAML généré automatiquement par le code XAML suivant. Ce code XAML ajoute une référence à l'espace de noms CustomControlLibrary ainsi que le contrôle personnalisé ButtonWithDesignTime. Le bouton apparaît en mode Design avec le texte « Actif en mode Design », indiquant que c'est uniquement en mode Design. Si le bouton ne s'affiche pas, vous pouvez devoir cliquer sur la barre d'informations, en haut du concepteur, pour recharger la vue.
<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 mode Design, cliquez sur le contrôle ButtonWithDesignTime pour le sélectionner.
Cliquez avec le bouton droit sur le contrôle ButtonWithDesignTime, pointez sur Définir l'arrière-planet sélectionnez Bleu.
L'arrière-plan du contrôle a la valeur bleu. En mode XAML, la propriété Background a la valeur spécifiée par l'action du menu.
Exécutez le projet de DemoApplication.
Pendant l'exécution, le bouton a l'arrière-plan que vous avez défini avec le menu contextuel.
Étapes suivantes
Vous pouvez ajouter plus des fonctionnalités personnalisées au moment du design à vos contrôles personnalisés.
Ajoutez un ornement personnalisé au moment du design de votre contrôle. Pour plus d'informations, consultez Procédure pas à pas : création d'un ornement au moment du design.
Créez un éditeur pour un type personnalisé, éditeur que vous pouvez utiliser dans la fenêtre Propriétés. Pour plus d'informations, consultez Comment : créer un éditeur de valeurs.
Voir aussi
Tâches
Référence
PrimarySelectionContextMenuProvider