Since Microsoft released the .NET Framework, a lot of component vendors have surfaced and some of them provide amazing controls at a very cheap price. However sometimes a customer asks you for something too specific that you can't buy anywhere so you have to do it yourself.
This is the case for this article. A customer wanted to offer the possibility to do online tests on his portal. However he wanted to be able to know the remaining time exactly while doing the tests as well as be able to change the appearance without recompiling. Of course when the time expires he wanted the test to finish immediately. So it was time to make a custom control with DHTML support...
As I don't have time to change the source code you will see that it's in Spanish. I'm sorry if you don't understand it. It's a nice and very used language so you should start learning it ;-)
Using the code
Using the timer in your code is very easy:
Here is a list of the properties of the control and what they do:
TimeSpan when the timer expires.
ImagesPath: path to the folder with the images for the styles.
Estilo: style to use. There are 16 predefined styles. You can use your own style if you add your custom images to the
CausaPostBack: if it's true, the control will cause postback when the timer expires generating the
Ascendente: if it's true, the timer will count from 0 to the specified
TimeSpan, otherwise from the specified
TimeSpan to 0.
Mensaje: message to show when the timer expires.
MsgCssClass: CSS class to use for the message.
InitialTime: when exactly the timer starts (if it's not set, it will set the first time in the prerender stage).
For example, the demo project source code is:
Cronometro1.Duracion = new TimeSpan(0, 1, 0);
Cronometro1.Ascendente = false;
Cronometro2.Duracion = new TimeSpan(0, 1, 10);
Cronometro2.Ascendente = false;
Cronometro2.CausaPostBack = false;
Cronometro3.Duracion = new TimeSpan(0, 1, 20);
Cronometro3.Ascendente = false;
Cronometro3.CausaPostBack = false;
Cronometro4.Duracion = new TimeSpan(0, 1, 30);
Cronometro4.Ascendente = true;
There's no limit to the number of timers you can use in a page. The control has been tested in IE 6.0, FireFox 1.0 and Opera 8.0.
Points of Interest
When you have to make a custom control that has logic on the server and the client side, it's important to think about how to pass values from the server side to the client side and vice versa.
RegisterClientScriptBlock in the prerender stage. Also, for each timer it creates an object with the following fields:
style: style to use.
expired: true if this timer has expired.
upwards: if true, the timer goes upwards, otherwise it goes downwards.
causePostBack: if it's true, the control will cause postback when the timer expires, generating the
imgPath: path to the folder with the images for the styles.
timeSpan: instant of time when the timer expires.
serverInitTime: when exactly the timer starts (if it's not set, it will be set the first time in the prerender stage).
clientInitTime: client browser's time when the object is created.
serverInitLoadTime: instant of time when the page is in prerender stage for this roundtrip.
Instead of passing the
InitialTime property directly I stored it in a hidden input field to allow to use the control to post a form's data to another page and be able to get the initial server time.
The client side methods are:
Tick: called every second to update the timer.
ShowRow: method to show/hide the row that shows a message when the timer expires.
DisplayTime: called from
Tick to update the timer's digits.
GetInitialServerTime: helper method to get when exactly the timer starts (in server time).
GetTimeSpan: helper method to convert a string holding a
TimeSpan value to a
Tick() method is a bit complex because it has the main timer logic.
The client side doesn't need to pass any value to the server side, as the server can find out if the timer has expired. However, the client side has to generate a server side event if the
CausaPostBack property is set to true. In order to accomplish that, the control registers a function that will be called from
Tick() when the timer expires, that uses
Page.GetPostBackEventReference() to generate a postback.
The custom control has six images as children (one for each digit to show the timer in the format hh:mm:ss), that are created and added in
CreateChildControls. The control implements
INamingContainer to give unique names to its child controls as well as
IPostBackEventHandler in order to be able to generate server side events.
The control has custom rendering to draw a table with two rows. On the first row it shows the digits, and the second row is used to display a message when the timer expires.
The control has a custom
UITypeEditor to select the style as you can see in the picture at the top of this article.
To improve design time experience, I wanted the control to display images reflecting the selected style, but using ASP.NET 1.1 forces you to implement a custom handler to obtain the images from the assembly (in ASP.NET 2.0, this is improved, thanks to the
WebResourceAttribute). The custom handler is implemented in the class
DesignTimeImageHandler. The form used to select the control's style has some
PictureBox controls and the framework automatically stores the associated bitmap as an image resource. Instead of adding the images as different embedded resources, I reused the images from the
- 2005/10/13 - Initial version.