Custom Controls Design Time Support Part 1: Design Time Attributes

As I mentioned in my previous post, I am willing to write a multi part tutorial on how to add Design Time Support to your custom controls.

In this part, I will talk about the common attributes for Properties and Events

Attribute Applied To Description
Browsable Properties and events Specifies whether a property or an event should be displayed in the property browser.
Category

Properties and events

Specifies the name of the category in which to group a property or event. When categories are used, component properties and events can be displayed in logical groupings in the property browser.
Description Properties and events Defines a small block of text to be displayed at the bottom of the property browser when the user selects a property or event.
DefaultProperty Properties
(Insert this attribute before the class declaration.)
Specifies the default property for the component. This property is selected in the property browser when a user clicks on the control.
DefaultValue Properties Sets a simple default value for a property.
DefaultEvent Events
(Insert this attribute before the class declaration.)
Specifies the default event for the component. This is the event that is selected in the property browser when a user clicks on the component.

To illustrate how these attributes work I need first to set a custom control, let's start with simple windows forms button. [more]

[code:c#]

using System;
using System.Windows.Forms;

namespace Elsehemy.Controls
{
  public class ButtonEx : Button
  {
  
  }
}

[/code]

Now add a property to make use of some attributes (I will use simple ones first)

[code:c#]

private int _numOfClicks;

public int NumOfClicks
{
  get { return _numOfClicks; }
  set { _numOfClicks = value; }
}

[/code]

Now add the ButtonEx control to a windows form to test the effect of attributes one by one.

[code:c#]

[Description("Tells how many time the button has been clicked")]
public int NumOfClicks{…}

[/code]

DescriptionAttribute

[code:c#]

[Category("Special Properties")]
[Description("Tells how many time the button has been clicked")]
public int NumOfClicks{…}

[/code]

[code:c#]

[DefaultValue(10)]
[Category("Special Properties")]
[Description("Tells how many time the button has been clicked")]
public int NumOfClicks{…}

[/code]

As you can notice the default value attribute now enabled the Reset context menu item which (of course) will reset the Property value to 10, the Reset command is only enabled when the value is not equal to 10, further more the value is always bold when it is not the default.

NOTE: The DefaultValue Attribute just writes the value of the box beside the property name to the value chosen, which means the actual inner variable isn't set to that value, so if you reset the value and 10 is written then ran the program and tested for NumOfClicks value you will find it equal to 0, even though its written 10.

Solution: Make sure to set the default value in the constructor of the control to have it work as expected.

More on DefaultValue Attribute as you already noticed the constructor has overloads for different types however all types are simple (bool, int, short, string ….) and one more constructor overload that has 2 parameters a type and a string value, consider we have a System.Drawing.Color Property that needs to have a default value.

[code:c#]

[DefaultValue(typeof(System.Drawing.Color),"Red")]
public System.Drawing.Color ColorProperty

[/code]

More over not only KnownColors can be set as default values, you can set the default value as RGB by supplying its Hex value..

[code:c#]

[DefaultValue(typeof(System.Drawing.Color),"#FFBA00")]
public System.Drawing.Color ColorProperty

[/code]

Sometimes there are more complex properties that need default values as System.Drawing.Font where DefaultValueAttribute will not fit, two special purpose methods named

void ResetPropertyname(), bool ShouldSerializePropertyname().

if Reset method is available it will be called one Reset command, ShouldSerialize method is for (should the designer generate a line in the form.designer.cs file or not) so obviously you should serialize when the value is not the default and not serialize if the property value is changed.

[code:c#]

System.Drawing.Font f;
public System.Drawing.Font FontProperty
{
  get
  {
    if (f == null)
      return this.Font; //this should be the default value you want
    else return f;
  }
  set { f = value; }
}

void ResetFontProperty()
{
  f = null;
}
bool ShouldSerializeFontProperty()
{
  return f == null ? false : true;
}

[/code]

The DefaultPropertyAttribute just tells the designer which Property should be selected when the PropretyWindow opens (control:right click > Properties Or selected control: press F4). For example, Text is the default property of the TextBox control.

The DefaultEventAttribute tells the designer which Event should be selected when the ProperyWindow (Events Tab) opens, more over when double click the control the designer will generate an event handler method for that event. For example, Click is the default event of the Button control.

[code:c#]

[DefaultEvent("NumofClicksChanged")]
[DefaultProperty("NumOfClicks"]

public class ButtonEx : Button

[/code]

To be continued…

References:

http://msdn2.microsoft.com/en-us/library/tk67c2t8.aspx

Download Code : ButtonEx.cs (2.10 kb)


Posted

in

,

by

Tags:

Comments

6 responses to “Custom Controls Design Time Support Part 1: Design Time Attributes”

  1. Renaud Bompuis Avatar

    Thanks for taking the time to write this series.
    It’s been very useful.

  2. Tristen Fielding Avatar
    Tristen Fielding

    I agree, thank you very much for taking the time to write this series. I’ve read a lot about creating custom controls and I can say without a doubt, your series has be the most direct, easy to understand reading I have ever read on the subject.

    Thanks again, keep up the good work! I’m excited to see/read what ever you have next.

  3. Shearn Avatar
    Shearn

    Amr,

    I am now just learning how to use these components you’re discussing in your series, so please forgive my ignorance. And thank you so much for simplifying the explanation.

    I’m confused as to where the sample codes you provided should go to? Would it be [UserControl1].cs or [UserControl1].Designer.cs (where [UserControl1] is the actual file name one is using)? If I put it in UserContro1.cs, it’s complaining that there’s no suitable override method found for the .Dispose(bool), since that method exists in the .Designer.cs file. However, if I put it in the .Designer.cs file, then I’ll need to redeclare all the "using …." (e.g. using System.Drawing, System.Collection, etc).

    So what’s the correct location for these codes?

  4. Amr Avatar

    Hello Shearn,

    Just to be sure at first, do you know the difference between a UserControl and a CustomControl? if u do skip the next paragraph.

    UserControls are a special type of custom controls that have a designer ready for you just as the "Form" class, where you drag and drop already made controls to end up with a big container of other controls, While CustomControls are controls that are not already there with different functionality (think of a circular progress bar) or eventhere and just adding some functionality like having a button that glows when the mouse hovers on it.

    Now, both types of controls can have design time support, all u have to do is just have your class (control) ready (functional wise) and design time support only adds some fun and help for the developer using this control, this means that to have design time support u must already have ur own control that has new properties or events or both and u need to support them, finally i didnt get the part u want to override the dispose function why is that?

  5. Shearn Avatar
    Shearn

    Hi Amr,

    yes, I do know the difference between User and Custom control. Sorry, I should have made that clearer. What I am wanting to do is a User control, consisting of a number of pre-made controls in a big container but adding a bunch of functionalities to be consumed by the user. Here’s the situation I’m in: My control contains a TabControl. However, I need to be able to control the custom TabPages that get added/removed (I said custom TabPage because the tabpage contains a DataGridView control). What I’d like to do is to allow the user who consumes this control to be able to set what tabpages he wants to see (it can be one or a combination of these tabpages), and I will take care of creating that tabpage and adding the DataGridView to the tabpage. This part I currently have working. Not an elegant solution, but it is working (what I would love to do is somehow create a custom TabPage collection property. But what I currently have is basically a True/False property for each tabpage. True to show in the TabControl, False otherwise). Now the part I can’t figure out is how to give user the ability to see the addition/removal of these tabpages at design-time and also the ability to reorder the tabpages also during design-time. I know this question is probably very hard to grasp unless you see what I am doing, so don’t worry if you don’t understand. I believe there are a lot of information in your series that I can use to come to a solution.

    As for the part you didn’t understand, please ignore it. I just went back to look closely at what I’ve done and found out it was my own mistake. Sorry.

  6. Amr Avatar

    Shearn,
    You can do that after reading a little about (Designers) , which are classes you write that take care of your control in the design time (take care means respond to your events (drags, drops ordering tabs, etc..) ) so that is the place you start from, my blog has some parts talking about designers which can give you a start,
    And good luck

Leave a Reply

Your email address will not be published. Required fields are marked *