2016-04-21 6 views
0

Возможно, самое длинное название вопроса за все время! Потому что это вопрос из двух частей.Как NotifyOnValidationError в конечном итоге вызывает CanExecute (и почему он не работает с MVVM Light RelayCommand)

(1) Я не понимаю, как настройка NotifyOnValidationError = «True» может инициировать обновления для моего CanExecute. Здесь есть немного волшебства, которые мне нужно понять. Кто-то (предмет) подписывается на событие CanExecuteChanged моей ICommand, но стек вызовов указывает на внешний код, поэтому я не могу понять, что происходит.

(2) Возможно, наиболее важные последующие вопросы: почему это не работает в MVVM Light RelayCommand! CanExecute вызывается только один раз при инициализации, а затем никогда больше. Глядя на исходный код RelayCommand в MVVM Light, он не выявляет каких-либо различий в сравнении с моей собственной реализацией. Я должен упомянуть, что делегат-делегат Призма, похоже, тоже не работает.

(Bonus) Maybee Я приближаюсь к этой проблеме неправильно? Я просто хочу включить/отключить кнопки на основе отказов проверки.

XAML (фрагмент):

<TextBox Grid.Column="1" Grid.Row="0"> 
     <Binding Path="X" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> 
      <Binding.ValidationRules> 
       <ExceptionValidationRule></ExceptionValidationRule> 
      </Binding.ValidationRules> 
     </Binding> 
    </TextBox> 

    <Button Grid.Column="1" Grid.Row="3" Command="{Binding CalculateCommand}"> 
     Calculate 
    </Button> 

RelayCommand:

public class MyRelayCommand : ICommand 
{ 
    readonly Action<object> Execute_; 
    readonly Predicate<object> CanExecute_; 

    public MyRelayCommand(Action<object> Execute, Predicate<object> CanExecute) 
    { 
     if (Execute == null) 
      throw new ArgumentNullException("No action to execute for this command."); 

     Execute_ = Execute; 
     CanExecute_ = CanExecute; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return (CanExecute_ == null) ? true : CanExecute_(parameter); 
    } 

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

    public void Execute(object parameter) 
    { 
     Execute_(parameter); 
    } 
} 

ViewModel:

private DelegateCommand _calculateCommmand; 
    public DelegateCommand CalculateCommand 
    { 
     get 
     { 
      return _calculateCommmand ?? (_calculateCommmand = new DelegateCommand(
      () => 
      { 
       Sum = X + X; 
      }, 
      () => 
      { 
       try 
       { 
        Convert.ChangeType(X, TypeCode.Byte); 
        return true; 
       } 
       catch 
       { 
        return false; 
       } 
      })); 
     } 
    } 

PS: Если вы хотите купить мой X + X программы, когда это делается по электронной почте я на [email protected]

ответ

0

Я не думаю, что это зависит от реализации ICommand. В вашем, я вижу public event EventHandler CanExecuteChanged, где вы указываете CommandManager для обработки вызова метода CanExecute() вашей команды. Без CommandManager вам придется самому справиться с этим, например. путем предоставления вашей реализации ICommand с помощью метода public void RaiseCanExecuteChanged(), который ваш ViewModel должен вызывать для каждой команды, которую он считает необходимым для пересчета, например. внутри ViewModel's OnPropertyChanged. Пример: https://codereview.stackexchange.com/questions/124361/mvvm-am-i-doing-it-right

Итак, CommandManager делает магию для вас. Как только вы вызываете событие ViewModel PropertyChanged, «внешний код» обрабатывает затронутые команды и запрашивает их для нового значения CanExecute().

+0

Я должен отметить, что моя реализация представляет собой урезанный вариант источника, найденного для RelayCommand (MVVM Light), который находится здесь: https://mvvmlight.codeplex.com/SourceControl/latest#GalaSoft.MvvmLight/GalaSoft.MvvmLight (PCL)/Command/RelayCommand. cs Как вы можете видеть, он также использует CommandManager. – sunefred

+0

Вот что я пытался вам сказать. Магия, которую вы просили, выполняется CommandManager. Я предполагаю, что ваш ViewModel реализует 'INotifyPropertyChanged', поэтому должен существовать' event PropertyChangedEventHandler PropertyChanged', который вы можете вызвать: 'PropertyChanged? .Invoke()'. Это говорит диспетчеру команды, что ему нужно снова вызвать ваши команды «CanExecute()». Попробуй! –

1

(2) Я сам это понял. Вы можете включить RelayCommand из двух разных пространств имен, убедитесь, что вы используете

using GalaSoft.MvvmLight.CommandWpf; 

Я до сих пор ищу хороший ответ на (1), как сантехнические работы, что повышает CanExecutetChanged на основе ошибки проверки.

0

(1) Я думаю, что так происходит.

  1. Когда мы связываем с RelayCommand: ICommand к Button.Command, процесс связывания будет также приложить EventHandler к ICommand.CanExecuteChanged. Это поведение по умолчанию.
  2. Обработчик событий, переданный в CanExecutedChanged, будет передан и присоединен к статическому событию CommandManager.RequerySposed.
  3. При возникновении ошибки проверки и установки NotifyOnValidationError внешняя сила или джедай поднимут событие RequerySknown, которое будет транслироваться во ВСЕ активные команды.
  4. Кнопка получает событие и, следовательно, вызывает CanExecute, чтобы узнать, отключена ли она или активирована кнопка.

Я хотел бы знать больше о третьей точке пули выше, так что я буду держать этот вопрос открытым немного дольше, чтобы дать экспертам возможность звонить в.

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

  • Нет связанных вопросов^_^