Introduction
The DigitalCounter is an implementation of the famous 7 segment display - having the following features:
- DigitalCounter displays numbers.
- DigitalCounter can be used as a timer.
- Each Active or InActive segment has two modes: Fill and Draw.v
- DigitalCounter has a colorful gradient background.
- DigitalCounter has a rich design-time support.

GDI+
This control is primarily based on the GDI+ functions to draw the seven segments with their colors. I wrote seven methods, one for each segment that returns a GraphicsPath object containing a polygon representing the segment.
Drawing the Background
First, the background color, as shown below:
Drawing the segments

Segment a and b for example:
Drawing Numbers

After making the seven segments graphics path ready to use, all that is needed is to call the appropriate segments for each number. For example, number 4 is as follows:
Drawing the Value
As shown above, the mode of Active color is checked, and then we Draw or Fill the active segments according to the ActiveDrawingMode. For the InActive segments the same logic is used. Now, we can draw all numbers by choosing the right segment as Active or InActive. For drawing more than one number, we have some challenges, such as:
- Getting the number to be drawn.
- Drawing the number in the right position.
So I wrote the DrawValue function to handle the above challenges.
In the above method there is a loop for the number of digits to be displayed, as you can see it in the below code snippet there are some steps that are repeated for each digit. First I retrieved the number to be drawn: For this I intialized two temporary variables temp and val by the actual Value. temp holds the value of the digit to be drawn and val indicates the remaining digits to be drawn.
By using the following two equations we can trace if the Value is equal to 123 where i is the loop index starting from 0 to nunOfDigits - 1
To calculate the right position for next digit, I used the following code:
As you can see in the above line the graphics object changes its transformation with the TranslateTransform method which changes the new origin of the graphics; For example when drawing a rectangle with (0,0,10,10) it would show a square having top=0, left=0, right=10, bottom=10; however if we use TranslateTransform(10,10) it will move the origin 10 in direction X and 10 in direction Y so now if we draw a rectangle (0,0,10,10) we will find the square having top=10, left=10, right=20, bottom=20.
Now for that line of code I have used the TranslateTransform to move the origin of drawing to be in a proper position as shown we don't translate in the y direction, for the x direction we move the origin (_size * 11) which is the size of the digit itself plus (_size * _spacing) where _spacing is the space between digits.
Notice here that I don't reverse the translation so that the next digit would translate again from the last postion. As shown also before starting this algorithm for drawing I have used the ResetTransform method to get back the original origin at 0,0 since the DrawValue method is called many times for painting.
Design-time Support
By adding some attributes to the class and its members, we have a rich design-time environment for our control. The design-time environment of Visual Studio gives some services for us to use, such as: Desginer, UITypeEditors, TypeConverters and more.
Simple Attributes
First, for simple attributes:
The Browsable attribute shows if this property or event should appear in the PropertyGrid or not.
The DefaultValue attribute shows the default value of the property. The user can reset the default value by right-clicking and choosing “Reset”
The Category attribute shows the category that this property belongs to; it appears when the PropertyGrid is categorized rather than sorted alphabetically.
The Description shows the description of the Property or Event in the PropertyGrid when highlighted.
UITypeEditors

I made a Custom UITypeEditor named DigitalCounterSizeEditor as shown below. To implement one, you need to implement a class derived from UITypeEditor, and then override the needed methods.
Desginer

I also implemented a custom Designer class to give us more control during design-time. I used the designer to draw a red dashed border around the control in design-time, to filter the properties shown in the PropertyGrid and to remove the unused ones. To implement one, you first need to implement a class that derives from the ComponentDesigner or one of its derived types such as ControlDesigner, ParentControlDesginer, etc. Then you override the needed methods.
Finally, do not forget to attach the control designer to the control by using the following attribute:
Toolbox support
The last design time option is to put an icon bitmap to associate the control when displayed in the toolbox, to do so you need to follow these steps:
- Add a picture with Size of 16X16 to the project.
- From the properties of the picture choose the Build Action as EmbeddedResource.
- Be sure to rename the picture with the exact name of the class.
- Mark the class with the
ToolBoxBitmapAttribute as seen below.
[ToolboxBitmap(typeof(DigitalCounter), "DigitalCounter.ico")]
Summary
In this article, I have tackled more than one topic. I have shown how to create an owner drawn control, how to work with some GDI+ classes and how to draw simple figures. I have introduced how to give custom controls some design-time support (Attributes, UITypeEditors and a simple Designer class). This control is one of my control libraries. I will introduce some of it in the near future. I hope you like the control and the article. Please leave a comment or any questions (if needed) and report any bugs you encounter.
Downloads
DigitalCounter VS Project File
Please login to rate or to leave a comment.