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

WPF / Silverlight Countdown Timer and Time Ticker TextBlock

0.00/5 (No votes)
25 Apr 2011 1  
In one of my applications I had to display a timer for all the items in a ListView, i.e., given the last update time of an item I required to display the time elapsed since the update time and update it after every second.

In one of my applications, I had to display a timer for all the items in a ListView, i.e., given the last update time of an item, I required to display the time elapsed since the update time and update it after every second. In a classic application, the solution would have been to add a timer control to the host form and update each elapsed time value at each tick (second) of the timer.

However, in WPF/Silverlight, we can easily achieve this by creating a custom control inheriting it from the TextBlock control. The custom control defines a TimeSpan property that holds the time elapsed (or time remaining in the case of count down) and binds it to the TextBlock.Text property. The TimeSpan is updated every second and thus the Text property displays the updated value.

Count down and timer demo using the TimerTextBlock control.

The control initializes a static System.Threading.Timer object with an interval of one second. Also, the control defines a private static event OnTick that is raised in the timer callback method.

C#
private static event EventHandler OnTick;
private static Timer _UpdateTimer = 
        new Timer(new TimerCallback(UpdateTimer), null, 1000, 1000);

private static void UpdateTimer(object state)
{
    EventHandler onTick = OnTick;
    if (onTick != null)
        onTick(null, EventArgs.Empty);
}

The control subscribes to the OnTick event while loading to receive the event, and unsubscribes the event while unloading.

C#
private void Init()
{
    Loaded += new RoutedEventHandler(TimerTextBlock_Loaded);
    Unloaded += new RoutedEventHandler(TimerTextBlock_Unloaded);
}

void TimerTextBlock_Loaded(object sender, RoutedEventArgs e)
{
    Binding binding = new Binding("TimeSpan");
    binding.Source = this;
    binding.Mode = BindingMode.OneWay;
    binding.StringFormat = TimeFormat;

    SetBinding(TextProperty, binding);

    _UpdateTimeInvoker = new Invoker(UpdateTime);

    OnTick += new EventHandler(TimerTextBlock_OnTick);
}

void TimerTextBlock_Unloaded(object sender, RoutedEventArgs e)
{
    OnTick -= new EventHandler(TimerTextBlock_OnTick);
}

The TimeSpan is updated in the OnTick event handler.

C#
void TimerTextBlock_OnTick(object sender, EventArgs e)
{
    Dispatcher.Invoke(_UpdateTimeInvoker);
}

private void UpdateTime()
{
    if (IsStarted)
    {
        TimeSpan step = TimeSpan.FromSeconds(1);
        if (IsCountDown)
        {
            if (TimeSpan >= TimeSpan.FromSeconds(1))
            {
                TimeSpan -= step;
                if (TimeSpan.TotalSeconds <= 0)
                {
                    TimeSpan = TimeSpan.Zero;
                    IsStarted = false;
                    NotifyCountDownComplete();
                }
            }
        }
        else
        {
            TimeSpan += step;
        }
    }
}

private void NotifyCountDownComplete()
{
    EventHandler handler = OnCountDownComplete;
    if (handler != null)
        handler(this, EventArgs.Empty);
}

The control defines additional properties like IsStarted to start/stop the timer, IsCountDown to increase or decrease the TimeSpan at each tick, and TimeFormat for formatting the elapsed time displayed. The control also defines an event OnCountDownComplete that is raised when the count down completes, i.e., when it reaches zero.

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