Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#
Article

Targeting Design-Time Events of User Controls

Rate me:
Please Sign up or sign in to vote.
4.63/5 (24 votes)
22 Mar 2006CPOL6 min read 113.3K   1K   48   33
The article will go over various design-time features including smart tags, menu items, adornments.
Sample Image - Web.gif

Introduction

Well here it is, a seemlessly useless control. There is nothing for the user of this control, but for the developer this is a control that is rich in design-time features. This article will go over many features of design-time developing with Visual Studio .NET 2005. The topics that will be covered include smart tags, menu items, adornments, and design-time interaction. To show you these various features, I have designed a 'target control', this is a control that will, as you may have guessed, create a target on a form. This target will be a multi-colored group of circles centered around a point at the center of the control. Through the design-time features discussed, you will be able to change the width of a circle by dragging portions of a circle, add circles through right-click menus, and change the colors used in the control through smart tags.

Control Designer

The key concept for giving a user control design-time features is the control designer. There are many designers available for various forms of user controls. Most designers can be found in the System.Windows.Forms.Design namespace, although some designers can also be found in the System.ComponentModel.Design namespace. Two common designers are the ParentControlDesigner and the ControlDesigner which can be found in the System.Windows.Forms.Design namespace. For the purpose of this article, we will use the ControlDesigner since our control will not be parent to other user controls.

The ControlDesigner gives us the capability of adding a multitude of features to a control during design-time, many of which include:

  1. ActionLists - Give support for smart tags
  2. Verbs - Give the capability for right-click menus
  3. Adornments - Additional method that allows us to add painting to our control
  4. WndProc - Allows you to encapsulate all events that take place during a user controls' design time events
  5. Other basic properties:
    • EnableDragRect - Allows you to disable the drag rectangle that is by default painted on a user-control
    • ParticipatesWithSnapLines - Allows you to disable the use of SnapLines which is a new feature to the Visual Studio .NET 2005 IDE
    • SelectionRules - Allows you to set how your control can interact with the form designer--whether you can move a control, and how the control can be selected
  6. Other features - There are a few other less important features that may not be covered by this article

Smart Tags

Smart tags are fairly simple to incorporate into a user control's design time features. As stated previously, ActionLists give us the ability to use smart tags, so that is where I will begin to explain. An ActionList is basically a group of methods and properties of a control that you would want to change dynamically during design-time.

To use an ActionList, you need to create a class inherited from a DesignerActionList in the System.ComponentModel.Design namespace. There is only one overridable method that is absolutely required to use smart tags with your control. That method which will be overridden will be the initialization of the DesignerActionList. With the following code snippet, I am overriding the base classes new functionality so that I can get a handle of the Target control that this ActionList will be interacting with, the dtc (DesignTimeControl) variable is a local variable of a Target Control.

C#
public Target_ActionsList(IComponent component)
   : base(component)
{
   this.dtc = component as Target;

   // Cache a reference to DesignerActionUIService, so the
   // DesigneractionList can be refreshed.
   this.designerActionUISvc =
        GetService(typeof(DesignerActionUIService))
   as DesignerActionUIService;
}

After the initialization is complete and we have a handle to the Target control, we can start adding methods and properties that will be seen on the smart tags for the Target control. Adding methods and properties to a smart tag is easy, but adding methods and properties that will affect the actual code is a bit more difficult. The following code snippet has a method called GetPropertyByName this will give us a handle to the PropertyDescriptor of a particular property so that we can effectively edit its properties.

C#
private PropertyDescriptor GetPropertyByName(String propName)
{
   PropertyDescriptor prop;
   prop = TypeDescriptor.GetProperties(dtc)[propName];
   if (null == prop)
      throw new ArgumentException(
            "Matching Target property not found!",
            propName);
   else
     return prop;
}

Once we get the PropertyDescriptor of a property, we will be able to get and set the value of a property of the Target control. The following example shows two public properties and one public method that will be shown on the smart tags for the Target control. Note how the GetPropertyByName method is used to set the values for the dtc or Target control.

