2011-12-08 5 views
0

Я работал над некоторыми примерами MVVM & WPF, и, выполняя некоторую отладку, я обнаружил, что RelayCommand, связанный с кнопкой на моем представлении, постоянно запускается (выполняется связанный с ним ImportHoursCommand) как как только начнется программа.WPF & RelayCommand - кнопка всегда срабатывает

Вот фрагменты кода:

Посмотреть

<Button x:Name="ImportHoursButton" Content="Import Hours" 
     Command="{Binding ImportHoursCommand}" 
     Height="25" Width="100" Margin="10" 
     VerticalAlignment="Bottom" HorizontalAlignment="Right"     
     Grid.Row="1" /> 

ViewModel

 private RelayCommand _importHoursCommand; 
     public ICommand ImportHoursCommand 
     { 
      get 
      { 
       if (_importHoursCommand == null) 
       { 
        _importHoursCommand = new RelayCommand(param => this.ImportHoursCommandExecute(), 
                  param => this.ImportHoursCommandCanExecute); 
       } 
       return _importHoursCommand; 
      } 
     } 

     void ImportHoursCommandExecute() 
     { 
      MessageBox.Show("Import Hours", 
          "Hours have been imported!", 
          MessageBoxButton.OK); 
     } 

     bool ImportHoursCommandCanExecute 
     { 
      get 
      { 
       string userProfile = System.Environment.GetEnvironmentVariable("USERPROFILE"); 
       string currentFile = @userProfile + "\\download\\test.txt"; 
       if (!File.Exists(currentFile)) 
       { 
        MessageBox.Show("File Not Found", 
            "The file " + currentFile + " was not found!", 
            MessageBoxButton.OK); 
        return false; 
       } 
       return true; 
      } 
     } 

Если я ставлю точку останова на строке 'Userprofile = ...' строки и запустите программу, Visual Studio остановится в точке останова и продолжит останавливаться на кануне контрольной точки rytime Я нажимаю кнопку отладки «Продолжить». Если у меня нет точки останова, программа работает нормально, но должна ли эта команда всегда проверять, может ли она выполняться?

Я использую RelayCommand из статьи here от Джоша Смита.

ответ

6

Если кнопка привязана к команде, CanExecute() определяет, включена ли кнопка или нет. Это означает, что CanExecute() запускается в любое время, когда кнопка должна проверять его включенное значение, например, когда оно нарисовано на экране.

Поскольку вы используете точку останова в VS, я предполагаю, что приложение скрывается, когда VS набирает фокус, и повторно нажимает кнопку, когда вы нажимаете кнопку «Продолжить». Когда он снова рисует кнопку, он снова оценивает CanExecute(), который входит в бесконечный цикл, который вы видите.

. Один из способов точно знать, как изменить точку останова на Debug.WriteLine и посмотреть окно вывода, когда ваш приложение работает.

В качестве дополнительной заметки вы также можете изменить свой RelayCommand на Microsoft Prism DelegateCommand. Я не слишком разбирался в различиях, однако я знаю, что RelayCommands автоматически поднимает событие CanExecuteChanged(), когда выполняются определенные условия (изменения свойств, визуальные недействительные и т. Д.), В то время как DelegateCommands только поднимет это событие, когда вы конкретно расскажете об этом. Это означает, что CanExecute() оценивает только тогда, когда вы конкретно рассказываете об этом, а не автоматически, что может быть хорошим или плохим в зависимости от вашей ситуации.

+0

ОК, это имеет смысл тогда. Примеры, которые я прошел, не дали понять, что CanExecute управляет самой кнопкой. Я думал, что это способ определить, можно ли выполнить команду. – BrianKE

+0

@BrianKE Нет, если вы когда-либо запускаете свой 'Command.Execute()' вручную, обязательно запустите 'Command.CanExecute()' first – Rachel

2

Что, в общем-то, нормально; WPF переоценивает, может ли команда выполняться очень часто, например, когда изменяется управление фокусом или когда окно фокусируется. Каждый раз, когда вы нажимаете «Продолжить», окно снова фокусируется на фокусе, которое пересматривает CanExecute вашей команды, поэтому ваша точка останова снова попадает.

+0

Почему это должно быть нормальное поведение? Не следует ли проверять/выполнять команду только при нажатии кнопки? Есть ли способ проверить это только при нажатии кнопки? Когда эта команда выполняется, я делаю некоторую проверку, чтобы проверить, не выходит ли файл, если часы для импорта уже существуют и т. Д., И отображение MessageBox, чтобы пользователь знал, что что-то пошло не так. Когда он постоянно проверяет состояние, я получаю MesasgeBoxes безостановочно, делая программу непригодной для использования. – BrianKE

+2

@BrianKE 'CanExecute' определяет, включена ли кнопка или нет, поэтому в любое время, когда пользовательский интерфейс должен повторно нарисовать кнопку, или когда RelayCommand считает, что параметры CanExecute изменены, метод' CanExecute() 'будет запущен.Вам лучше было бы проверить, существует ли файл или нет (или другая такая логика) в методе Click кнопки или в событии PropertyChanged в FileName. – Rachel

+0

Я думал, что метод Click был заменен Командой при использовании MVVM для поддержания разделения кода и просмотра ?! Разве это не так, или мне не хватает точки CommandExecute()? – BrianKE

Смежные вопросы