Samosynchronizujący się Timer z UI w C# WPF

By | 18 marca 2016

Framework Windows Presentation Foundation daje nam programistom C# duże pole do popisu, ponieważ oddziela warstwę kodu od warstwy widoku, co poprawia czytelność kodu, zwiększa możliwości testowania ale przede wszystkim po prostu dużo prościej się tak pisze aplikacje. Jednak poza wymienionymi plusami znalazły się też minusy, a mianowicie pomimo rozdzielenia widoku i kontrolera, wszystkie operacje działają w jednym wątku. Nie jest to dobre rozwiązanie, ponieważ przyzwyczaja to do pisania i korzystania z funkcji przebiegających w sposób synchroniczny, czyli w przypadku bardziej złożonych operacji, może prowadzić do blokowania okna.

Warto więc znać sposoby na to, żeby stworzyć funkcje działające w tle ale nie wpływające na działanie UI. Timer jest jednym z takich elementów. Timer pozwala uruchamiać pewne działanie w osobnym wątku co określony czas przez programistę czas.

Jednak okazuje się, że Timer, który zawarty jest w przestrzeni nazw System.Timers nie jest rozwiązaniem idealnym, ponieważ w przypadku komunikacji z wątkiem odpowiadającym za UI nie jest on w stanie doprowadzić do synchronizacji, czy do odpowiedniego ustawienia się w kolejkę wykonywania się operacji.

Rozwiązaniem jest System.Windows.Threading.DispatcherTimer, który całkowicie rozwiązuje problem synchronizacji między wątkami, ale trzeba znać również wady tego rozwiązania. Jedną z poważniejszych wad jest to, że ten timer nie będzie odmierzał czasu idealnie. On gwarantuje tylko, że wywołanie funkcji nie nastąpi wcześniej niż przed czasem, który został określony podczas jego inicjalizacji. Jest to związane dokładnie z tym o czym wcześniej wspomniałem, czyli kolejką operacji. Może się okazać, że w kolejce jest dość sporo zadań, które zajmują czas i nie ma możliwości na czas wykonania funkcji z timera, więc wykona się ona później.

Poniżej kod do wykorzystania w swoim rozwiązaniu:


System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
// timespan (godziny, minuty, sekundy)
dispatcherTimer.Interval = new TimeSpan(0,5,0);
dispatcherTimer.Start();

private void dispatcherTimer_Tick(object sender, EventArgs e)
{
// tutaj powinien się znaleźć kod wykonywany co 5 min
}

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *