Procédure pas à pas : implémentation d'un éditeur de types d'interface utilisateur

Mise à jour : novembre 2007

Vous pouvez fournir une expérience personnalisée au moment du design pour les types de propriété complexes en implémentant un éditeur de type d'interface utilisateur.

Cette procédure pas à pas explique comment créer votre propre éditeur de type d'interface utilisateur pour un type personnalisé et afficher l'interface d'édition à l'aide d'une PropertyGrid.

Cette procédure pas à pas explique les tâches suivantes :

  • définition d'un type personnalisé ;

  • définition d'un contrôle View pour votre éditeur de type d'interface utilisateur ;

  • définition d'une classe qui dérive de UITypeEditor ;

  • substitution de la méthode GetEditStyle pour informer PropertyGrid du type de style d'éditeur que l'éditeur utilisera ;

  • substitution de la méthode EditValue pour gérer l'interface utilisateur, le traitement des entrées d'utilisateur et l'assignation des valeurs.

Pour copier le code dans cette procédure pas à pas sous forme de liste unique, consultez Comment : créer un contrôle Windows Forms qui bénéficie des fonctionnalités au moment du design.

Composants requis

Pour exécuter cette procédure pas à pas, vous devrez :

  • disposer d'autorisations suffisantes pour pouvoir créer et exécuter des projets d'application Windows Forms sur l'ordinateur où le .NET Framework est installé.

Définition d'un type personnalisé

Votre éditeur de type d'interface utilisateur personnalisé affichera un type personnalisé. Ce type peut être complexe ou simple. Pour cette procédure pas à pas, vous définirez un type simple avec un comportement d'édition personnalisé au moment du design. Ce type est appelé MarqueeLightShape et il s'agit d'une enum à deux valeurs, Square et Circle.

Pour définir un type d'énumération personnalisé

  • Dans le corps de votre définition de contrôle Windows Forms, définissez le type MarqueeLightShape.

    ' This defines the possible values for the MarqueeBorder
    ' control's LightShape property.
    Public Enum MarqueeLightShape
        Square
        Circle
    End Enum
    
    // This defines the possible values for the MarqueeBorder
    // control's LightShape property.
    public enum MarqueeLightShape
    {
        Square,
        Circle
    }
    

Définition d'un contrôle View

Votre éditeur de type d'interface utilisateur personnalisé affiche l'interface d'édition à l'aide d'un contrôle Windows Forms. Ce contrôle est nommé LightShapeSelectionControl et dérive de UserControl. Son constructeur utilise la valeur de la propriété actuelle et une référence au IWindowsFormsEditorService. Le contrôle View utilise la méthode CloseDropDown sur IWindowsFormsEditorService pour fermer la fenêtre déroulante lorsque l'utilisateur clique sur une sélection.

