Почему System.Windows.Threading.DispatcherTimer не запускает событие? - PullRequest
1 голос
/ 17 мая 2011

У меня есть приложение VB.Net и WPF. Одна часть приложения использует «генератор изображений» для расчета изображений. Другой использует «Таймер», чтобы показать гистограмму. При использовании генератора для создания около 2 кадров в секунду, загрузка процессора практически равна нулю, изображение создается нормально, а гистограмма будет создаваться в таймере все 1 секунду. Кажется, все идеально.

Если я позволю рассчитать изображение с помощью моего собственного «генератора изображений» с примерно 20 FPS вместо только 2, ЦП будет расти до 20%, но таймер никогда не генерирует событие. Изображение в графическом интерфейсе показывает 20FPS. Если я остановлю генератор изображений, Таймер немедленно сработает.

Понятия не имею, с чего начать.

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

Если я уменьшу частоту кадров примерно до 10 кадров в секунду, иногда DispatcherTimer выбрасывает свое событие, иногда нет. Если я увеличу частоту кадров, DispatcherTimer будет выдавать меньше событий.

Редактировать Загрузите демонстрационный проект здесь: Диспетчер VisualStudio 2010 с диспетчером форм Windows

Редактировать Видео демо выложено здесь: Видео, где куб больше не вращается

Ответы [ 3 ]

3 голосов
/ 17 мая 2011

Я не могу продублировать эту проблему с моей стороны. У меня отлично работает.

Интересно, что вы можете делать в функции TimerCalc_Tick? Все, что вы там делаете, блокирует Диспетчер. Событие не сработает, пока оно не будет завершено. Так что я определенно мог видеть, что что-то напортачило.

После просмотра кода, просмотра видео и воспроизведения его на моей машине, я думаю, что вы просто лишаете себя возможности 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

чтобы на самом деле вы не запустили таймер, который берет на себя всю обработку, а затем запустили приложение и запустили ползунок полностью влево, остановился ли прямоугольник? Если это не так, то я уверен, что вы просто голодаете Диспетчер. Если это так ... тогда я все еще в замешательстве.

0 голосов
/ 18 мая 2011

Диспетчер блокируется при обновлении образа. Разблокируйте, используя новую тему.

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
0 голосов
/ 18 мая 2011

Если вы хотите короткие и устойчивые интервалы, используйте вместо этого мультимедийный таймер (найдите упаковщик dot net на сайте проекта кода).

Если вам нужно работать с потоком пользовательского интерфейса, вызовите диспетчер (не диспетчерский таймер) всобытие мультимедийного таймера.Установите приоритет диспетчера для ввода, чтобы убедиться, что пользовательский интерфейс не блокирует его.Убедитесь, что операции выполняются намного меньше, чем интервал.

Рекомендуются интервалы от 5 мсек и выше.

...