Condividi tramite


Procedura dettagliata: implementazione di un editor di tipi con interfaccia utente

Implementando un editor di tipo dell'interfaccia utente, è possibile fornire una soluzione di progettazione personalizzata per tipi di proprietà complessi.

Nella presente procedura dettagliata viene illustrato come creare un editor di tipi con interfaccia utente per un tipo personalizzato e come visualizzare l'interfaccia di modifica utilizzando una classe PropertyGrid.

Di seguito sono elencate le attività illustrate nella procedura dettagliata:

  • Definizione di un tipo personalizzato.

  • Definizione di un controllo di visualizzazione per l'editor di tipi con interfaccia utente.

  • Definizione di una classe che deriva da UITypeEditor.

  • Override del metodo GetEditStyle per informare la classe PropertyGrid dello stile del tipo di editor che verrà utilizzato dall'editor.

  • Override del metodo EditValue per la gestione dell'interfaccia utente, l'elaborazione degli input dell'utente e l'assegnazione dei valori.

Per copiare il codice contenuto in questa procedura dettagliata come elenco singolo, vedere Procedura: creare un controllo Windows Form che utilizza le funzionalità di progettazione.

Prerequisiti

Per completare questa procedura dettagliata, è necessario disporre di quanto segue:

  • Autorizzazioni sufficienti per la creazione e l'esecuzione di progetti dell'applicazione Windows Form nel computer in cui è installato .NET Framework.

Definizione di un tipo personalizzato

L'editor di tipi con interfaccia utente personalizzato consentirà di visualizzare un tipo personalizzato. Tale tipo può essere complesso o semplice. Pe questa procedura dettagliata verrà definito un tipo semplice con un comportamento personalizzato di modifica della fase di progettazione. Tale tipo è denominato MarqueeLightShape ed è un oggetto enum con due valori, Square e Circle.

Per definire un tipo di enumerazione personalizzato

  • Nel corpo della definizione del controllo Windows Form definire il tipo 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
    }
    

Definizione di un controllo di visualizzazione

L'editor di tipi con interfaccia utente personalizzato consente di visualizzare l'interfaccia di modifica utilizzando un controllo Windows Form denominato LightShapeSelectionControl e che deriva dalla classe UserControl. Il relativo costruttore accetta il valore della proprietà corrente e un riferimento a IWindowsFormsEditorService. Il controllo di visualizzazione utilizza il metodo CloseDropDown su IWindowsFormsEditorService per chiudere la finestra a discesa quando l'utente fa clic su una selezione.

Per definire un controllo di visualizzazione

  • Nel corpo della definizione del controllo Windows Form definire il controllo 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
    
    
        }
    

Definizione di una classe di editor di tipi con interfaccia utente

Per implementare il comportamento dell'editor di tipi con interfaccia utente, derivare dalla classe base UITypeEditor denominata LightShapeEditor.

Per definire una classe di editor di tipi con interfaccia utente

  1. Consentire l'accesso al supporto in fase di progettazione di .NET Framework facendo riferimento all'assembly System.Design e importando gli spazi dei nomi System.Drawing.Design e System.Windows.Forms.Design. Per ulteriori informazioni, vedere Procedura: accedere al supporto in fase di progettazione in Windows Form.

  2. Nel corpo della definizione del controllo Windows Form definire 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
    {
    

Override del metodo GetEditStyle

Il metodo GetEditStyle indica all'ambiente di progettazione il tipo di interfaccia che dovrà essere implementato dall'editor di tipi con interfaccia utente. I valori possibili sono definiti nel tipo UITypeEditorEditStyle. LightShapeEditor implementa un editor di tipi con interfaccia utente DropDown.

Per eseguire l'override del metodo GetEditStyle

  • Nel corpo della definizione di LightShapeEditor eseguire l'override del metodo GetEditStyle per restituire 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;
    }
    

Override del metodo EditValue

