The following sample is an extender provider that provides a help label extender property for the FlashTrackBar sample in the Win Forms Control Sample. To download the source code, see the Win Forms Quickstart.
The sample shows the following key steps.
[C#] namespace SampleControlPack { using System; using System.Collections; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.WinForms; using System.WinForms.Design; // // <doc> // <desc> // Help Label offers an extender property called // "HelpText". It monitors the active control // and displays the help text for the active control. // </desc> // </doc> // [ ProvideProperty("HelpText"), Designer(typeof(HelpLabel.HelpLabelDesigner)) ] public class HelpLabel : RichControl, IExtenderProvider { private Hashtable helpTexts; private Control activeControl; // // <doc> // <desc> // Creates a new help label object. // </desc> // </doc> // public HelpLabel() { helpTexts = new Hashtable(); BackColor = SystemColors.Info; ForeColor = SystemColors.InfoText; TabStop = false; } // // <doc> // <desc> // Overrides the default tab stop property. // Changes the default value to be false. // </desc> // </doc> // [ DefaultValue(false) ] public bool TabStop { override get { return base.TabStop; } override set { base.TabStop = value; } } // // <doc> // <desc> // Overrides the text property of RichControl. The help label //ignores the text property, // so you have to add additional attributes here so that the // property does not show up in the property browser and is not // persisted. // </desc> // </doc> // [ Browsable(false), Persistable(PersistableSupport.None) ] public string Text { override get { return base.Text; } override set { base.Text = value; } } // // <doc> // <desc> // 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 HelpLabel is interested in providing the extended // property for the // component. You return true here if the object is a control, // but is not a HelpLabel (because it not meaningful for // HelpLabel to add the property to itself). // </desc> // </doc> // bool IExtenderProvider.CanExtend(object target) { if (target is Control && !(target is HelpLabel)) { return true; } return false; } // // <doc> // <desc> // This is the extended HelpText property. // Extended properties are actually methods because they take an // additional parameter // that is the object or control to provide the property for. // </desc> // </doc> // [ DefaultValue(""), ExtenderProperty(typeof(Control)) ] public string GetHelpText(Control control) { string text = (string)helpTexts[control]; if (text == null) { text = string.Empty; } return text; } // // <doc> // <desc> // This is an event handler that responds to the OnControlEnter // event. You should attach this to each control you // are providing help text for. // </desc> // </doc> // private void OnControlEnter(object sender, EventArgs e) { activeControl = (Control)sender; Invalidate(); } // // <doc> // <desc> // This is an event handler that responds to the OnControlLeave //event. You should attach this to each control we are providing //help text for. // </desc> // </doc> // private void OnControlLeave(object sender, EventArgs e) { if (sender == activeControl) { activeControl = null; Invalidate(); } } // // <doc> // <desc> // This is the extended property for the HelpText property. // </desc> // </doc> // public void SetHelpText(Control control, string value) { if (value == null) { value = string.Empty; } if (value.Length == 0) { helpTexts.Remove(control); control.RemoveOnEnter(new EventHandler(OnControlEnter)); control.RemoveOnLeave(new EventHandler(OnControlLeave)); } else { helpTexts[control] = value; control.AddOnEnter(new EventHandler(OnControlEnter)); control.AddOnLeave(new EventHandler(OnControlLeave)); } if (control == activeControl) { Invalidate(); } } // // <doc> // <desc> // Overrides RichControl.OnPaint to draw the label. // </desc> // </doc> // protected override void OnPaint(PaintEventArgs pe) { // Let the base draw. This will take care // of the back color // and set any image that the user may have // provided. // base.OnPaint(pe); // Draw a rectangle around the control. // Rectangle rect = ClientRectangle; Pen borderPen = new Pen(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 (text != null && text.Length > 0) { rect.Inflate(-2, -2); Brush brush = new SolidBrush(ForeColor); pe.Graphics.DrawString(text, NewFont, brush, rect); brush.Dispose(); } } } // <doc> // <desc> // Returns true if the backColor should be persisted in code gen. // You override this to change the default back color. // </desc> // <retvalue> // true if the backColor should be persisted. // </retvalue> // </doc> // public override bool ShouldPersistBackColor() { return(!BackColor.Equals(SystemColors.Info)); } // <doc> // <desc> // Returns true if the foreColor should be persisted in code gen. // Override this to change the default foreground color. // </desc> // <retvalue> // true if the foreColor should be persisted. // </retvalue> // </doc> // public override bool ShouldPersistForeColor() { return(!ForeColor.Equals(SystemColors.InfoText)); }