Επεξεργασία

Κοινή χρήση μέσω


IExtenderProvider Interface

Definition

Defines the interface for extending properties to other components in a container.

public interface class IExtenderProvider
public interface IExtenderProvider
type IExtenderProvider = interface
Public Interface IExtenderProvider
Derived

Examples

The following code example demonstrates how to implement the IExtenderProvider interface. This example is part of a larger example discussed in How to: Implement a HelpLabel Extender Provider.


using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace Microsoft.Samples.WinForms.Cs.HelpLabel;
//
// Help Label offers an extender property called
// "HelpText".  It monitors the active control
// and displays the help text for the active control.
//
[
ProvideProperty("HelpText", typeof(Control)),
Designer(typeof(HelpLabelDesigner))
]
public class HelpLabel : Control, IExtenderProvider
{
    /// <summary>
    ///    Required designer variable.
    /// </summary>
    Container components;
    readonly Hashtable helpTexts;
    Control activeControl;

    //
    //      Creates a new help label object.
    //
    public HelpLabel()
    {
        //
        // Required for Windows Form Designer support
        //
        InitializeComponent();

        helpTexts = [];
    }

    /// <summary>
    ///    Clean up any resources being used.
    /// </summary>
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    /// <summary>
    ///    Required method for Designer support - do not modify
    ///    the contents of this method with the code editor.
    /// </summary>
    void InitializeComponent()
    {
        BackColor = SystemColors.Info;
        components = new Container();
        ForeColor = SystemColors.InfoText;
        TabStop = false;
    }

    //
    //      Overrides the text property of Control.  This label ignores
    //      the text property, so we add additional attributes here so the
    //      property does not show up in the properties window and is not
    //      persisted.
    //
    [
    Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
    ]
    public override string Text
    {
        get => base.Text; set => base.Text = value;
    }

    //
    //      This implements the IExtenderProvider.CanExtend method.  The
    //      help label provides an extender property, and the design time
    //      framework will call this method once for each component to determine
    //      if we are interested in providing our extended properties for the
    //      component.  We return true here if the object is a control and is
    //      not a HelpLabel (since it would be silly to add this property to
    //      ourselves).
    //
    bool IExtenderProvider.CanExtend(object target) => target is Control and
            not HelpLabel;

    //
    //      This is the extended property for the HelpText property.  Extended
    //      properties are actual methods because they take an additional parameter
    //      that is the object or control to provide the property for.
    //
    [
    DefaultValue(""),
    ]
    public string GetHelpText(Control control)
    {
        string text = (string)helpTexts[control];
        text ??= string.Empty;
        return text;
    }

    //
    //      This is an event handler that responds to the OnControlEnter
    //      event.  We attach this to each control we are providing help
    //      text for.
    //
    void OnControlEnter(object sender, EventArgs e)
    {
        activeControl = (Control)sender;
        Invalidate();
    }

    //
    //      This is an event handler that responds to the OnControlLeave
    //      event.  We attach this to each control we are providing help
    //      text for.
    //
    void OnControlLeave(object sender, EventArgs e)
    {
        if (sender == activeControl)
        {
            activeControl = null;
            Invalidate();
        }
    }

    //
    //      This is the extended property for the HelpText property.
    //
    public void SetHelpText(Control control, string value)
    {
        value ??= string.Empty;

        if (value.Length == 0)
        {
            helpTexts.Remove(control);

            control.Enter -= OnControlEnter;
            control.Leave -= OnControlLeave;
        }
        else
        {
            helpTexts[control] = value;

            control.Enter += OnControlEnter;
            control.Leave += OnControlLeave;
        }

        if (control == activeControl)
        {
            Invalidate();
        }
    }

    //
    //      Overrides Control.OnPaint.  Here we draw our
    //      label.
    //
    protected override void OnPaint(PaintEventArgs pe)
    {
        // Let the base draw.  This will cover our back
        // color and set any image that the user may have
        // provided.
        //
        base.OnPaint(pe);

        // Draw a rectangle around our control.
        //
        Rectangle rect = ClientRectangle;

        Pen borderPen = new(ForeColor);
        pe.Graphics.DrawRectangle(borderPen, rect);
        borderPen.Dispose();

        // Finally, draw the text over the top of the
        // rectangle.
        //
        if (activeControl != null)
        {
            string text = (string)helpTexts[activeControl];
            if (!string.IsNullOrEmpty(text))
            {
                rect.Inflate(-2, -2);
                Brush brush = new SolidBrush(ForeColor);
                pe.Graphics.DrawString(text, Font, brush, rect);
                brush.Dispose();
            }
        }
    }

