Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Label with Divider

0.00/5 (No votes)
14 Nov 2004 1  
A simple divider with text.

Introduction

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.

Background

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.

Using the code

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.

History

  • November 12, 2004: ver. 1.0
  • November 13, 2004: ver. 1.1: LeftToRight bugfix.

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