Подтвердить что ты не робот

DispatcherTimer против обычного таймера в приложении WPF для планировщика задач

Пожалуйста, объясните разницу между "DispatcherTimer" и "обычным таймером", которую @Kent Boogaart предназначил для использования в многопоточном WPF-приложении в качестве диспетчера задач в этом разделе:

Рекомендации, необходимые для многопоточной стратегии для приложения WPF

в комментариях к одному из сообщений (цитата):

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

Что такое "регулярный таймер"? Как они ( "DispatcherTimer" и "обычный таймер" ) отличаются в отношении их влияния на пользовательский интерфейс?

(До чтения этого сообщения я думал о DispatcherTimer как о естественном способе использования таймеров в WPF. В каких случаях это неверно?)

4b9b3361

Ответ 1

DispatcherTimer - это обычный таймер. Он запускает событие Tick в потоке пользовательского интерфейса, вы можете делать все, что хотите, с помощью пользовательского интерфейса. System.Timers.Timer - это асинхронный таймер, его событие Elapsed запускается в потоке пула потоков. Вы должны быть очень осторожны в обработчике событий, вам не разрешено касаться каких-либо компонентов пользовательского интерфейса или связанных с данными переменных. И вам нужно будет использовать оператор блокировки, когда бы вы ни получали доступ к членам класса, которые также используются в потоке пользовательского интерфейса.

В связанном ответе класс Timer был более уместным, потому что OP пытался запустить асинхронный код специально.

Ответ 2

Событие с обычным типом таймера фактически запускается в потоке, где был создан таймер, поэтому в событии тика, чтобы получить доступ к чему-либо с пользовательским интерфейсом, вам придется пройти через dispatcher.begininvoke, как указано ниже.

RegularTimer_Tick(object sender, EventArgs e)
{
    txtBox1.Text = "count" + i.ToString(); 
    // error can not access
    // txtBox1.Text property outside dispatcher thread...

    // instead you have to write...
    Dispatcher.BeginInvoke( (Action)delegate(){
       txtBox1.Text = "count " + i.ToString();
    });
}

В случае диспетчерского таймера вы можете получить доступ к элементам пользовательского интерфейса, не заставляя их запускать или вызывать, следуя...

DispatcherTimer_Tick(object sender, EventArgs e)
{
    txtBox1.Text = "Count " + i.ToString();
    // no error here..
}

DispatcherTimer просто обеспечивает удобство по сравнению с обычным таймером для легкого доступа к объектам пользовательского интерфейса.

Ответ 3

С .NET 4.5 вы также можете создать делегат async для своего таймера, если вам нужно использовать новую функциональность .NET 4.5 await.

        var timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(20);
        timer.Tick += new EventHandler(async (object s, EventArgs a) =>
        {
            Message = "Updating...";
            await UpdateSystemStatus(false);  
            Message = "Last updated " + DateTime.Now;              
        });
        timer.Start();