    //     Returns true if the backColor should be persisted in code gen.  We
    //      override this because we change the default back color.
    //     true if the backColor should be persisted.
    //
    public bool ShouldSerializeBackColor() => !BackColor.Equals(SystemColors.Info);

    //     Returns true if the foreColor should be persisted in code gen.  We
    //      override this because we change the default foreground color.
    //     true if the foreColor should be persisted.
    //
    public bool ShouldSerializeForeColor() => !ForeColor.Equals(SystemColors.InfoText);

    //
    //      This is a designer for the HelpLabel.  This designer provides
    //      design time feedback for the label.  The help label responds
    //      to changes in the active control, but these events do not
    //      occur at design time.  In order to provide some usable feedback
    //      that the control is working the right way, this designer listens
    //      to selection change events and uses those events to trigger active
    //      control changes.
    //
    public class HelpLabelDesigner : ControlDesigner
    {
        bool trackSelection = true;

        /// <summary>
        /// This property is added to the control's set of properties in the method
        /// PreFilterProperties below.  Note that on designers, properties that are
        /// explicitly declared by TypeDescriptor.CreateProperty can be declared as
        /// private on the designer.  This helps to keep the designer's public
        /// object model clean.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        bool TrackSelection
        {
            get => trackSelection;
            set
            {
                trackSelection = value;
                if (trackSelection)
                {
                    ISelectionService ss = (ISelectionService)GetService(typeof(ISelectionService));
                    if (ss != null)
                    {
                        UpdateHelpLabelSelection(ss);
                    }
                }
                else
                {
                    HelpLabel helpLabel = (HelpLabel)Control;
                    if (helpLabel.activeControl != null)
                    {
                        helpLabel.activeControl = null;
                        helpLabel.Invalidate();
                    }
                }
            }
        }

        public override DesignerVerbCollection Verbs
        {
            get
            {
                DesignerVerb[] verbs = [
                                                            new("Sample Verb", new EventHandler(OnSampleVerb))
                                                          ];
                return [.. verbs];
            }
        }

        //
        //      Overrides Dispose.  Here we remove our handler for the selection changed
        //      event.  With designers, it is critical that they clean up any events they
        //      have attached.  Otherwise, during the course of an editing session many
        //      designers may get created and never destroyed.
        //
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                ISelectionService ss = (ISelectionService)GetService(typeof(ISelectionService));
                if (ss != null)
                {
                    ss.SelectionChanged -= OnSelectionChanged;
                }
            }

            base.Dispose(disposing);
        }

        //
        //       Overrides initialize.  Here we add an event handler to the selection service.
        //      Notice that we are very careful not to assume that the selection service is
        //      available.  It is entirely optional that a service is available and you should
        //      always degrade gracefully if a service could not be found.
        //
        public override void Initialize(IComponent component)
        {
            base.Initialize(component);

            ISelectionService ss = (ISelectionService)GetService(typeof(ISelectionService));
            if (ss != null)
            {
                ss.SelectionChanged += OnSelectionChanged;
            }
        }

        void OnSampleVerb(object sender, EventArgs e) => MessageBox.Show("You have just invoked a sample verb.  Normally, this would do something interesting.");

        //
        //      Our handler for the selection change event.  Here we update the active control within
        //      the help label.
        //
        void OnSelectionChanged(object sender, EventArgs e)
        {
            if (trackSelection)
            {
                ISelectionService ss = (ISelectionService)sender;
                UpdateHelpLabelSelection(ss);
            }
        }

        protected override void PreFilterProperties(IDictionary properties)
        {
            // Always call base first in PreFilter* methods, and last in PostFilter*
            // methods.
            base.PreFilterProperties(properties);

            // We add a design-time property called "TrackSelection" that is used to track
            // the active selection.  If the user sets this to true (the default), then
            // we will listen to selection change events and update the control's active
            // control to point to the current primary selection.
            properties["TrackSelection"] = TypeDescriptor.CreateProperty(
                GetType(),        // the type this property is defined on
                "TrackSelection",    // the name of the property
                typeof(bool),        // the type of the property
                [CategoryAttribute.Design]);    // attributes
        }

        /// <summary>
        /// This is a helper method that, given a selection service, will update the active control
        /// of our help label with the currently active selection.
        /// </summary>
        /// <param name="ss"></param>
        void UpdateHelpLabelSelection(ISelectionService ss)
        {
            HelpLabel helpLabel = (HelpLabel)Control;
            if (ss.PrimarySelection is Control c)
            {
                helpLabel.activeControl = c;
                helpLabel.Invalidate();
            }
            else
            {
                if (helpLabel.activeControl != null)
                {
                    helpLabel.activeControl = null;
                    helpLabel.Invalidate();
                }
            }
        }
    }
}
Option Strict On
Option Explicit On 
Imports System.Collections
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Windows.Forms.Design

