Wednesday, March 24, 2010

WPF Timer (DispatcherTimer)

This article discusses the WPF DispatcherTimer.

Most of us are from a background of C# (or VB.Net). You must have some point of time come across a scenario for performing a repetitive GUI operation after certain period of time. The solution in most cases has been the WinForm's Timer.

What about WPF ? Does it have a Timer ?

WPF no different to WinForm has it's own Timer equivalent. It is called DispatcherTimer. There are other options to get the Timer behavior but one of the most efficient for a Window based operation is the DispatcherTimer.

I have attached a sample Timer application demonstrating the functionality.

The window has a "Start timer" and "Stop timer" functionality. There is an input TextBox which takes the Timer frequency in milliseconds.

Just enter the Timer frequency in millisecond and hit the "Start timer" button. There is a status bar which displays the status of the time. At start it will be blank. When you start the Timer it will display the current Time and when you stop the Timer it will display the "Stopped" status.

Let us discuss the code to look into how we use it.

XAML,
< Window x:Class="TimerSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Timer" Height="148" Width="300" ResizeMode="NoResize" 
WindowStartupLocation="CenterScreen">
    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <Label Margin="50,5,5,5">Timer value:</Label>
            <TextBox Name="time"  Height="20">1000</TextBox>
            <Label Margin="0,5,5,5" FontWeight="Bold">ms</Label>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Button Margin="50,5,5,5" Click="Start_Click">Start timer</Button>
            <Button Margin="5,5,75,5" Click="Stop_Click">Stop timer</Button>
        </StackPanel>
        <TextBlock Name="status"  Margin="0,35,0,0" Background="LightGray"
 Height="20" Padding="25,0,0,0">Not working</TextBlock>
    </StackPanel>
</Window>


Code behind,
public partial class Window1 : Window
{
    DispatcherTimer _timer;

    public Window1()
    {
        InitializeComponent();

        _timer = new DispatcherTimer();
        _timer.Tick += new EventHandler(delegate(object s, EventArgs a)
        {
            status.Text = "Started: " + DateTime.Now;
            //MessageBox.Show("Dummy message"); //notify timer end
            //this.Close(); //close application
        });
    }

    private void Start_Click(object sender, RoutedEventArgs e)
    {
        // Set the Interval
        _timer.Interval = TimeSpan.FromMilliseconds(Convert.ToDouble(time.Text));

        // Start the timer
        _timer.Start();

        status.Text = "Started";
    }

    private void Stop_Click(object sender, RoutedEventArgs e)
    {
        // Stop the timer
        _timer.Stop();

        status.Text = "Stopped";
    }
}


We have a local variable of type DispatcherTimer - _timer. We manipulate this variable to start and stop the timer. At start we initialize the variable with an Event delegate to fire whenever the Timer ticks.
 _timer.Tick += new EventHandler(delegate(object s, EventArgs a)
        {
            status.Text = "Started: " + DateTime.Now;
            //MessageBox.Show("Dummy message"); //notify timer end
            //this.Close(); //close application
        });


I have specifically left the commented lines to show the different possibilities that can be done in the Event delegate. Whenever the Timer ticks the event is fired and Status bar is updated with the most recent DateTime.

DispatcerTimer runs on the UI thread and hence does not need marshaling back and forth as we have to do in the normal cases of a Thread.