Click here to Skip to main content
Click here to Skip to main content

Creating Custom Controls-Providing Design Time Support 1

By , 22 Feb 2005
 

Introduction

During my interactions in the C# Forum, I came across questions on providing Design time support for custom controls. So I thought of sharing a little experience I have on this.

The Design time support architecture allows us to develop customized design time extensions using which we can configure our controls/properties of the control. Ex: Dock, Anchor properties of Button and other controls. I also encountered a similar scenario while developing a custom user control, where I needed to provide User Interface for modifying its property at design time.

Let's see in brief the .NET FrameWork support for this.

.NET Support

The .NET FrameWork has interfaces that we can use to implement customized design time support. There are three ways in which we can provide this.

  • UITypeEditor
  • TypeConverters
  • Designers

UITypeEditors:

UITypeEditors allow us to provide a custom user interface for editing the value of a property of the control. This also allows us to display the visual representation of the current value in the properties window.

TypeConverters:

TypeConverters allow us to convert the values between the types. They also allows us to provide logic for configuration of a property in the property browser.

Designers:

Designers allow us to customize the behaviour of our control at design time.

This article explains how we can use UITypeEditors and TypeConverters, to provide design time support. Using Designers are explained in the next article.

Using UITypeEditor/Property Editor

Dock, Anchor properties of .NET controls provide user interface for supplying/setting their value. These are called as Property Editors. We can use .NET FrameWork UITypeEditor class to create such interfaces for our custom properties. Property Editors are generally displayed in the drop-down area inside the properties window itself. But we can also make them to appear as modal windows.

Let's see how we can create Property Editors for our custom properties. We will use a custom control (Rectangle Control) for explaining this. Rectangle Control draw a filled rectangle. This control exposes two custom properties, RectWidth and RectHeight. Users can use these properties for setting width and height of the rectangle.

It will be more useful if we can provide a user interface (TrackBar) for supplying these values instead of asking the users to enter the values.

Sample screenshot

Fig 1: Property Editor for Setting RectHeight and RectWidth

The first step in creating the property editor is to specify the editor (WidthEditor) in the Editor attribute associated with the property procedure.

[Description("Width of the rectangle"),Editor(typeof(WidthEditor),
                                                        typeof(UITypeEditor))]
public int RectWidth
{
    get{
        return this.width;
    }
    set{
        if( value > 0){
            this.width = value;
            this.Invalidate();
          }
    }
}

The Editor attribute takes two System.Type arguments. The first argument is the type of editor. (WidthEditor - we will be creating this in the second step). The second argument is always typeof(UITypeEditor).

In the second step we have to create WidthEditor class. This class should be inherited from System.Drawing.Design.UITypeEditor class and must override two methods. They are GetEditStyle() and EditValue() methods.

The form designer calls GetEditStyle() method when it's filling the properties window with the values of all the properties of the control. This method returns an enumerated value that tells the designer whether the property editor is going to display in the drop-down area or modal form. In our example the property editor is displayed in the drop-down area.

public override UITypeEditorEditStyle 
GetEditStyle(System.ComponentModel.ITypeDescriptorContext 
context)
{
    return 
    UITypeEditorEditStyle.DropDown;
}

The form designer calls the EditValue() method when the user clicks the button beside the property name. The EditValue() method creates TrackBar control and sets the configuration details for it. (Like Range, Orientation). This method uses IWindowsFormEditorService class object to show the TrackBar control in the drop-down area.

IWindowsFormsEditorService frmsvr = 
(IWindowsFormsEditorService)provider.GetService(
                           typeof(IWindowsFormsEditorService));
frmsvr.DropDownControl(tbr); //tbr = Object of Type track 
bar

That's all we need to do. Now we can use this control by adding it to the from designer. (The attached solution has TestCustomControl project which consumes this control). When we select RectWidth or RectHeight properties, a TrackBar control will be displayed. The values of these properties can be changed using the TrackBar. When we change these values, the new value will appear in the property browser and rectangle will be redrawn with the current dimension . Very simple. Am I right?

If we want to display the modal form instead of showing it in drop-down area, we need to follow the same steps with only two differences.

  1. Return value of GetEditStyle()should be UITypeEditorEditStyle.Modal.
  2. We need to create a Form class and should add all the controls that make up the editor interface to this Form. In the EditValue() method we need to create an instance of this form. Now to show this form we need to call ShowModal() method of IWindowsFormsEditorService class.