Namespace Microsoft.Samples.WinForms.Vb.HelpLabel
    '
    ' Help Label offers an extender property called
    ' HelpText.  It monitors the active control
    ' and displays the help text for the active control.
    '

    <ProvideProperty("HelpText", GetType(Control)), Designer(GetType(HelpLabel.HelpLabelDesigner))> _
    Public Class HelpLabel
        Inherits Control
        Implements System.ComponentModel.IExtenderProvider
        '    Required designer variable.
        Private components As System.ComponentModel.Container
        Private helpTexts As Hashtable
        Private activeControl As System.Windows.Forms.Control

        '
        '      Creates a new help label object.
        '
        Public Sub New()
            '
            ' Required for Windows Form designer support.
            '
            InitializeComponent()
            helpTexts = New Hashtable
        End Sub

        '    Clean up any resources being used.
        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                If components IsNot Nothing Then
                    components.Dispose()
                End If
            End If
            MyBase.Dispose(disposing)
        End Sub

        '    Required method for designer support. Do not modify
        '    the contents of this method with the code editor.
        Private Sub InitializeComponent()
            Me.components = New System.ComponentModel.Container
            Me.BackColor = System.Drawing.SystemColors.Info
            Me.ForeColor = System.Drawing.SystemColors.InfoText
            Me.TabStop = False
        End Sub
        '
        '      Overrides the text property of Control.  This label ignores
        '      the text property, so we add additional attributes here so the
        '      property does not show up in the Properties window and is not
        '      persisted.
        '
        <Browsable(False), _
        EditorBrowsable(EditorBrowsableState.Never), _
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public Overrides Property [Text]() As String
            Get
                Return MyBase.Text
            End Get
            Set(ByVal Value As String)
                MyBase.Text = Value
            End Set
        End Property


        '
        '      This implements the IExtenderProvider.CanExtend method.  The
        '      help label provides an extender property, and the design-time
        '      framework will call this method once for each component to determine
        '      if we are interested in providing our extended properties for the
        '      component.  We return true here if the object is a control and is
        '      not a HelpLabel (because it would not be meaningful to add this property to
        '      ourselves).
        '
        Function CanExtend(ByVal target As Object) As Boolean Implements IExtenderProvider.CanExtend
            If TypeOf target Is Control And Not TypeOf target Is HelpLabel Then

                Return True
            End If
            Return False
        End Function

        '
        '      This is the extended property for the HelpText property.  Extended
        '      properties are actual methods because they take an additional parameter
        '      that is the object or control to provide the property for.
        '
        <DefaultValue("")> _
        Public Function GetHelpText(ByVal ctrl As Control) As String
            Dim myText As String = CStr(helpTexts(ctrl))
            If myText Is Nothing Then
                myText = String.Empty
            End If
            Return myText
        End Function

        '
        '      This is the extended property for the HelpText property.
        '
        Public Sub SetHelpText(ByVal ctrl As Control, ByVal value As String)
            If value Is Nothing Then
                value = String.Empty
            End If

            If value.Length = 0 Then
                helpTexts.Remove(ctrl)

                RemoveHandler ctrl.Enter, AddressOf OnControlEnter
                RemoveHandler ctrl.Leave, AddressOf OnControlLeave
            Else
                helpTexts(ctrl) = value
                AddHandler ctrl.Enter, AddressOf OnControlEnter
                AddHandler ctrl.Leave, AddressOf OnControlLeave
            End If

            If ctrl Is activeControl Then
                Invalidate()
            End If
        End Sub

        '
        '      This is an event handler that responds to the OnControlEnter
        '      event.  We attach this to each control we are providing help
        '      text for.
        '
        Private Sub OnControlEnter(ByVal sender As Object, ByVal e As EventArgs)
            activeControl = CType(sender, Control)
            Invalidate()
        End Sub

        '
        '      This is an event handler that responds to the OnControlLeave
        '      event.  We attach this to each control we are providing help
        '      text for.
        '
        Private Sub OnControlLeave(ByVal sender As Object, ByVal e As EventArgs)
            If sender Is activeControl Then
                activeControl = Nothing
                Invalidate()
            End If
        End Sub

        '
        '      Overrides Control.OnPaint.  Here we draw our
        '      label.
        '
        Protected Overrides Sub OnPaint(ByVal pe As PaintEventArgs)
            ' Let the base draw.  This will cover our back
            ' color and set any image that the user has
            ' provided.
            '
            MyBase.OnPaint(pe)

            ' Draw a rectangle around the control.
            '
            Dim rect As Rectangle = ClientRectangle

            Dim borderPen As New Pen(ForeColor)
            pe.Graphics.DrawRectangle(borderPen, rect)
            borderPen.Dispose()

            ' Finally, draw the text over the top of the
            ' rectangle.
            '
            If (activeControl IsNot Nothing) Then
                Dim myText As String = CStr(helpTexts(activeControl))
                If (myText IsNot Nothing) And myText.Length > 0 Then
                    rect.Inflate(-2, -2)
                    Dim brush As New SolidBrush(ForeColor)
                    pe.Graphics.DrawString(myText, Font, brush, RectangleF.op_Implicit(rect))
                    brush.Dispose()
                End If
            End If
        End Sub


        '     Returns true if backColor should be persisted in code gen.  We
        '      override this because we change the default back color.
        '     true if the backColor should be persisted.
        '
        Public Function ShouldSerializeBackColor() As Boolean
            Return Not BackColor.Equals(SystemColors.Info)
        End Function


        '     Returns true if foreColor should be persisted in code gen.  We
        '      override this because we change the default foreground color.
        '     true if foreColor should be persisted.
        '
        Public Function ShouldSerializeForeColor() As Boolean
            Return Not ForeColor.Equals(SystemColors.InfoText)
        End Function

        '
        '      This is a designer for the HelpLabel.  This designer provides
        '      design time feedback for the label.  The help label responds
        '      to changes in the active control, but these events do not
        '      occur at design time.  In order to provide some usable feedback
        '      that the control is working the right way, this designer listens
        '      to selection change events and uses those events to trigger active
        '      control changes.
        '
        <System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
        Public Class HelpLabelDesigner
            Inherits System.Windows.Forms.Design.ControlDesigner

            Private _trackSelection As Boolean = True

            ' This property is added to the control's set of properties in the method
            ' PreFilterProperties below.  Note that on designers, properties that are
            ' explictly declared by TypeDescriptor.CreateProperty can be declared as
            ' private on the designer.  This helps to keep the designer's public
            ' object model clean.
            <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
            Private Property TrackSelection() As Boolean
                Get
                    Return _trackSelection
                End Get
                Set(ByVal Value As Boolean)
                    _trackSelection = Value
                    If _trackSelection Then
                        Dim ss As ISelectionService = CType(GetService(GetType(ISelectionService)), ISelectionService)
                        If (ss IsNot Nothing) Then
                            UpdateHelpLabelSelection(ss)
                        End If
                    Else
                        Dim helpLabel As HelpLabel = CType(Control, HelpLabel)
                        If (helpLabel.activeControl IsNot Nothing) Then
                            helpLabel.activeControl = Nothing
                            helpLabel.Invalidate()
                        End If
                    End If
                End Set
            End Property

            Public Overrides ReadOnly Property Verbs() As DesignerVerbCollection
                Get
                    Dim myVerbs() As DesignerVerb = {New DesignerVerb("Sample Verb", AddressOf OnSampleVerb)}
                    Return New DesignerVerbCollection(myVerbs)
                End Get
            End Property

            '
            '      Overrides Dispose.  Here we remove our handler for the selection changed
            '      event.  With designers, it is critical that they clean up any events they
            '      have attached.  Otherwise, during the course of an editing session many
            '      designers might get created and never destroyed.
            '
            Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
                If disposing Then
                    Dim ss As ISelectionService = CType(GetService(GetType(ISelectionService)), ISelectionService)
                    If (ss IsNot Nothing) Then
                        RemoveHandler ss.SelectionChanged, AddressOf OnSelectionChanged
                    End If
                End If
                MyBase.Dispose(disposing)
            End Sub

            '
            '       Overrides initialize.  Here we add an event handler to the selection service.
            '      Notice that we are very careful not to assume that the selection service is
            '      available.  It is entirely optional that a service is available and you should
            '      always degrade gracefully if a service cannot be found.
            '
            Public Overrides Sub Initialize(ByVal component As IComponent)
                MyBase.Initialize(component)

                Dim ss As ISelectionService = CType(GetService(GetType(ISelectionService)), ISelectionService)
                If (ss IsNot Nothing) Then
                    AddHandler ss.SelectionChanged, AddressOf OnSelectionChanged
                End If
            End Sub

            Private Sub OnSampleVerb(ByVal sender As Object, ByVal e As EventArgs)
                MessageBox.Show("You have just invoked a sample verb.  Normally, this would do something interesting.")
            End Sub

            '
            '      The handler for the selection change event.  Here we update the active control within
            '      the help label.
            '
            Private Sub OnSelectionChanged(ByVal sender As Object, ByVal e As EventArgs)
                If _trackSelection Then
                    Dim ss As ISelectionService = CType(sender, ISelectionService)
                    UpdateHelpLabelSelection(ss)
                End If
            End Sub

            Protected Overrides Sub PreFilterProperties(ByVal properties As IDictionary)
                ' Always call base first in PreFilter* methods, and last in PostFilter*
                ' methods.
                MyBase.PreFilterProperties(properties)

                ' We add a design-time property called TrackSelection that is used to track
                ' the active selection.  If the user sets this to true (the default), then
                ' we will listen to selection change events and update the control's active
                ' control to point to the current primary selection.
                properties("TrackSelection") = TypeDescriptor.CreateProperty( _
                   Me.GetType(), _
                   "TrackSelection", _
                   GetType(Boolean), _
                   New Attribute() {CategoryAttribute.Design})
            End Sub

            ' This is a helper method that, given a selection service, will update the active control
            ' of the help label with the currently active selection.
            ' <param name="ss"></param>
            Private Sub UpdateHelpLabelSelection(ByVal ss As ISelectionService)
                Dim c As Control = CType(ss.PrimarySelection, Control)
                Dim helpLabel As HelpLabel = CType(Control, HelpLabel)
                If (c IsNot Nothing) Then
                    helpLabel.activeControl = c
                    helpLabel.Invalidate()
                Else
                    If (helpLabel.activeControl IsNot Nothing) Then
                        helpLabel.activeControl = Nothing
                        helpLabel.Invalidate()
                    End If
                End If
            End Sub

            Public Sub New()

            End Sub
        End Class

    End Class
End Namespace

Remarks

An extender provider is a component that provides properties to other components. For example, the ToolTip control is an extender provider. When you add a ToolTip control to a Form, all other controls on the form have a ToolTip property added to their list of properties.

Any component that provides extender properties must implement IExtenderProvider. A visual designer can then call CanExtend to determine which objects in a container should receive the extender properties.

For more information about extender providers, see How to: Implement an Extender Provider.

Methods

CanExtend(Object)

Specifies whether this object can provide its extender properties to the specified object.

Applies to