Сегодня мы разберёмся с тем, как заставить программу, написанную с применением MVVM, самостоятельно и в реальном времени обновлять данные, с которыми взаимодействует View. Основная проблема заключается в том, что таймеры из System.Windows
и System.Threading
создают отдельные потоки в фоне, что вызывает исключение при попытке изменения отслеживающих обновление свойств, которые связаны с UI.
Это происходит потому, что пользовательский интерфейс может редактироваться только из того потока, в котором он был создан. В этой статье мы разберём вариант с автозапуском, а также с запуском и остановкой таймера по кнопке.
Итак, для решения проблемы воспользуемся классом DispatcherTimer
из System.Windows.Threading
. Пример:
//MyViewModel.cs ... using System.Windows.Threading;//Подключим пространство имён ... DispatcherTimer timer;//Объявим поле для таймера ... public MyViewModel() { StartTimer();//Запустим таймер } ... #region Timer //Метод для запуска таймера private void StartTimer() { timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 30) }; timer.Tick += new EventHandler(Tick); timer.Start(); } private void Tick(object sender, EventArgs e) { //Здесь пишем что должен делать таймер MessageBox.Show("It works!"); } #endregion
Таким образом, мы запускаем таймер при инициализации MyViewModel.
Если вам нужно запускать и останавливать таймер по кнопке, создадим для этого команды:
#region Commands //Команда старта таймера public ICommand StartTimerCommand {get;set;} //Команда остановки таймера public ICommand StopTimerCommand {get;set;} #endregion public MyViewModel() { //Вместо автозапуска повесим методы на команды. this.StartTimerCommand = new RelayCommand(this.StartTimer); this.StopTimerCommand = new RelayCommand(this.StopTimer); } #region Methods ... //Допишем метод остановки таймера public void StopTimer() { if (timer != null) { timer.Stop(); timer = null; } } #endregion
Надеюсь, эта статья помогла вам решить проблему. Спасибо за внимание.