Introduction
This article will show you how to use the System.Drawing
classes (also known as GDI+) to create a .NET UserControl
for displaying information similar to the old Arrival/Departure boards at airports. As each row changes, the board will flicker through the alphabet to display the new entry.
This article is not meant to teach you how to become a GDI+ expert. It’s really designed to show that GDI+ isn't as hard as many people think. It's designed to encourage developers to create custom controls when existing controls don't meet the requirement, or when you want to add some gloss to your Winforms UI presentation.
Using the Code
Once you have added the AirportDepartureBoard
control to your form, you will find that you can not add or remove rows to the control. So the only way of changing a row’s text is to call the control's UpdateRow
method. It is best to update the row with the flicker set to Flicker.No
while initializing the form. This will avoid slowing down the load time of the form.
MyDepartureBoard.UpdateRow(0, “Hello World” Flicker.No);
Once initialized, to get the flicker working, set the Flicker
parameter to Flicker.Yes
when updating a row's text.
MyDepartureBoard.UpdateRow(1, “It’s a beautiful day” Flicker.Yes);
The AirportDepartureBoard
control, in the download source code, is an example of how to use the Croll.Windows.Forms.DestinationBoard
control which does most of the work. The DestinationBoard
control has a number of properties you can set at design or run time. These are BoardBackColor
, BoardRowDividerColor
and BoardFlickerHingeColor
. You will find as you change these properties at design time, the changes will be reflected in the form designer (which is nice). One thing worth noting is that the control only displays whole rows using the BoardBackColor
. Any space left at the bottom of the control will be displayed using the control's BackColor
property.
Using GDI+ to Create a UserControl
GDI+ sounds a bit scary. It gives the impression that you're going to have to do some low level programming to use GDI+. But that’s not the case because the .NET Framework has abstracted the GDI+ functionality into the System.Drawing
namespace making the developer's life a whole lot easier and simpler. The centrepiece of the System.Drawing
namespace is the Graphics
object. Graphics
has a number of methods for drawing. This demonstration will highlight some of the easier methods to use when creating your own UserControl
s. Below is a code snippet that uses two simple graphics methods, FillRectangle
and DrawLine
.
private void PaintPanel()
{
Graphics g = this.CreateGraphics();
Pen dividerPen = new Pen(this.boardRowDividerColor);
Pen hingePen = new Pen(this.boardFlickerHingeColor);
g.FillRectangle(new SolidBrush(this.boardBackColor), 0, 0,
base.Width, this.rowCount * this.rowHeight);
for (int i = 0; i <= this.rowCount; i++)
{
g.DrawLine(dividerPen, 0, i * this.rowHeight,
base.Width, i * this.rowHeight);
}
for (int i = 0; i < this.rowCount; i++)
{
g.DrawLine(hingePen, 0, i * this.rowHeight + (this.rowHeight / 2) + 1,
base.Width, i * this.rowHeight + (this.rowHeight / 2) + 1);
}
for (int i = 0; i < rows.Count; i++)
{
PaintRow(new PaintRowParameters(i, Flicker.No, rows[i]));
}
}
In the next snippet, you will also notice the use of the DrawRectangle
and DrawString
methods. All these methods are so well named that no explanation is needed making the System.Drawing
namespace relatively intuitive. Just as important is the use of Brush
es. In this case, a simple SolidBrush
has been used, but there are a variety of brush
es that can be used to really bring your new control to life. It should also be noted that a number of objects need disposing, so don't forget to dispose of the objects when you have finished using them.
private void PaintCharacter(char c, int colIndex, int rowIndex)
{
Graphics g = this.CreateGraphics();
SolidBrush brush = new SolidBrush(ForeColor);
Pen pen = new Pen(this.boardFlickerHingeColor);
try
{
int x = (this.colWidth * colIndex);
int y = (this.rowHeight * rowIndex) + 1;
Rectangle topHalfRect = new Rectangle(x, y, this.colWidth,
(this.rowHeight / 2) - 1);
Rectangle fullRect = new Rectangle(x, y, this.colWidth, this.rowHeight - 1);
g.FillRectangle(new SolidBrush(this.boardBackColor), topHalfRect);
g.DrawString(c.ToString(), this.Font, brush, topHalfRect);
g.DrawLine(pen, x, y + (this.rowHeight / 2), x +
this.colWidth, y + (this.rowHeight / 2));
g.FillRectangle(new SolidBrush(this.boardBackColor), fullRect);
g.DrawString(c.ToString(), this.Font, brush, fullRect);
g.DrawLine(pen, x, y + (this.rowHeight / 2), x +
this.colWidth, y + (this.rowHeight / 2));
}
finally
{
g.Dispose();
brush.Dispose();
pen.Dispose();
}
}
As you can see, no rocket science required, no low level programming. Pretty simple code for what I think is a pretty cool control. Definitely, this has just scratched the surface of what can be done with GDI+ but it shows for most custom controls, all you need is a bit of imagination.
Helpful Tip
When working in the System.Drawing
space, or charting for that matter, you come across a lot of x
and y
parameters. The easy way to remember what’s x
and what’s y
is as simple as reading this page. First you read across (x
) and then you read down (y
).
History
- 7th September, 2009: Initial version