0

У меня есть таймер в базовой VM:

private DispatcherTimer timer;
protected DispatcherTimer Timer { 
  get => timer;
  set
  { 
     timer = value;
     OnPropertyChanged();
   }
}

private int tickCounter = 5; public int TickCounter { get { return tickCounter; } set { tickCounter = value; OnPropertyChanged(); } }

public BaseTrainerViewModel() { Timer = new DispatcherTimer(); Timer.Interval = TimeSpan.FromSeconds(1d); Timer.Tick += new EventHandler(Timer_Tick); }

private void Timer_Tick(object sender, EventArgs e) { if (--TickCounter <= 0) { Timer.Stop(); } }

И вот такой код в VM, которая наследуется от базовой VM:

public RelayCommand startTimer;
public override RelayCommand StartTimer
{
  get
  {
    return startTimer ?? (startTimer = new RelayCommand(obj =>
      {
        Timer.Start();
      },
      obj=>
      {
        return !Timer.IsEnabled;
       }));
  }
}

Где Execute - Timer.Start();, а CanExecute - return !Timer.IsEnabled;

Эта команда привязывается к кнопке:

<Button Content="Старт" Command="{Binding StartTimer}"/>

Теперь суть проблемы - когда я нажимаю на кнопку, то таймер запускается и начинается обратный отсчет и кнопка при этом не активна, как и должно быть. Когда таймер останавливается (if (--TickCounter <= 0) Timer.Stop();), то по идее кнопка должна стать доступна сразу же после этого, но мне необходимо щелкнуть в любом месте формы для того, чтобы кнопка снова стала доступна. Что мне надо сделать, чтобы кнопка становилась доступна после окончания таймера(ну или другими словами как уведомить кнопку о том, что таймер остановился без щелчка по форме)?

P.S. Пытался сделать отдельное свойство IsStartTimer которое бы устанавливалось в true при запуске и в false при остановке таймера, та же проблема.

P.S.S. Предполагаю, что надо где-то вызвать OnPropertyChanged, но не совсем понимаю где.

Pekor
  • 449

1 Answers1

1

Обновление CanExecute происходит посредством вызова обработчика CanExecuteChanged у команды. Оно скорее всего у вас привязано к CommandManager.RequerySuggested внутри RelayCommand (вы не показали, это упущение, поэтому я пытаюсь угадать).

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}

CommandManager вызывает RequerySuggested когда происходит событие ввода, например тык мышкой или ввод с клавиатуры. Но можно вызвать и принудительно.

Вот так:

if (--TickCounter <= 0)
{
    Timer.Stop();
    CommandManager.InvalidateRequerySuggested();
}

Кстати, вам стоит познакомиться с асинхронными программированием, тогда не придется мучать таймеры - Создание бесконечно повторяющегося метода в c#.

aepot
  • 49,560
  • 1
    да, спасибо большое, работает, насчет асинхронного программирования в точку, но я его боюсь :) – Pekor Apr 21 '22 at 18:52
  • 1
    @Pekor https://ru.stackoverflow.com/q/1275282/373567 вот кстати, загляните сюда еще. – aepot Apr 21 '22 at 19:02