WinForms FAQ - Custom Designers

Find answers for the most frequently asked questions
Expand All Collapse All

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

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

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

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

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

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

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

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

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

Share with

Couldn't find the FAQs you're looking for?

Please submit your question and answer.