DispatcherTimer против обычного таймера в приложении WPF для планировщика задач - PullRequest
23 голосов
/ 13 февраля 2010

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

Необходим совет для стратегии многопоточности для приложения WPF

в комментариях к одному посту (цитата):

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

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

Ответы [ 3 ]

42 голосов
/ 13 февраля 2010

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

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

30 голосов
/ 14 февраля 2010

Событие тика обычного таймера фактически запускается в потоке, в котором был создан таймер, поэтому в событии тика, чтобы получить доступ к чему-либо через пользовательский интерфейс, вам нужно будет выполнить 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();
    });
}

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

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

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

15 голосов
/ 15 сентября 2012

С .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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...