Il metodo EditValue stabilisce l'interazione tra l'ambiente di progettazione e l'interfaccia utente per la modifica del tipo personalizzato. Il metodo EditValue consente di creare un'istanza del controllo di visualizzazione o la finestra di dialogo modale tramite la quale l'utente modifica il valore. Al termine della modifica il metodo EditValue restituisce il valore all'ambiente di progettazione.

Nel caso di un controllo di visualizzazione come LightShapeSelectionControl, il metodo EditValue può passare un riferimento all'interfaccia IWindowsFormsEditorService al controllo di visualizzazione. Il controllo di visualizzazione può utilizzare tale riferimento per chiudersi quando l'utente seleziona un valore. L'operazione non è necessaria per una finestra di dialogo modale, in quanto un form è in grado di chiudersi automaticamente.

Per eseguire l'override del metodo EditValue

  • Nel corpo della definizione di LightShapeEditor eseguire l'override del metodo 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;
    }
    

Override del metodo PaintValue

È possibile fornire una rappresentazione grafica del valore della proprietà eseguendo l'override del metodo PaintValue.

Per eseguire l'override del metodo PaintValue

  • Nel corpo della definizione di LightShapeEditor eseguire l'override del metodo PaintValue. Eseguire inoltre l'override del metodo GetPaintValueSupported per restituire 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);
            }
        }   
    }
    

Associazione dell'editor di tipi con interfaccia utente a una proprietà

Quando l'editor di tipi con interfaccia utente è pronto per l'utilizzo nel controllo personalizzato, associare l'oggetto LightShapeEditor a una proprietà, implementare la proprietà in base al tipo MarqueeLightShape e applicare la classe EditorAttribute alla proprietà.

Per associare l'editor di tipi con interfaccia utente a una proprietà

  • Nel corpo della definizione del controllo dichiarare una proprietà MarqueeLightShape denominata LightShape. Dichiarare inoltre un campo istanza denominato lightShapeValue di tipo MarqueeLightShape insieme alla proprietà. Applicare la classe EditorAttribute alla proprietà.
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 dell'editor di tipi con interfaccia utente

Per eseguire il test dell'editor di tipi con interfaccia utente in uso, è possibile creare un'istanza del controllo personalizzato e associarla a un controllo PropertyGrid mediante la proprietà SelectedObject.

Se si utilizza Visual Studio, è possibile creare un nuovo progetto Applicazione Windows, fare riferimento all'assembly del controllo e aggiungere un'istanza del controllo al form. È disponibile un supporto completo per questa attività in Visual Studio. Procedura dettagliata: compilazione automatica della casella degli strumenti con componenti personalizzati
Procedura dettagliata: compilazione automatica della casella degli strumenti con componenti personalizzati
Procedura dettagliata: compilare automaticamente la casella degli strumenti con componenti personalizzati
Procedura dettagliata: compilare automaticamente la casella degli strumenti con componenti personalizzati

Quando le proprietà relative al controllo vengono visualizzate in fase di progettazione, è possibile selezionare la proprietà LightShape. Dopo che tale proprietà è stata selezionata, viene visualizzata una freccia a discesa (Properties Window Down Arrow). Se si fa clic sulla freccia, il controllo di visualizzazione appare sotto la voce relativa alla proprietà. Fare clic sul cerchio o sul quadrato per selezionare il valore. Dopo aver fatto clic, il controllo di visualizzazione si chiude e il valore selezionato viene visualizzato nel controllo PropertyGrid.

Nota

Quando si sviluppa un oggetto UITypeEditor personalizzato, si consiglia di impostare il numero di build per incrementare il numero di ogni nuova build.In questo modo è possibile impedire la creazione nell'ambiente di progettazione di versioni meno recenti di UITypeEditor memorizzate nella cache.

Passaggi successivi

Dopo aver creato l'editor di tipi con interfaccia utente personalizzato, è possibile esaminare altri sistemi per interagire con un oggetto PropertyGrid e l'ambiente di progettazione:

Vedere anche

Attività

Procedura: creare un controllo Windows Form che utilizza le funzionalità di progettazione

Riferimenti

UITypeEditor

EditorAttribute

PropertyGrid

Altre risorse

Editor di tipo con interfaccia utente