Let's move into the second topic of this article. Using TypeConverters.

Using TypeConverters

We know that few properties (Font, Size) return objects instead of scalar values and these properties are displayed in the property browser with a "+" sign. If our custom control contain any properties that return .NET FrameWork defined objects (Font, Point, Location, Size) then they will inherit the similar behaviour. But if our custom control contains any property that returns a custom object, then how can we achieve the similar behaviour? To get that, we need to create a custom TypeConverter class.

Fig2: PhoneData property returning a custom object

Fig2:PhoneData property with "+" sign

The current example use PhoneNumber custom control. This control allows the users to enter Name, CountryCode, AreaCode, PhoneNumber details. Let's expose this data in a single property instead of exposing them in five different properties.

The first step in doing this is to create PhoneNumber class that wrap all the properties and raise PropertyChanged event when any property changes. We need to decorate this class with TypeConverter attribute.

[TypeConverter(typeof(PhoneTypeConverter))]
public class PhoneNumber
{
}

TypeConverter attribute tells the form designer that PhoneTypeConverter is associated with PhoneNumber class.

In the second step we need to create PhoneTypeConverter class which is derived from System.ComponentModel.TypeConverter and override two methods. They are GetPropertiesSupported(), GetProperties() methods.

GetPropertiesSupported() method returns whether the object supports properties or not. Form designer use this value to display "+" symbol at PhoneData property. Since our object supports properties GetPropertiesSupported() method returns true value.

GetProperties() method returns PropertiesDescriptorCollection object which will describe the items that will appear when the "+" symbol is clicked.

public override PropertyDescriptorCollection 
GetProperties(ITypeDescriptorContext context, 
               object value, Attribute[] attributes)
{
return 
TypeDescriptor.GetProperties(typeof(PhoneNumber));
}

The third and last step is to set the DesignerSerializationVisibility attribute of the PhoneData to Content.

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]

DesignerSerializationVisibility attribute specify the type of persistence to use while serializing a property on a control at design time. Setting this value to content tells VS.NET that, it should serialize the contents of this PhoneData property.

Now it's the time for compiling and using the control. When we add this control to the form designer the PhoneData property of the PhoneNumber control appear with "+" sign in the properties window. Clicking on the "+" sign will expand all the items. When we modify any value it will be displayed in the PhoneNumber control.

Conclusion

In this article we saw how we can use PropertyEditor and TypeConverters for enhancing design time support of our custom controls. In the next article we will see how we can use designers.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Kodanda Pani
Web Developer
India India
Working on .NET for last 6 years. Currently working for TCS.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberJibsta-Man23-May-13 0:16 
Just what I was looking for! Make the designer much more clean on my control.
QuestionConfigurationmemberPedrazzi6-Aug-12 9:41 
How do I change the project configuration file when we change some property in the property window? Is it possible?
 
I've tryed to use this:
EnvDTE.DTE dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.10.0");
 
But it gets just the visual studio opened first, and it would let my control linked to the VS2010 :(
QuestionNeed more help!memberZeeshan_lqp18-Aug-11 11:43 
Some time custom propery (phoneData in our example) express readonly property. But control's programmer want to allow its user to change in design time. How we will do? To understand my question observe 'Font' property of System.Windows.Form object.
GeneralMy vote of 5memberODHeart9-Mar-11 1:53 
Short and clear example of this technique. Thx a lot 4 the effort.
GeneralRe: My vote of 5memberNick Alexeev26-May-11 18:03 
I too have enjoyed reading this clearly written article!
QuestionHow to make custom property editor work in VBA?memberODHeart9-Mar-11 1:20 
Hi,
 
Thanks for a great article that has helped me a lot.
 
I am developing a control that will be used in a third party ActiveX container with VBA support. My control has a property "DataFile", which is supposed to open a FileOpen dialog. When testing the control in The C# IDE it works as expected: An ellipses button appears in the property field and the OpenFile dialog appears when activating the button. In the third party environment the ellipses button doesn't appear. It seems the custom property settings are not known to VBA.
 
// The custom editor
public class PropFileBrowser : UITypeEditor
{
public PropFileBrowser() {}
 
public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
 
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)
{
 
string fileName;
if (DrawLabDoc.GetOpenFileName(out fileName))
{
return fileName;
}
return value;
}
 
}
 
// The property definition in my ActiveX control
[Description("File with shape data."), Editor(typeof(PropFileBrowser), typeof(UITypeEditor))]
public string DataFile { get { return dataFile; } set { dataFile = value; } }
 