C#
public Color Color1
{
   get { return this.dtc.Color1; }
   set { GetPropertyByName("Color1").SetValue(dtc, value); }
}
public Color Color2
{
   get { return this.dtc.Color2; }
   set { GetPropertyByName("Color2").SetValue(dtc, value); }
}
public void InvertTargetColors()
{
   Color tmp = dtc.Color1;
   Color1 = dtc.Color2;
   Color2 = tmp;
}

To complete the use of smart tags, you must override the ActionLists property in the ControlDesigner. You will create a new instance of the inherited ActionList and add the list to a DesignerActionListCollection which in the following example is called actionLists.

C#
public override DesignerActionListCollection ActionLists
{
   get
   {
      if (null == actionLists)
      {
          actionLists = new DesignerActionListCollection();
          actionLists.Add(
               new Target_ActionsList(this.Component));
      }
      return actionLists;
   }
}

Right-Click Menu Items

Verbs in the ControlDesigner give us the ability to add any necessary menu items that we see fit in the right-click menu of the control. To begin adding right-click menu items, we must first create a new instance of the DesignerVerbCollection to the controls designer. After we have created an instance of the DesignerVerbCollection, we will add a DesignerVerb to the collection. In the snippet below, we add two menu items to the right-click menu and add two event handlers that will handle when the two menu items are clicked. When interacting with the Target control, we must make sure that we use the GetPropertiesByName method to edit the properties for the control, or a change in the properties will not affect the run-time of the control.

C#
private DesignerActionListCollection actionLists;
public Target_Designer()
{
    dvc.Add(new DesignerVerb("Invert Colors of Target", 
            new EventHandler(InvertColors)));
    dvc.Add(new DesignerVerb("Add Circle", new EventHandler(AddCircle)));
} 

Adornments

Adornments is a fancy term basically meaning that you can add more paint events to the control that is being designed. OnPaintAdornments is an overridable method in the ControlDesigner that will allow you to paint anything you want on a control that is only seen during design-time. A few uses for adornments include copyright notices. For this control, I have the text "This is a Target Control" painted on the control when the control is active. The following code example shows how I accomplished this. The text variable contains the text that is to be displayed on the Target control, you can easily replace the text with a copyright notice for your control.

C#
protected override void OnPaintAdornments(PaintEventArgs e)
{
   if (mouseover)
   {
       string text = "This control is a Target Control";
       e.Graphics.FillRectangle(new SolidBrush(Color.LightYellow), 
        new Rectangle(0, this.Control.Height - 
        (int)e.Graphics.MeasureString(text, this.Control.Font).Height - 3, 
        (int)e.Graphics.MeasureString(text, this.Control.Font).Width + 3, 
        (int)this.Control.Font.Height));
       e.Graphics.DrawRectangle(new Pen(Color.Black), 
        new Rectangle(0, this.Control.Height - 
        (int)e.Graphics.MeasureString(text, this.Control.Font).Height - 3, 
        (int)e.Graphics.MeasureString(text, this.Control.Font).Width + 3, 
        (int)this.Control.Font.Height));
       e.Graphics.DrawString(text, this.Control.Font, 
        new SolidBrush(Color.Black), 0, this.Control.Height - 
        (int)e.Graphics.MeasureString(text, this.Control.Font).Height - 3);
   }
}

WndProc

The WndProc of the ControlDesigner works the same way as if the control was working on a regular form, but anything that is included with the ControlDesigner's WndProc will not affect the run-time of the control. That is unless you use the GetPropertiesByName method to set a property for the control. With the target control, I have implemented a sort of complicated way to change the dimensions of each circle on the target during design-time. The result of what I will explain is a square on four corners of each circle, when the left or top square is dragged the circle will decrease in size, when the right and bottom square is dragged the circle will increase in size. To accomplish this I drew squares, in the WndProc, on four sides of each circle in the Target control. I then made a collection of the possible points that each square can take up and what circle belongs with what points. I then intercept the WM_MOUSEMOVE event and check the coordinates of the mouse cursor, if the cursor is in the collection of points, I will resize the specified circle.

Conclusion

