Sometimes it is necessary to visually separate controls in a dialog. GroupBox
is one solution, but it is not appropriate if you just want a horizontal 3D line with a label like in some Options dialogs in Visual Studio. One possible solution is to create an additional empty label with BorderStyle
set to Fixed3D
and Height
set to 2. However, this approach is cumbersome because you must take care of control placement order. Moreover, if you are going to change the label text (e.g., when localizing the application) or text alignment, you'll have to resize/reposition controls. Therefore, I have created this simple label that takes care of such details.
Details regarding custom control creation has been explained elsewhere (e.g., in excellent step-by-step tutorial Divider Panel - A tutorial on creating a custom Windows Forms control from Start to Toolbox). Therefore, I will not go through them but only outline some specific points.
LabelWithDivider
control inherits the Label
class, overriding only its OnPaint
method. In this method, line is drawn first, and then base class' OnPaint
method is called that takes care of drawing the text:
protected override void OnPaint(PaintEventArgs e) {
PlaceLine(e.Graphics);
base.OnPaint(e);
}
The order of method calls is actually not important since PlaceLine
method calculates position and length of the line taking in account the text length as well as its horizontal and vertical alignments:
protected void PlaceLine(Graphics g) {
// evaluates text size SizeF textSize = g.MeasureString(this.Text, this.Font);
int x0 = 0; // first point x-coordinate int x1 = this.Width; // second point x-coordinate // for different horizontal alignments recalculates x-coordinates switch (GetHorizontalAlignment()) {
case HorizontalAlignment.Left:
x0 = (int)textSize.Width + m_gap;
break;
case HorizontalAlignment.Right:
x1 = this.Width - (int)textSize.Width - m_gap;
break;
case HorizontalAlignment.Center:
x1 = (this.Width - (int)textSize.Width) / 2 - m_gap;
break;
}
int y = (int)textSize.Height / 2;
// for different vertical alignments recalculates y-coordinate if (TextAlign == ContentAlignment.MiddleLeft
|| TextAlign == ContentAlignment.MiddleCenter
|| TextAlign == ContentAlignment.MiddleRight)
y = this.Height / 2;
else if (TextAlign == ContentAlignment.BottomLeft
|| TextAlign == ContentAlignment.BottomCenter
|| TextAlign == ContentAlignment.BottomRight)
y = this.Height - (int)(textSize.Height / 2) - 2;
Draw3DLine(g, x0, y, x1, y);
// for centered text, two line sections have to be drawn if (TextAlign == ContentAlignment.TopCenter
|| TextAlign == ContentAlignment.MiddleCenter
|| TextAlign == ContentAlignment.BottomCenter) {
x0 = (this.Width + (int)textSize.Width) / 2 + m_gap;
x1 = this.Width;
Draw3DLine(g, x0, y, x1, y);
}
}
protected HorizontalAlignment GetHorizontalAlignment() {
if (TextAlign == ContentAlignment.TopLeft
|| TextAlign == ContentAlignment.MiddleLeft
|| TextAlign == ContentAlignment.BottomLeft) {
if (RightToLeft == RightToLeft.Yes)
return HorizontalAlignment.Right;
else
return HorizontalAlignment.Left;
}
if (TextAlign == ContentAlignment.TopRight
|| TextAlign == ContentAlignment.MiddleRight
|| TextAlign == ContentAlignment.BottomRight) {
if (RightToLeft == RightToLeft.Yes)
return HorizontalAlignment.Left;
else
return HorizontalAlignment.Right;
}
return HorizontalAlignment.Center;
}
protected void Draw3DLine(Graphics g, int x1, int y1, int x2, int y2) {
g.DrawLine(SystemPens.ControlDark, x1, y1, x2, y2);
g.DrawLine(SystemPens.ControlLightLight, x1, y1+1, x2, y2+1);
}
m_gap
in the above code is the optional gap between text and line, which can be set to a non-zero value by Gap
property:
public int Gap {
get { return m_gap; }
set {
m_gap = value;
Invalidate();
}
}
Note that setter calls Invalidate
to ensure control is redrawn in the visual designer on value change.
Control has been placed into class library (LabelWithDivider.dll) and all required attributes are set so that control can be added to toolbox and simply dragged and dropped onto a form. Gap
property is available in Appearance category. And last but not least: LabelWitDivider
is placed into System.Windows.Forms
namespace.
LeftToRight
bugfix.This article, along with any associated source code and files, is licensed under The zlib/libpng License