Is there any attributes that must be set to make the custom property event visible when the control is deployed as a COM object?
Is there a way to expose a custom properties dialog like the TreeView does?
 
Thanks in advance
Niels C. Munch

GeneralAwesome - Definately a 5 StarsmemberGreatBigYetti25-Feb-11 6:30 
Exactly what I was looking for and I couldn't find this information elsewhere
Generalinherited controls design viewmemberMember 348723110-Aug-10 23:52 
I have some forms, that are supposed to have custom controls on it, but also they are to have some predefined controls. This predefined set is equal for each form and i made a base control for them, containing these predefined controls.
 
It appears, that i show in designer controls, that are inherited from the base control. and every control from that predefined set is drawn with a flag in upper left corner, showing that it belongs to the base control.
 
How can i suppress that flag?
GeneralMy vote of 5memberHua Yujun4-Aug-10 23:11 
clearly
GeneralMy vote of 5membervla_dd2-Jul-10 5:33 
very good!
GeneralEventsmemberbooies6-Jul-07 10:47 
I see that by using private void RectangleControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e) in a way this program is running withing the "TestCustomControl" form. Is there a way to take it one step further by adding other events within the Paint event. For example could you perhaps have the Paint evet run a check for isMouseOver? I'm new to ActiveX controls, sorry if i'm misunderstanding them.
GeneralExpandableObjectConvertermembernseveno24-May-07 21:42 
You can also use the built in System.ComponentModel.ExpandableObjectConverter instead of creating a custom TypeConverter since the ExpandableObjectConverter does exactly the same things as your PhoneTypeConverter...
GeneralSee Also These cool articles!memberS.Serpooshan18-Jan-07 6:11 
You can see these new good and easy-to-use articles:
SmartTag Designer
Property Editor
Written by Saeed Serpooshan
QuestionSet of controlsmemberthe Same [aaaaaa]1-Dec-06 7:47 
My custom control has to use set of existing controls as browsable property. Is there a default editor for that trick? For example, I want to use "panel1", "scrollBar1" and "button1" that are currently present on the form. as "Controls" property of "MyControl" class
GeneralCustom datagridmemberhemaral3-Oct-06 10:04 
Hi,I created a custom datagrid and a custom designer that allowed me to create the tablestyle and the colums with they properties, it works fine but when I compile the project all the properties are gone. What I have been done wrong?
Can anyone help me?
Thanks.
QuestionA specific questionmembernilsgate8-Sep-06 3:14 
I have set of colors (say 10 colors). I want the user to choose the color property of my control from those colors only. so i am writing the customUItypeEditor.
Also in my control color property is of type string (which is id of the color in the list). Everything is working fine. But the value is shown in PropertyGrid against the color property of my control, which of type (string) is shown as the id (string id) of the selected color. which is true considering the type(string) of the property.
 
I want to show it same as other color properties shows, a small Color block with name or RGB values, without changing my implimentation..
 
please get back to me.
 
i also want to communicate with u for some other beneficial(to u) reasons. Please contact.
 
Thanks
r[.]nilesh[@]gmail[.]com
 
nils_gate
GeneralCancelling the drop down Slider(Trackbar)sussJaswinder Singh Kohli2-Jul-05 12:20 
Nice article, very well explains the details and how to go about using Property Grid/Sheet
 
One problem surfaced while i was experimenting more or less the same kind of code.
My question is how to cancel the values selected with the dropdown Slider.
Whenever i select the values then press ESC the values are reflected in the designer which were not intended.
I have tried overriding KeyPress, KeyDown as well as implementing the respective methods for both
control as well as sub controls.
 
Is there any way to do same ?
 
Thanks anyways.
GeneralRe: Cancelling the drop down Slider(Trackbar)memberS.Serpooshan18-Jan-07 6:15 
You can see these new easy-to-use articles:
SmartTag Designer
Property Editor
Written by Saeed Serpooshan
GeneralHelp!!!memberTim McCurdy20-Mar-05 23:27 
I've been trying everything and I cannot get my objects to persist in the CodeDom! I've tried creating a TypeConverter and also just simply using the ExpandableObjectConverter...nothing works!!! Can you take a look?D'Oh! | :doh:
 
