One of the nice things about the Visual Studio WinForms
designers are the guidelines it draws onto design surfaces,
aiding you in perfectly positioning your controls. These
guidelines are known internally as snap lines, and by
default each visual component inheriting from
four of these, representing the values of the control's
A problem arises when you have multiple controls that have different heights, and contain a display string - in this case aligning along one edge isn't going to work and will probably look pretty ugly. Instead, you more than likely want to align the different controls so that the text appears on the same line.
Fortunately for us developers, the designers do include this
functionality - just not by default. After all, while all
controls have a
Text property, not all of them use it, and how
could the default designers know where your owner-draw control
is going to paint text?
The image above shows a
all aligned along the text baseline (the magenta line). We can
achieve the same thing by creating a custom designer.
The first thing therefore is to create a new class and inherit
System.Windows.Forms.Design.ControlDesigner. You may also
need to add a reference to
System.Design to your project
(which rules out Client Profile targets).
.NET conventions generally recommend that you put these types of classes in a sub-namespace called Design.
So, assuming I had a control named
BetterTextBox, then the
associated designer would probably look similar to the
If you use a tool such as Resharper to fill in namespaces, note that by default it will try and use
System.Web.UI.Design.ControlDesignerwhich unsurprisingly won't work for WinForms controls.
To add or remove snap lines, we override the
property and manipulate the list it returns. There are only a
few snap lines available, the one we want to add is
For the baseline, you'll need to calculate where the control will draw the text, taking into consideration padding, borders, text alignments and of course the font. My previous article retrieving font and text metrics using C# describes how to do this.
Note: Resharper seems to think the
SnapLinesproperty can return a null object. At least for the base WinForms
ControlDesigner, this is not true and it will always return a list containing every possible snapline except for
You can link your custom control to your designer by decorating
your class with the
If your designer type is in the same assembly as the control (or
is referenced), then you can call it with the direct type as
with the following example.
However, if the designer isn't directly available to your
control, all is not lost - the
DesignerAttribute can also take
a string value that contains the assembly qualified designer
type name. Visual Studio will then figure out how to load the
type if it can.
After rebuilding the project, you'll find that your control now uses your designer rather than the default.
I seem to recall that when using older versions of Visual Studio once the IDE had loaded my custom designer contained in a source code project it seemed to cache it. This meant that if I then changed the designer code and recompiled, it wouldn't be picked up unless I restarted Visual Studio. I haven't noticed that happening in VS2015, so either I'm imagining the whole thing, or it was fixed. Regardless, if you get odd behaviour in older versions of VS, a restart of the IDE might be just what you need.
The following image shows a zoomed version of the
BetterTextbox (which is just a garishly painted demo control
and so is several lies for the price of one) showing all three
controls are perfectly aligned to the magenta
ControlDesigner allows controls to be resized
along any edge at will. If your control automatically sets its
height or width to fit its contents, then this behaviour can be
undesirable. By overriding the
you can define how the control can be processed. The following
code snippet shows an example which prevents the control from
being resized vertically, useful for single-line text box style
- 2016-07-21 - First published
- 2020-11-21 - Updated formatting
Like what you're reading? Perhaps you like to buy us a coffee?