Pour définir un contrôle View

  • Dans le corps de votre définition de contrôle Windows Forms, définissez le contrôle LightShapeSelectionControl.

    ' This control provides the custom UI for the LightShape property
    ' of the MarqueeBorder. It is used by the LightShapeEditor.
    Public Class LightShapeSelectionControl
        Inherits System.Windows.Forms.UserControl
    
       Private lightShapeValue As MarqueeLightShape = MarqueeLightShape.Square
    
        Private editorService As IWindowsFormsEditorService
       Private squarePanel As System.Windows.Forms.Panel
       Private circlePanel As System.Windows.Forms.Panel
    
       ' Required designer variable.
       Private components As System.ComponentModel.Container = Nothing
    
    
       ' This constructor takes a MarqueeLightShape value from the
       ' design-time environment, which will be used to display
       ' the initial state.
        Public Sub New( _
        ByVal lightShape As MarqueeLightShape, _
        ByVal editorService As IWindowsFormsEditorService)
            ' This call is required by the Windows.Forms Form Designer.
            InitializeComponent()
    
            ' Cache the light shape value provided by the 
            ' design-time environment.
            Me.lightShapeValue = lightShape
    
            ' Cache the reference to the editor service.
            Me.editorService = editorService
    
            ' Handle the Click event for the two panels. 
            AddHandler Me.squarePanel.Click, AddressOf squarePanel_Click
            AddHandler Me.circlePanel.Click, AddressOf circlePanel_Click
        End Sub
    
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
    
                ' Be sure to unhook event handlers
                ' to prevent "lapsed listener" leaks.
                RemoveHandler Me.squarePanel.Click, AddressOf squarePanel_Click
                RemoveHandler Me.circlePanel.Click, AddressOf circlePanel_Click
    
                If (components IsNot Nothing) Then
                    components.Dispose()
                End If
    
            End If
            MyBase.Dispose(disposing)
        End Sub
    
        ' LightShape is the property for which this control provides
        ' a custom user interface in the Properties window.
        Public Property LightShape() As MarqueeLightShape
    
            Get
                Return Me.lightShapeValue
            End Get
    
            Set(ByVal Value As MarqueeLightShape)
                If Me.lightShapeValue <> Value Then
                    Me.lightShapeValue = Value
                End If
            End Set
    
        End Property
    
        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            MyBase.OnPaint(e)
    
            Dim gCircle As Graphics = Me.circlePanel.CreateGraphics()
            Try
                Dim gSquare As Graphics = Me.squarePanel.CreateGraphics()
                Try
                    ' Draw a filled square in the client area of
                    ' the squarePanel control.
                    gSquare.FillRectangle( _
                    Brushes.Red, _
                    0, _
                    0, _
                    Me.squarePanel.Width, _
                    Me.squarePanel.Height)
    
                    ' If the Square option has been selected, draw a 
                    ' border inside the squarePanel.
                    If Me.lightShapeValue = MarqueeLightShape.Square Then
                        gSquare.DrawRectangle( _
                        Pens.Black, _
                        0, _
                        0, _
                        Me.squarePanel.Width - 1, _
                        Me.squarePanel.Height - 1)
                    End If
    
                    ' Draw a filled circle in the client area of
                    ' the circlePanel control.
                    gCircle.Clear(Me.circlePanel.BackColor)
                    gCircle.FillEllipse( _
                    Brushes.Blue, _
                    0, _
                    0, _
                    Me.circlePanel.Width, _
                    Me.circlePanel.Height)
    
                    ' If the Circle option has been selected, draw a 
                    ' border inside the circlePanel.
                    If Me.lightShapeValue = MarqueeLightShape.Circle Then
                        gCircle.DrawRectangle( _
                        Pens.Black, _
                        0, _
                        0, _
                        Me.circlePanel.Width - 1, _
                        Me.circlePanel.Height - 1)
                    End If
                Finally
                    gSquare.Dispose()
                End Try
            Finally
                gCircle.Dispose()
            End Try
        End Sub
    
        Private Sub squarePanel_Click( _
        ByVal sender As Object, _
        ByVal e As EventArgs)
    
            Me.lightShapeValue = MarqueeLightShape.Square
            Me.Invalidate(False)
            Me.editorService.CloseDropDown()
    
        End Sub
    
    
        Private Sub circlePanel_Click( _
        ByVal sender As Object, _
        ByVal e As EventArgs)
    
            Me.lightShapeValue = MarqueeLightShape.Circle
            Me.Invalidate(False)
            Me.editorService.CloseDropDown()
    
        End Sub
    
    #Region "Component Designer generated code"
    
        '/ <summary> 
        '/ Required method for Designer support - do not modify 
        '/ the contents of this method with the code editor.
        '/ </summary>
        Private Sub InitializeComponent()
            Me.squarePanel = New System.Windows.Forms.Panel
            Me.circlePanel = New System.Windows.Forms.Panel
            Me.SuspendLayout()
            ' 
            ' squarePanel
            ' 
            Me.squarePanel.Location = New System.Drawing.Point(8, 10)
            Me.squarePanel.Name = "squarePanel"
            Me.squarePanel.Size = New System.Drawing.Size(60, 60)
            Me.squarePanel.TabIndex = 2
            ' 
            ' circlePanel
            ' 
            Me.circlePanel.Location = New System.Drawing.Point(80, 10)
            Me.circlePanel.Name = "circlePanel"
            Me.circlePanel.Size = New System.Drawing.Size(60, 60)
            Me.circlePanel.TabIndex = 3
            ' 
            ' LightShapeSelectionControl
            ' 
            Me.Controls.Add(squarePanel)
            Me.Controls.Add(circlePanel)
            Me.Name = "LightShapeSelectionControl"
            Me.Size = New System.Drawing.Size(150, 80)
            Me.ResumeLayout(False)
        End Sub
    
    #End Region
    
    End Class
    
        // This control provides the custom UI for the LightShape property
        // of the MarqueeBorder. It is used by the LightShapeEditor.
        public class LightShapeSelectionControl : System.Windows.Forms.UserControl
        {
            private MarqueeLightShape lightShapeValue = MarqueeLightShape.Square;
            private IWindowsFormsEditorService editorService = null;
            private System.Windows.Forms.Panel squarePanel;
            private System.Windows.Forms.Panel circlePanel;
    
            // Required designer variable.
            private System.ComponentModel.Container components = null;
    
            // This constructor takes a MarqueeLightShape value from the
            // design-time environment, which will be used to display
            // the initial state.
            public LightShapeSelectionControl( 
                MarqueeLightShape lightShape,
                IWindowsFormsEditorService editorService )
            {
                // This call is required by the designer.
                InitializeComponent();
    
                // Cache the light shape value provided by the 
                // design-time environment.
                this.lightShapeValue = lightShape;
    
                // Cache the reference to the editor service.
                this.editorService = editorService;
    
                // Handle the Click event for the two panels. 
                this.squarePanel.Click += new EventHandler(squarePanel_Click);
                this.circlePanel.Click += new EventHandler(circlePanel_Click);
            }
    
            protected override void Dispose( bool disposing )
            {
                if( disposing )
                {
                    // Be sure to unhook event handlers
                    // to prevent "lapsed listener" leaks.
                    this.squarePanel.Click -= 
                        new EventHandler(squarePanel_Click);
                    this.circlePanel.Click -= 
                        new EventHandler(circlePanel_Click);
    
                    if(components != null)
                    {
                        components.Dispose();
                    }
                }
                base.Dispose( disposing );
            }
    
            // LightShape is the property for which this control provides
            // a custom user interface in the Properties window.
            public MarqueeLightShape LightShape
            {
                get
                {
                    return this.lightShapeValue;
                }
    
                set
                {
                    if( this.lightShapeValue != value )
                    {
                        this.lightShapeValue = value;
                    }
                }
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint (e);
    
                using( 
                    Graphics gSquare = this.squarePanel.CreateGraphics(),
                    gCircle = this.circlePanel.CreateGraphics() )
                {   
                    // Draw a filled square in the client area of
                    // the squarePanel control.
                    gSquare.FillRectangle(
                        Brushes.Red, 
                        0,
                        0,
                        this.squarePanel.Width,
                        this.squarePanel.Height
                        );
    
                    // If the Square option has been selected, draw a 
                    // border inside the squarePanel.
                    if( this.lightShapeValue == MarqueeLightShape.Square )
                    {
                        gSquare.DrawRectangle( 
                            Pens.Black,
                            0,
                            0,
                            this.squarePanel.Width-1,
                            this.squarePanel.Height-1);
                    }
    
                    // Draw a filled circle in the client area of
                    // the circlePanel control.
                    gCircle.Clear( this.circlePanel.BackColor );
                    gCircle.FillEllipse( 
                        Brushes.Blue, 
                        0,
                        0,
                        this.circlePanel.Width, 
                        this.circlePanel.Height
                        );
    
                    // If the Circle option has been selected, draw a 
                    // border inside the circlePanel.
                    if( this.lightShapeValue == MarqueeLightShape.Circle )
                    {
                        gCircle.DrawRectangle( 
                            Pens.Black,
                            0,
                            0,
                            this.circlePanel.Width-1,
                            this.circlePanel.Height-1);
                    }
                }   
            }
    
            private void squarePanel_Click(object sender, EventArgs e)
            {
                this.lightShapeValue = MarqueeLightShape.Square;
    
                this.Invalidate( false );
    
                this.editorService.CloseDropDown();
            }
    
            private void circlePanel_Click(object sender, EventArgs e)
            {
                this.lightShapeValue = MarqueeLightShape.Circle;
    
                this.Invalidate( false );
    
                this.editorService.CloseDropDown();
            }
    
            #region Component Designer generated code
            /// <summary> 
            /// Required method for Designer support - do not modify 
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.squarePanel = new System.Windows.Forms.Panel();
                this.circlePanel = new System.Windows.Forms.Panel();
                this.SuspendLayout();
    // 
    // squarePanel
    // 
                this.squarePanel.Location = new System.Drawing.Point(8, 10);
                this.squarePanel.Name = "squarePanel";
                this.squarePanel.Size = new System.Drawing.Size(60, 60);
                this.squarePanel.TabIndex = 2;
    // 
    // circlePanel
    // 
                this.circlePanel.Location = new System.Drawing.Point(80, 10);
                this.circlePanel.Name = "circlePanel";
                this.circlePanel.Size = new System.Drawing.Size(60, 60);
                this.circlePanel.TabIndex = 3;
    // 
    // LightShapeSelectionControl
    // 
                this.Controls.Add(this.squarePanel);
                this.Controls.Add(this.circlePanel);
                this.Name = "LightShapeSelectionControl";
                this.Size = new System.Drawing.Size(150, 80);
                this.ResumeLayout(false);
    
            }
            #endregion
    
    
        }
    

