tags:

views:

99

answers:

3

I am using a DispatchTimer to perform a count down before triggering the release on a camera. The UpdateCountdown method is used to change the image displayed to the user before the camera fires. Rather than having the TakePicture method execute immediately, I would like have a slight delay after the counter reaches zero and the last image is displayed.

The code shown below results in the pause occurring at the _countdown = 1 point. While the final image displays and TakePicture() fire almost simultaneously (I think TakePicture happens first).

_countdownTimer = new DispatcherTimer();
_countdownTimer.Interval = TimeSpan.FromSeconds(1);
_countdownTimer.Tick += new EventHandler(delegate(object s, EventArgs a)
     { UpdateCountdown(); } );

_countdownTimer.Tick += new EventHandler(delegate(object s, EventArgs a)
     {if (_countdown == _countdownMax)
        {
            System.Threading.Thread.Sleep(2000);  // Slight delay before taking picture
            Camera.TakePicture();
        } });
    }

public void StartCountdown()
{
    if (doCount)
    {
        doCount = false;
        UpdateCountdown();
        _countdownTimer.Start();
    }
}

private void UpdateCountdown()
{
    _countdown--;
    CountdownImage = _countDownImages[_countdown]; // Data bound to Image Control

     if (_countdown == 0)
     {
       _countdown = _countdownMax;
       _countdownTimer.Stop();
       doCount = true;
      }

What am I not taking into account with my timing?

A: 

I don't think that events guarantee that event handlers are triggered in the order that they are registered. Try

_countdownTimer.Tick += new EventHandler(delegate(object s, EventArgs a)     
{
        UpdateCountdown();
        if (_countdown == _countdownMax)
        {
            System.Threading.Thread.Sleep(2000);  // Slight delay before taking picture
            Camera.TakePicture();
        }
      });
    }
antonm
Good point, I think I started out with this configuration.
pdemarest
+1  A: 

Why not just make your display always show 1 less than the number of seconds remaining. That way when you get to zero, (obviously with a Math.Max(0, _countdown) to prevent showing -1) it will seem like the time has run out even though there's one more second to go.

Edit: What I meant to imply but did not state - was that you could then just have one Tick handler and not use Sleep at all which will just wind up blocking the UI anyway which will probably block your UI from updating.

Josh Einstein
That is essentially my current solution (not shown), but I was hoping to be able to tune the delay to be less than a full tick.
pdemarest
+2  A: 

The UI does not update immediately when you change control properties - it only updates when the thread becomes idle (that is, after all your event handlers finish executing).

Thread.Sleep blocks the thread, the event handlers don't finish executing and UI isn't redrawn.

You have to either use another timer (start a new timer on the last tick of the existing timer and call TakePicture on teh new timer's tick) or, even better, use the last tick of the existing timer - update UI when (_countdown <= _countdownMax), take picture when (_countdown == _countdownMax + 1).

Nir