Silverlight and Timers

May 15, 2007
No Comments.

I was doing a Silverlight video player for some videos I am doing and I was playing with different ways to show the timeline of a playing video. There are a couple of ways to do this, but in Silverlight 1.0 the typical way was with an animation on a hidden Canvas that you restart over and over to mimic the behavior of a Timer:

<!-- The XAML -->
<Canvas ... >
  <Canvas.Resources>
    <Storyboard x:Name="theTimer">
      <DoubleAnimation Storyboard.TargetName="timerCanvas" 
                       Storyboard.TargetProperty="(Canvas.Left)" 
                       From="0" To="1"  
                       Duration="0:0:0.1"
                       Completed="theTimer_Completed" />
    </Storyboard>
  </Canvas.Resources>


  <Canvas x:Name="timerCanvas" Opacity="0" />

</Canvas

This is hacky to me but it works great in Silverlight 1.0.  I wanted a better Silverlight 1.1 solution so I though, “Hey, its .NET…I’ll use a timer”:

Timer timer = new Timer(new TimerCallback(timerFired), 
                        null, 
                        500, 
                        500);

And the Handler:

void timerFired(object o)
{
  // Does not work because I can't update the UI thread from a non UI thread
  progressBar.Width = ((double)videoPlayer.Position.Seconds / 
                       (double)videoPlayer.NaturalDuration.TimeSpan.Seconds) 
                       * progressBack.Width;
}

In Silverlight 1.1 the XAML stack does not support a Dispatcher as such. In fact there is no cross thread messaging at all. Incidently, this has been reported on the Silverlight.net Forums and they’ve said that they are going to add a high-performance timer in the Beta timeframe of Silverlight.

But I wanted an answer now and the only one I could find (without resorting to the fake Animation) was the HtmlTimer class. NOTE: The Silverlight team warn against using the HtmlTimer as it is it not high performance enough, but for prototyping Silverlight 1.1, I think its fine. Here’s the HtmlTimer implementation:

// Use a Timer
HtmlTimer timer = new HtmlTimer();
timer.Interval = 100;
timer.Tick += new EventHandler(timer_Tick);
timer.Start();

And the Handler:

void timer_Tick(object sender, EventArgs e)
{
  // Works because the HtmlTimer does not use a separate thread
  // But may be a bit choppy as the timer not very high resolution
  progressBar.Width = ((double)videoPlayer.Position.Seconds / 
                       (double)videoPlayer.NaturalDuration.TimeSpan.Seconds) 
                       * progressBack.Width;
}

Not perfect, but good enough for now…