Définition d'une classe d'éditeur de type d'interface utilisateur

Pour implémenter un comportement d'éditeur de type d'interface utilisateur, dérivez de la classe de base UITypeEditor. Cette classe est appelée LightShapeEditor.

Pour définir une classe d'éditeur de type d'interface utilisateur

  1. Activez l'accès à la prise en charge .NET Framework au moment du design en référençant l'assembly System.Design et en important les espaces de noms System.Drawing.Design et System.Windows.Forms.Design. Pour plus d'informations, consultez Comment : accéder à la prise en charge au moment du design dans les Windows Forms.

  2. Dans le corps de votre définition de contrôle Windows Forms, définissez la classe LightShapeEditor.

    ' This class demonstrates the use of a custom UITypeEditor. 
    ' It allows the MarqueeBorder control's LightShape property
    ' to be changed at design time using a customized UI element
    ' that is invoked by the Properties window. The UI is provided
    ' by the LightShapeSelectionControl class.
    Friend Class LightShapeEditor
        Inherits UITypeEditor
    
    // This class demonstrates the use of a custom UITypeEditor. 
    // It allows the MarqueeBorder control's LightShape property
    // to be changed at design time using a customized UI element
    // that is invoked by the Properties window. The UI is provided
    // by the LightShapeSelectionControl class.
    internal class LightShapeEditor : UITypeEditor
    {
    

Substitution de la méthode GetEditStyle

La méthode GetEditStyle indique à l'environnement de design le type d'interface utilisateur que votre éditeur de type d'interface utilisateur implémente. Les valeurs possibles sont définies dans le type UITypeEditorEditStyle. LightShapeEditor implémente un éditeur de type d'interface utilisateur DropDown.

Pour substituer la méthode GetEditStyle

  • Dans le corps de la définition LightShapeEditor, substituez la méthode GetEditStyle pour retourner DropDown.

    Public Overrides Function GetEditStyle( _
    ByVal context As System.ComponentModel.ITypeDescriptorContext) _
    As UITypeEditorEditStyle
        Return UITypeEditorEditStyle.DropDown
    End Function
    
    
    public override UITypeEditorEditStyle GetEditStyle(
    System.ComponentModel.ITypeDescriptorContext context)
    {
        return UITypeEditorEditStyle.DropDown;
    }
    

Substitution de la méthode EditValue

La méthode EditValue établit l'interaction entre l'environnement de design et l'interface utilisateur afin de modifier votre type personnalisé. La méthode EditValue crée une instance du contrôle View ou la boîte de dialogue modale avec laquelle l'utilisateur modifie la valeur. Lorsque l'utilisateur a terminé les modifications, la méthode EditValue retourne la valeur à l'environnement de design.

Dans le cas d'un contrôle View tel que LightShapeSelectionControl, la méthode EditValue peut passer une référence au IWindowsFormsEditorService au contrôle View. Le contrôle View peut utiliser cette référence pour se fermer lorsque l'utilisateur sélectionne une valeur. Cela n'est pas nécessaire pour une boîte de dialogue modale car un formulaire peut se fermer lui-même.

Pour substituer la méthode EditValue

  • Dans le corps de la définition LightShapeEditor, substituez la méthode EditValue.

    Public Overrides Function EditValue( _
    ByVal context As ITypeDescriptorContext, _
    ByVal provider As IServiceProvider, _
    ByVal value As Object) As Object
        If (provider IsNot Nothing) Then
            editorService = _
            CType(provider.GetService(GetType(IWindowsFormsEditorService)), _
            IWindowsFormsEditorService)
        End If
    
        If (editorService IsNot Nothing) Then
            Dim selectionControl As _
            New LightShapeSelectionControl( _
            CType(value, MarqueeLightShape), _
            editorService)
    
            editorService.DropDownControl(selectionControl)
    
            value = selectionControl.LightShape
        End If
    
        Return value
    End Function
    
    public override object EditValue(
        ITypeDescriptorContext context,
        IServiceProvider provider,
        object value)
    {
        if (provider != null)
        {
            editorService =
                provider.GetService(
                typeof(IWindowsFormsEditorService))
                as IWindowsFormsEditorService;
        }
    
        if (editorService != null)
        {
            LightShapeSelectionControl selectionControl =
                new LightShapeSelectionControl(
                (MarqueeLightShape)value,
                editorService);
    
            editorService.DropDownControl(selectionControl);
    
            value = selectionControl.LightShape;
        }
    
        return value;
    }
    

Substitution de la méthode PaintValue

Vous pouvez fournir une représentation graphique de la valeur de votre propriété en substituant la méthode PaintValue.

Pour substituer la méthode PaintValue

  • Dans le corps de la définition LightShapeEditor, substituez la méthode PaintValue. Substituez également la méthode GetPaintValueSupported pour retourner true.

    ' This method indicates to the design environment that
    ' the type editor will paint additional content in the
    ' LightShape entry in the PropertyGrid.
    Public Overrides Function GetPaintValueSupported( _
    ByVal context As ITypeDescriptorContext) As Boolean
    
        Return True
    
    End Function
    
    ' This method paints a graphical representation of the 
    ' selected value of the LightShpae property.
    Public Overrides Sub PaintValue( _
    ByVal e As PaintValueEventArgs)
    
        Dim shape As MarqueeLightShape = _
        CType(e.Value, MarqueeLightShape)
        Using p As Pen = Pens.Black
    
            If shape = MarqueeLightShape.Square Then
    
                e.Graphics.DrawRectangle(p, e.Bounds)
    
            Else
    
                e.Graphics.DrawEllipse(p, e.Bounds)
    
            End If
    
        End Using
    
    End Sub
    
    // This method indicates to the design environment that
    // the type editor will paint additional content in the
    // LightShape entry in the PropertyGrid.
    public override bool GetPaintValueSupported(
        ITypeDescriptorContext context)
    {  
        return true;
    }
    
    // This method paints a graphical representation of the 
    // selected value of the LightShpae property.
    public override void PaintValue(PaintValueEventArgs e)
    {   
        MarqueeLightShape shape = (MarqueeLightShape)e.Value;
        using (Pen p = Pens.Black)
        {
            if (shape == MarqueeLightShape.Square)
            {
                e.Graphics.DrawRectangle(p, e.Bounds);
            }
            else
            {
                e.Graphics.DrawEllipse(p, e.Bounds);
            }
        }   
    }
    

Attachez votre éditeur de type d'interface utilisateur à une propriété

Lorsque votre éditeur de type d'interface utilisateur est prêt à être utilisé dans votre contrôle personnalisé, attachez LightShapeEditor à une propriété, implémentez la propriété basée sur le type MarqueeLightShape et appliquez EditorAttribute à la propriété.

Pour attacher votre éditeur de type d'interface utilisateur à une propriété

  • Dans le corps de la définition de votre contrôle, déclarez une propriété MarqueeLightShape nommée LightShape. Déclarez également un champ d'instance nommé lightShapeValue de type MarqueeLightShape pour sauvegarder la propriété. Appliquez EditorAttribute à la propriété.
Private lightShapeValue As MarqueeLightShape

<Category("Marquee"), _
Browsable(True), _
EditorAttribute(GetType(LightShapeEditor), _
GetType(System.Drawing.Design.UITypeEditor))> _
Public Property LightShape() As MarqueeLightShape
    Get
        Return Me.lightShapeValue
    End Get
    Set(ByVal value As MarqueeLightShape)
        Me.lightShapeValue = value
    End Set
End Property
private MarqueeLightShape lightShapeValue;

[Category("Marquee")]
[Browsable(true)]
[EditorAttribute(typeof(LightShapeEditor),
typeof(System.Drawing.Design.UITypeEditor))]
public MarqueeLightShape LightShape
{
    get
    {
        return this.lightShapeValue;
    }

    set
    {
        this.lightShapeValue = value;
    }
}

Test de votre éditeur de type d'interface utilisateur

Vous pouvez tester votre éditeur de type d'interface utilisateur en créant une instance de votre contrôle personnalisé et en l'attachant à un contrôle PropertyGrid à l'aide de la propriété SelectedObject.

Si vous utilisez Visual Studio, vous pouvez créer un nouveau projet Application Windows, référencer l'assembly de votre contrôle et ajouter une instance de votre contrôle au formulaire. Il existe une prise en charge étendue pour cette tâche dans Visual Studio.

Lorsque les propriétés de votre contrôle sont affichées au moment du design, vous pouvez sélectionner la propriété LightShape. Lorsqu'elle est sélectionnée, une flèche de déroulement (Flèche Bas de la fenêtre Propriétés) apparaît. Lorsque vous cliquez sur la flèche, votre contrôle View apparaît sous l'entrée de propriété. Cliquez sur le cercle ou le carré pour sélectionner la valeur. Le contrôle View se ferme alors lui-même et la valeur que vous avez sélectionnée apparaît dans la PropertyGrid.

Remarque :

Lorsque vous développez votre UITypeEditorpersonnalisé, il est recommandé de définir le numéro de génération à incrémenter avec chaque génération. Cela empêche des versions plus anciennes, mises en cache de votre UITypeEditor d'être créées dans l'environnement de design.

Étapes suivantes

Après avoir créé votre propre éditeur de type d'interface utilisateur, explorez les autres façons d'interagir avec une PropertyGrid et l'environnement de design :

Voir aussi

Tâches

Comment : créer un contrôle Windows Forms qui bénéficie des fonctionnalités au moment du design

Référence

UITypeEditor

EditorAttribute

PropertyGrid

Autres ressources

Éditeurs de types d'interface utilisateur