为什么System.Windows.Threading.DispatcherTimer不会触发事件?

时间:2011-05-17 17:05:21

标签: .net wpf events timer dispatcher

我有一个VB.Net和WPF应用程序。该应用程序的一部分使用“图像生成器”来计算图像。另一个是使用“计时器”来显示直方图。当使用生成器每秒创建大约2帧时,CPU使用率约为零,图像创建正常,直方图将在Timer中创建1秒钟。一切似乎都很完美。

如果我让我自己的“图像生成器”使用大约20 FPS而不是2来计算图像,则CPU最高可达20%,但Timer不会抛出事件。 GUI中的图像显示20FPS。如果我停止图像生成器,Timer会立即触发他的事件。

我不知道从哪里开始搜索。

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

如果我将帧速率降低到大约10FPS,有时DispatcherTimer会抛出他的事件,有时则不会。如果我增加帧速率,DispatcherTimer将抛出更少的事件。

修改 在此下载演示项目:VisualStudio 2010 Dispatcher Test with Windows Form Timer

修改 上传的演示视频:Video where cube does not rotate anymore

3 个答案:

答案 0 :(得分:3)

我无法在我的问题上复制这个问题。它对我来说很好。

我确实想知道你在TimerCalc_Tick函数中可能会做些什么。你在那里做的任何事都会阻止Dispatcher。在完成该事件之前,该事件不会再次触发。所以我绝对可以看到搞砸了。

在查看代码之后,观看视频,并在我的机器上播放它,我认为当你达到更高的费率时,你只是让Dispatcher挨饿。我不确定为什么矩形完全停止为你旋转(它不适合我),但如果你的处理器/显卡低于我的,我可以看出这是不同的。当我像你在视频中一样向左运行滑块时,我的处理器(所有四个核心)都固定在40%左右。低端机器会比这更差,可能会让其他线程挨饿。

如果您按照上面发布的项目进行,只需进行一次更改,请转到此处:

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

进入这个:

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

这样你就不会实际启动进行所有处理的计时器,然后运行应用程序并一直向左运行滑块,矩形是否仍然停止?如果没有,那么我相信你只是让调度员挨饿。如果它......那我仍然感到困惑。

答案 1 :(得分:0)

如果您想要短而稳定的间隔,请使用多媒体计时器(在代码项目网站上找到点网络包装器)。

如果您需要在UI的线程上工作,请在多媒体计时器的事件上调用调度程序(而不是调度程序计时器)。将调度程序优先级设置为输入以确保UI不会阻止它。 确保操作比间隔少得多。

建议使用5毫秒及以上的间隔时间。

答案 2 :(得分:0)

更新图像时会阻止Dispatcher。使用新线程取消阻止。

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