I do hope this article will help many programmers in creating more manageable user controls that will both be appealing to the user and easy to manage during design time.

History

  • 22nd March, 2006: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer University of Michigan-Flint
United States United States
I am currently a Database Administrator & Developer for the International Center at the University of Michigan. My expertise is GUI design with WinForms and WPF.

Comments and Discussions

 
SuggestionGreat Sample Code and Target Framework Note Pin
KillerJimmy9-Mar-12 6:07
KillerJimmy9-Mar-12 6:07 
GeneralRe: Great Sample Code and Target Framework Note Pin
Thomas Stockwell9-Mar-12 6:49
professionalThomas Stockwell9-Mar-12 6:49 
QuestionHow to provide user interaction for ToolStripControlHost items? Pin
Qwertie6-Aug-08 14:55
Qwertie6-Aug-08 14:55 
AnswerRe: How to provide user interaction for ToolStripControlHost items? Pin
Thomas Stockwell6-Aug-08 15:39
professionalThomas Stockwell6-Aug-08 15:39 
QuestionWhat is a smart tag? Pin
Qwertie6-Aug-08 14:49
Qwertie6-Aug-08 14:49 
AnswerRe: What is a smart tag? Pin
Thomas Stockwell6-Aug-08 15:42
professionalThomas Stockwell6-Aug-08 15:42 
Questionhow can i add this user control to toolbox? Pin
skipio9629-Nov-07 20:58
skipio9629-Nov-07 20:58 
AnswerRe: how can i add this user control to toolbox? Pin
Thomas Stockwell30-Nov-07 1:31
professionalThomas Stockwell30-Nov-07 1:31 
GeneralDock in parent container Pin
Paul Talbot22-Oct-07 22:25
Paul Talbot22-Oct-07 22:25 
GeneralThank you for this! Pin
Paul Talbot22-Oct-07 4:14
Paul Talbot22-Oct-07 4:14 
Questionsmart tag for user control Pin
User-Rock1-Oct-07 21:00
User-Rock1-Oct-07 21:00 
AnswerRe: smart tag for user control Pin
Thomas Stockwell2-Oct-07 0:11
professionalThomas Stockwell2-Oct-07 0:11 
QuestionRe: smart tag for user control Pin
User-Rock2-Oct-07 1:32
User-Rock2-Oct-07 1:32 
AnswerRe: smart tag for user control Pin
Paul Talbot22-Oct-07 4:09
Paul Talbot22-Oct-07 4:09 
GeneralSmartPane does not refresh Pin
Alan Seedhouse6-Mar-07 22:07
professionalAlan Seedhouse6-Mar-07 22:07 
GeneralRe: SmartPane does not refresh Pin
Thomas Stockwell9-Mar-07 13:01
professionalThomas Stockwell9-Mar-07 13:01 
GeneralRe: SmartPane does not refresh Pin
Alan Seedhouse20-Mar-07 1:50
professionalAlan Seedhouse20-Mar-07 1:50 
Questionthe control draggin Pin
Cioce6-Feb-07 9:09
Cioce6-Feb-07 9:09 
AnswerRe: the control draggin Pin
Thomas Stockwell7-Feb-07 3:26
professionalThomas Stockwell7-Feb-07 3:26 
GeneralRe: the control draggin Pin
Cioce7-Feb-07 11:48
Cioce7-Feb-07 11:48 
GeneralRe: the control draggin Pin
mikevandre8-Feb-07 6:11
mikevandre8-Feb-07 6:11 
GeneralRe: the control draggin Pin
Thomas Stockwell8-Feb-07 9:50
professionalThomas Stockwell8-Feb-07 9:50 
GeneralWndProc for Resize Pin
HydReddy11-Jan-07 6:05
HydReddy11-Jan-07 6:05 
GeneralRe: WndProc for Resize Pin
Thomas Stockwell11-Jan-07 13:23
professionalThomas Stockwell11-Jan-07 13:23 
GeneralRe: WndProc for Resize Pin
HydReddy12-Jan-07 4:01
HydReddy12-Jan-07 4:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.