Introduction
Anyone else ever wondered why Microsoft did not include a "simple" line/shape control with .NET? I was getting tired of having to write GDI+ every time I wanted a line on a screen.
Overview
This is the first article I have submitted, so please bear with me on the format. I think I have a lot to offer to the CodeProject community, but I wanted to start with something simple.
First off, I would like to state that this control was developed on my own time. Were this something I was paid to do, I would probably have some better comments in the code, and there would not be any "gotchas" in the controls.
That being said, this project includes three controls:
SimpleLine
The simple line control can function as a line or a box. If it's a line, it can be horizontal or vertical. It can also handle gradients, as a line or a box (see picture above).
The following are some of the properties that can be set through the designer properties box, as well as at run-time:
[Category("Custom")]
public GradientDirection GradientAngle
[Category("Custom")]
public bool FitToParent
[Category("Custom")]
public bool UseGradient
[Category("Custom")]
public LineStyle Style
To draw the actual line (or box) the DrawLine()
method is called:
public void DrawLine()
{
if (this.Parent == null) { return ; }
if (this.Style == LineStyle.None)
{
_lineStyle = LineStyle.Horizontal ;
_lineWidth = 1 ;
this.Left = (Parent.Width /2) - this.Width / 2 ;
this.Top = Parent.Height / 2 ;
}
Graphics g = this.CreateGraphics() ;
g.Clear(Parent.BackColor) ;
Pen pn ;
if (this.Style == LineStyle.Vertical || this.Style == LineStyle.Horizontal)
pn = new Pen( LineColor,LineWidth * 2);
else
pn = new Pen( LineColor,LineWidth);
Point pt1 = new Point( 0, 0 );
Point pt2 ;
if (this.Style == LineStyle.Horizontal)
{
if (FitToParent == true)
{
this.Left = 0 ;
this.Width = Parent.ClientRectangle.Width ;
}
this.Height = LineWidth ;
if (this.Height < 1) { this.Height = 1 ; }
pt2 = new Point( Width , 0 );
if (UseGradient == false)
{
g.DrawLine( pn, pt1, pt2 );
}
else
{
Rectangle rect = new Rectangle(new Point(0,0),
new Size(this.ClientRectangle.Width,LineWidth)) ;
if (FillColor == Color.Transparent)
{FillColor = Parent.BackColor ; }
{
LinearGradientBrush lgb = new
LinearGradientBrush(rect,FillColor,Gradient,0,false) ;
g.FillRectangle(lgb,0,0,this.Width,LineWidth) ;
}
}
}
else if (this.Style == LineStyle.Vertical)
{
if (FitToParent == true)
{
this.Top = 0 ;
this.Height = Parent.Height ;
}
this.Width = LineWidth ;
if (this.Width < 1) { this.Width = 1 ; }
pt2 = new Point( 0, Height ) ;
if (UseGradient == false)
{
g.DrawLine( pn, pt1, pt2 );
}
else
{
Rectangle rect = new Rectangle(new Point(0,0),
new Size(LineWidth,this.Height)) ;
if (FillColor == Color.Transparent)
{FillColor = Parent.BackColor ; }
{
LinearGradientBrush lgb = new
LinearGradientBrush(rect,FillColor,Gradient,90,false) ;
g.FillRectangle(lgb,0,0,LineWidth,this.Height) ;
}
}
}
else if (this.Style == LineStyle.Box )
{
if (FitToParent == true)
{
this.Top = 0 ;
this.Left = 0 ;
this.Width = Parent.Width;
this.Height = Parent.Height ;
}
Rectangle rect = new Rectangle(new Point(0,0),
new Size(this.Width,this.Height)) ;
if (FillColor == Color.Transparent)
{FillColor = Parent.BackColor ; }
if (UseGradient)
{
LinearGradientBrush lgb = new LinearGradientBrush(rect,
FillColor,Gradient,
GradientAngle==GradientDirection.Horizontal ? 0 : 90,false) ;
g.FillRectangle(lgb,0,0,this.Width - LineWidth,
this.Height - LineWidth) ;
}
else
{
SolidBrush sb = new SolidBrush(FillColor) ;
g.FillRectangle(sb,0,0,this.Width - LineWidth,this.Height - LineWidth) ;
}
decimal mod = Decimal.Remainder((decimal)LineWidth,(decimal)2) ;
int offset = 0 ;
if (mod != 0 && LineWidth !=1) { offset = 1 ; }
rect.Offset(LineWidth/2,LineWidth/2) ;
rect.Height = rect.Height - LineWidth + offset -1 ;
rect.Width = rect.Width - LineWidth + offset -1 ;
if (LineWidth > 0) {g.DrawRectangle(pn,rect) ;}
}
g.Dispose() ;
}
SimpleBox
The SimpleBox
control "looks" like the SimpleLine
control (running in "Box
" mode). There is one primary difference: the SimpleBox
is a container control. In other words, it behaves similar to a Panel
.
To make a user control a container control, all you need to do is add the following attribute to the class:
[Designer("System.Windows.Forms.Design.ParentControlDesigner,
System.Design", typeof(IDesigner))]
TransparentLabel
I have to give credit on this control to Kenneth Hadden. I worked with Ken for about a year at my last job, and he took it upon himself to add this control to the SimpleLine project. Although .NET allows you to specify "transparent" as the background for various controls (such as the .NET Label
control), that is not truly transparent. It will accurately display the gradient, if placed on a gradient control, but you would not see another control come through, if it were between the gradient and the Label
.
Usage
To use these controls, open up the solution I've included. Compile, and add the three SimpleLine controls to your toolbox, if necessary. Place one of the controls on a form or user control, and set the appropriate properties.
The properties of these controls are fairly straightforward. Make sure to change the "UseGradient
" property to true
if you want to display a gradient.
Good luck. For what it's worth, I am using these controls in a couple of production apps. The code is not perfect, but I have yet to have a problem.
... and finally
If you like this control, please vote. If you don't like it, please email me at paul@blurious.com, and give me the opportunity to fix or explain before you vote.
Updates:
- 05-10-05
- Added code from Eric Woodruff to allow
SimpleBox
to paint at design time.
- Added a few code snippets to illustrate how controls function.