goldengel
goldengel

Reputation: 611

Why System.Windows.Threading.DispatcherTimer does not fire event?

I have a VB.Net and WPF application. One part of the application uses a "image generator" to calculate images. Another is using a "Timer" to show histogram. When using the generator to create about 2 Frames per second, CPU is about zero usage, image is created fine and Histogram will be created in Timer all 1 second. All seems to be PERFECT.

If I let calculate the image by using my own "image generator" with About 20 FPS instead of only 2, CPU is going up to 20% but the Timer never throws an event. Image in GUI is showing 20FPS. If I stop the image generator, immediately the Timer fires his event.

I have no idea where to start to search.

Me.TimerCalc = New System.Windows.Threading.DispatcherTimer
Me.TimerCalc.Interval = TimeSpan.FromMilliseconds(1000)
Me.TimerCalc.Start

Private Sub TimerCalc_Tick(sender As Object, e As System.EventArgs) Handles TimerCalc.Tick
'Does not fire if other process is running by using more CPU
End Sub

If I reduce the framerate to about 10FPS, sometimes the DispatcherTimer throws his event, somethimes not. If I increase the framerate, the DispatcherTimer will throw less events.

Edit Download demo project here: VisualStudio 2010 Dispatcher Test with Windows Form Timer

Edit Video of demo uploaded here: Video where cube does not rotate anymore

Upvotes: 3

Views: 3038

Answers (4)

Peter Huber
Peter Huber

Reputation: 3312

Unfortunately, the DispatcherTimer cannot fire every 50 milliseconds (20 times a second). Your CPU might show only 20% usage, because you might have more than 1 core, but the WPF GUI thread runs on only 1 core.

To find out how quickly DispatcherTimer can fire, run it with an DispatcherTimer.Interval of 1 millisecond and at default priority DispatcherPriority.Background. Tick gets actually called much slower. On my PC, Tick run every 3..300 milliseconds, even WPF had nothing else to do.

You can increase the priority to DispatcherPriority.Input, then the Tick run every 4...125 milliseconds. You could use a higher priority, but then the rendering stops running smoothly.

Even if you chose an Interval of 200 milliseconds and count them, you will find that some Ticks get lost over time. You can improve that by measuring for each Tick how many milliseconds it was delayed and shorten the Interval accordingly.

For details, see my article on CodeProject: Improving the WPF DispatcherTimer Precision

Upvotes: 0

goldengel
goldengel

Reputation: 611

The Dispatcher is blocked when updating the Image. Unblock by using an new Thread.

Private Sub cImageGenerator_NewImageAvailable() Handles cImageGenerator.NewImageAvailable
        If _IsReady = False Then Exit Sub
        _IsReady = False
        ' ################
        ' # Thread - Christian Zech
        ' #################
        Dim trd As New System.Threading.Thread(Sub()
                                                   ' ##########################
                                                   ' # Clone
                                                   ' ##########################
                                                   Dim bm As System.Drawing.Bitmap = Me.cImageGenerator.CreateBitmap '.Clone
                                                   Dim imgSrc As ImageSource = BitmapToWpfBitmapSource(bm)
                                                   imgSrc.Freeze() 'needed because otherwise we will get the error: The calling thread cannot access this object because a different thread owns it.
                                                   Me.Dispatcher.Invoke(New Action(Of ImageSource)(AddressOf UpdateImage), imgSrc)
                                               End Sub)
        trd.SetApartmentState(System.Threading.ApartmentState.STA) ''ToDo: MTA probieren
        trd.Name = "cImageGenerator_NewImageAvailable"
        trd.Start()
    End Sub

    Private Sub UpdateImage(ByVal img As ImageSource)
        Me.img1.Source = img
        _IsReady = True
    End Sub

Upvotes: 0

Tim
Tim

Reputation: 15237

I can't duplicate this problem on my end. It works fine for me.

I do wonder what you might be doing in the TimerCalc_Tick function, though. Anything you do in there will block the Dispatcher. The event won't fire again until that one is completed. So I could definitely see that screwing something up.

After looking at the code some more, and looking at the video, and playing with it on my machine, I think you're just starving the Dispatcher when you get up to the higher rates. I'm not sure why the rectangle completely stops rotating for you (it doesn't do that for me), but if your processor/graphics card is lower than mine, I could see that being the difference. When I run the slider all the way to the left like you did in your video, my processor (all four cores) is pegged at about 40%. A lower-end machine would be worse than that and could conceivably be starving other threads.

If you take the project as it is posted above, and you just make one single change, turning this:

Public Sub New()
    Me.TimerRefresh = New System.Windows.Forms.Timer
    Me.TimerRefresh.Interval = Me.Intervall
    Me.TimerRefresh.Enabled = True
End Sub

into this:

Public Sub New()
    Me.TimerRefresh = New System.Windows.Forms.Timer
    Me.TimerRefresh.Interval = Me.Intervall
    Me.TimerRefresh.Enabled = False
End Sub

so that you don't actually start the timer that takes all the processing, and then you run the app and run the slider all the way to the left, does the rectangle still stop? If it doesn't, then I'm confident you're just starving the Dispatcher. If it does... then I'm still confused.

Upvotes: 3

Danny Varod
Danny Varod

Reputation: 18068

If you want short and steady intervals use multimedia timer instead (find dot net wrapper on code project site).

If you need to do work on UI's thread, call a dispatcher (not dispatcher timer) on multimedia timer's event. Set dispatcher priority to input to make sure UI does not block it. Make sure operations take much less than the interval.

Intervals of 5mSec and above are recommended.

Upvotes: 0

Related Questions