Подтвердить что ты не робот

CanExecute Logic для DelegateCommand

Обновление: Фокус стал MVVM вместо фактического вопроса, поэтому я его обновляю.

У меня проблема с CanExecute для DelegateCommand. Он не обновляется до того, как я назову RaiseCanExecuteChanged, это желаемое поведение?

enter image description here

Я загрузил простой пример проекта, воспроизводящий эту проблему здесь: http://dl.dropbox.com/u/39657172/DelegateCommandProblem.zip

Проблема в том, что у меня есть два Buttons как это. Один из них - привязка Command к реализации RelayCommand, а другая привязка к реализации Prism DelegateCommand

<Button Command="{Binding DelegateSaveCommand}"/>
<Button Command="{Binding RelaySaveCommand}"/>

ViewModel ICommands

DelegateSaveCommand = new DelegateCommand(Save, CanSaveDelegate);
RelaySaveCommand = new RelayCommand(param => Save(), param => CanSaveRelay);

и CanExecute метод/предикат

public bool CanSaveDelegate()
{
    return HasChanges;
}
public bool CanSaveRelay
{
    get { return HasChanges; }
}

Оба используют свойство HasChanges. Когда HasChanges обновляется, обновляется только CanSaveRelay. Так оно и должно быть?

4b9b3361

Ответ 1

Как уже упоминалось, это предполагаемое поведение DelagateCommand, а не ошибка. DelegateCommand не создает событие CanExecuteChanged автоматически, вам нужно поднять это событие вручную, вызвав RaiseCanExecuteChanged, когда это необходимо. В то время как RelayCommand реле для события CommandManager.RequerySuggested для этого. Это событие возникает каждый раз, когда пользователь щелкает где-то или нажимает кнопку.

В ситуациях, когда это не очень удобно или нет подходящего места для вызова RaiseCanExecuteChanged (например, в вашем сценарии вам нужно подписаться на событие PropertyChanged на модели и т.д.), я создал следующую простую оболочку, гарантирует, что метод CanExecute завернутой команды выполняется автоматически в событии CommandManager.RequerySuggested:

public class AutoCanExecuteCommandWrapper : ICommand
{
    public ICommand WrappedCommand { get; private set; }

    public AutoCanExecuteCommandWrapper(ICommand wrappedCommand)
    {
        if (wrappedCommand == null) 
        {
            throw new ArgumentNullException("wrappedCommand");
        }

        WrappedCommand = wrappedCommand;
    }

    public void Execute(object parameter)
    {
        WrappedCommand.Execute(parameter);
    }

    public bool CanExecute(object parameter)
    {
        return WrappedCommand.CanExecute(parameter);
    }

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

Вы можете использовать его следующим образом:

DelegateSaveCommand = new AutoCanExecuteCommandWrapper(new DelegateCommand(Save, CanSaveDelegate));

Ответ 2

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

Альтернативой является использование одной из других фреймворков RelayCommand.

Изменить
Вместо того, чтобы переупорядочивать код, есть другие вопросы SO, которые предоставляют разрешения:

И у Kent B. есть хорошая статья: MVVM Infrastructure: DelegateCommand