Here is a simple property using the Class below:
/// <summary>
/// Property to Get or Set the Control Style
/// </summary>
[System.ComponentModel.Category("Appearance"),
System.ComponentModel.Description("Property to Get or Set the Control Style")]
public ControlStyle Style{
	get{
		if (this._Style == null) this._Style = new ControlStyle();
		return this._Style;
	}
	set{
		this._Style = value;
		//if (this._Style == null) this.ResetStyle();
	}
}
 
Here is the Class / Object:
/// <summary>
/// Controls the Style of a Control
/// </summary>
[System.ComponentModel.ToolboxItem(true),
System.ComponentModel.TypeConverter(typeof(ControlDynamix.ControlStyleConverter))]
public class ControlStyle : System.ComponentModel.Component {
	// <<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->>
	#region Declarations
 
	// Property Variables
	private System.Drawing.Color	_BorderColor = System.Drawing.SystemColors.ActiveBorder;
	private System.Drawing.Color	_ForeColor = System.Drawing.SystemColors.ControlText;
 
	#endregion
	// <<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->>

	// <<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->>
	#region Properties
 
	/// <summary>
	/// Property to Get or Set the Border Color of the Control
	/// this is only used when the BorderStyle is Normal or Flat
	/// and when there is no Theme enabled
	/// </summary>
	[System.ComponentModel.Category("Appearance"),
	System.ComponentModel.Description("Property to Get or Set the Border Color of the Control this is only used when the BorderStyle is Normal or Flat  and when there is no Theme enabled.")]
	public System.Drawing.Color BorderColor{
		get{return this._BorderColor;}
		set{
			if (this._BorderColor == value) return;
			this._BorderColor = value;
		}
	}
 

	/// <summary>
	/// Property to Get or Set the Fore Color of the Control
	/// </summary>
	[System.ComponentModel.Category("Appearance"),
	System.ComponentModel.Description("Property to Get or Set the Fore Color of the Control.")]
	public System.Drawing.Color ForeColor{
		get{return this._ForeColor;}
		set{
			if (this._ForeColor == value) return;
			this._ForeColor = value;
		}
	}
 

	#endregion
	// <<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->>

	// <<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->>
	#region Construct / Destruct
	
	/// <summary>
	/// Constructor
	/// </summary>
	/// <param name="container"></param>
	public ControlStyle(System.ComponentModel.IContainer container) {
		// Required for Windows.Forms Class Composition Designer support
		container.Add(this);
		InitializeComponent();
 
		//
		// TODO: Add any constructor code after InitializeComponent call
		//
	}
 

	/// <summary>
	/// Constructor
	/// </summary>
	public ControlStyle() {
		// Required for Windows.Forms Class Composition Designer support
		InitializeComponent();
		// Add any constructor code after InitializeComponent call
	}
 

	/// <summary>Required designer variable</summary>
	private System.ComponentModel.Container components = null;
 
	/// <summary>
	/// Required method for Designer support - do not modify
	/// the contents of this method with the code editor.
	/// </summary>
	private void InitializeComponent() {
		components = new System.ComponentModel.Container();
	}
 

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

	#endregion
	// <<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->><<->>
}

GeneralRe: Help!!!memberKodanda Pani21-Mar-05 19:57 
Hi,
 
To persist the design time values we have to decorate the property with DesignerSerializationVisibility attribute. We set the value of this attribute to DesignerSerializationVisibility enumeration value. The valid values are Content, Hidden, Visible. Set the value to DesignerSerializationVisibility.Content.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
 
Guess this will help you.
 
Thanks and Regards
SGS
GeneralRe: Help!!!memberTim McCurdy26-Mar-05 6:29 
Nope, I've tried that, it persists absolutely nothing! D'Oh! | :doh:
GeneralRe: Help!!!member
MadHatter ¢
28-Mar-05 18:37 
I had the same problem. turns out, adding a [Serializable] to the class that needed persisting, allowed some base 64 data of the object to be persisted to the resource file. Dont ask me if this is good style but it works. I wanted to save the property as:
// (DesignerSerializationVisibility.Visible)
myControl.CustomProperty = new CustomPropertyClass(45, 23, true);
 
instead of setting all of that properties public properties:
 
// (DesignerSerializationVisibility.Content)
myControl.CustomProperty.One = 45;
myControl.CustomProperty.Two = 23;
myControl.CustomProperty.AmICool = true;
 
once the class was serializable (& designer att set to visible), then it would serialize the class as shown in the first example.
 
good luck.
 



/bb|[^b]{2}/
 

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130619.1 | Last Updated 23 Feb 2005
Article Copyright 2005 by Kodanda Pani
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid