WinForms FAQ - Custom Designers

How do I control the state of my custom verb in my designer?

You have to store a reference to the DesignerVerb instance you create to represent the custom verb. You can then update the state of the verb through this reference. Here is an example:

public class MyControlDesigner : ParentControlDesigner
{
    private DesignerVerb removeVerb;
    private DesignerVerbCollection verbs;
    ...

    public override /*ParentControlDesigner*/ void Initialize(IComponent component)
    {
        //... 
        // Update your designer verb whenever ComponentChanged event occurs.
        iComponentChangeService = (IComponentChangeService) this.GetService(typeof(IComponentChangeService));
        if (iComponentChangeService != null)
            iComponentChangeService.ComponentChanged += new ComponentChangedEventHandler(this.ComponentChanged);

    }

    protected override void Dispose(bool disposing)
    {
        ...
        if (iComponentChangeService != null)
            iComponentChangeService.ComponentChanged -= new ComponentChangedEventHandler(this.ComponentChanged);
    }

    public override DesignerVerbCollection Verbs
    {
        get
        {
            if (this.verbs == null)
            {
                this.removeVerb = new DesignerVerb('Remove Tab', new EventHandler(this.OnRemove));
                this.verbs = new DesignerVerbCollection();
                this.verbs.Add(this.removeVerb);
            }
            this.removeVerb.Enabled = (this.Control.Controls.Count > 0);
            return this.verbs;
        }
    }

    private void UpdateVerbStatus()
    {
        if (this.removeVerb != null) this.removeVerb.Enabled = (this.Control.Controls.Count > 0);
    }

    private void CheckVerbStatus(object sender, ComponentChangedEventArgs e)
    {
        this.UpdateVerbStatus();
    }
}
Permalink
How do I implement a custom designer

Here are a couple of articles that discuss custom designers.

Shawn Burke, in his article Wrinting Custom Designers for .NET Components at msdn.

Brian Pepin, in his article .NET Shape Library: A Sample Designer at gotnetdot.com.

Permalink
How do I prevent the Designer-Grid from being drawn on my Container Control during design-time?

You can do so by overriding the DrawGrid property in your custom designer:

public class MyContainerDesigner : ParentControlDesigner
{
	protected override /*ParentControlDesigner*/ bool DrawGrid 
	{ 
		get
		{
			if (!this.disableDrawGrid)
				return base.DrawGrid;
			else
				return false;
		}
	}
}
Permalink
How do I prevent resizing of my Control in the designer?

You normally need this support when your Control is parented by another custom Container Control that manages the location and size of your Control.

You can prevent resizing by overriding this method in your custom ControlDesigner class:

protected override bool EnableDragRect 
{
	get { return false; }
}

Or, for more control over the resizing process:

public override /*ControlDesigner*/ SelectionRules SelectionRules 
{ 
	get
	{
		System.Windows.Forms.Design.SelectionRules selectionRules;
		System.Windows.Forms.Control control;
		selectionRules = base.SelectionRules;
		control = this.Control;
		if (control.Parent is MyControlParent)
			selectionRules = (SelectionRules)(selectionRules & ~(SelectionRules.AllSizeable));

		return selectionRules;
	}
}
Permalink
How can I know when a Control/Component has been selected in the designer surface?

You can listen to the SelectionChanged event in your Control Designer.

public class MyContainerDesigner : 
		ParentControlDesigner
{
	public override /*ParentControlDesigner*/ void Initialize(IComponent component)
	{
		base.Initialize(component);
		iSelectionService = (ISelectionService)this.GetService(typeof(ISelectionService));
		if (iSelectionService != null)
			iSelectionService.SelectionChanged += new EventHandler(this.OnSelectionChanged);
	}
	private void OnSelectionChanged(object sender, EventArgs e)
	{
		// To find out the current selection (can be more than 1) do this:
		System.ComponentModel.Design.ISelectionService iSelectionService;
		System.Collections.ICollection selectedComponents;

		this.iamSelected = false;
		iSelectionService = (ISelectionService)this.GetService(typeof(ISelectionService));

		if (iSelectionService != null)
		{
			selectedComponents = iSelectionService.GetSelectedComponents();
			foreach(object selectedComponent in selectedComponents)
			{
				if(selectedComponent == this.Component)
					this.iamSelected = true;
			}
		}
	}
}
Permalink
Can I do some custom drawing on my control designer’s surface during design-time?

Yes, you can. You have to override OnPaintAdornments in your Control Designer. This will be called after the Control has painted.

A good example is when you have a Control that has its border style set to None, and you want to draw a dummy border in the designer.

protected override /*ParentControlDesigner*/ void OnPaintAdornments(PaintEventArgs pe)
{
	System.Windows.Forms.Panel panel;
	panel = (System.Windows.Forms.Panel)this.Component;
	if (panel.BorderStyle == BorderStyle.None)
		this.DrawDesignTimeBorder(pe.Graphics, panel);
			
	base.OnPaintAdornments(pe);
}

public void DrawDesignTimeBorder(Graphics g, Control control)
{
	System.Drawing.Rectangle clientRectangle;
	System.Drawing.Color bgColor, adjustedBgColor;
	System.Drawing.Pen pen;

	clientRectangle = control.ClientRectangle;
	bgColor = control.BackColor;
	if (((double) bgColor.GetBrightness()) >= 0.5)
		adjustedBgColor = ControlPaint.Dark(control.BackColor);
	else
		adjustedBgColor = ControlPaint.Light(control.BackColor);
			
	pen = new Pen(adjustedBgColor);
	pen.DashStyle = DashStyle.Dash;

	clientRectangle.Width = (clientRectangle.Width - 1);
	clientRectangle.Height = (clientRectangle.Height - 1);

	g.DrawRectangle(pen,clientRectangle);
	pen.Dispose();
}
Permalink
How do I get Mouse Messages on my Control during design-time?

The design-time will forward the MouseEnter and MouseLeave messages to your Control by default. The MouseMove message are blocked by the designer. You can get MouseDown and Up messages in your Control if you override GetHitTest method in your designer and return true, as follows:

protected override /*ControlDesigner*/ bool GetHitTest(Point point)
{
	if(this.NeedMouseDown(point))
		return true;
	else
		return false;
}
Permalink
How do I restrict my Container Control to parent only certain types of Controls, and vice-versa, during design-time?

To restrict your Container Control to parent only certain types of controls, override as follows in your designer:

public class MyContainerControlDesigner : ParentControlDesigner
{
	public override /*ParentControlDesigner*/ bool CanParent(Control control)
	{
		// My Children can only be of type TextBox.
		return (control is TextBox);
	}
}

To restrict your Control to get parented to by a certain type, do so in your Control’s designer:

class MyControlDesigner : ControlDesigner
{
	public override /*ControlDesigner*/ bool CanBeParentedTo(IDesigner parentDesigner)
	{
		// MyControl can be parent only by MyParent
		return (parentDesigner is MyParentDesigner);
		// or do this:
		// return (parentDesigner.Component is MyParent);
	}
}
Permalink
How can I insert custom menu items (verbs) into my Component/Control designer’s Context Menu in design time?

You need to create custom ‘Verbs’ for your Component/Control designer. This will make your ‘verbs’ show up in the property browser and in the designer context menu.

The designer throws an event when the user selects a verb and you can perform custom operation when you handle this event.

You do this by overriding the Verbs property in your Designer class.

Here is an example:

public class MyControlExtDesigner : ControlDesigner
{
	...
	public override DesignerVerbCollection Verbs 
	{ 
		get
		{
			if (this.verbs == null)
			{
				this.verbs = new DesignerVerbCollection();
				this.verbs.Add(new DesignerVerb('Add New Child',new EventHandler(this.OnAdd)));
			}
			return this.verbs;
		}
	}

	private void OnAdd(object sender, EventArgs eevent)
	{
		// Code to add a new child inside your control.
		...
	}
}
Permalink
I have created a usercontrol and a designer, How can i debug the designer

You need to use a second instance of VS.NET to debug the one that’s running
the code.

Put your control on a form in VS.NET
Start a 2nd Vs.Net
Choose the Debug menu >> Processes …
Double click ‘devenv.exe’ and choose ‘Common Language Runtime’ as the types
of debugging
Open your code file, set your breakpoint, and you’re debugging.

Posted by Shawn Burke of MSFT in microsoft.public.dotnet.framework.windowsforms.

Permalink