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

ICommand CanExecute не запускается после PropertyChanged?

Я получил приложение WPF, которое показывает кнопку, привязанную к такой команде:

<Button Command="{Binding Path=TestrunStartCommand}" Content="GO!">

Команда определяется так:

public ICommand TestrunStartCommand
{
    get { return new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress); }
}

public bool IsTestrunInProgress
{
    get{
        return _isTestrunInProgress;
    }
    set{
        _isTestrunInProgress = value;
        RaisePropertyChanged(IsTestrunInProgressPropertyName);
    }
}   

Проблема в том, что кнопка не будет активирована сразу после того, как я установил для IsTestrunInProgress значение false, но только после того, как я IsTestrunInProgress внутри окна приложения.

Не могли бы вы помочь мне понять это поведение и показать, как это исправить?

Дальнейшее чтение: шаблон команды wpf - когда он запрашивает, может выполнить

4b9b3361

Ответ 1

Интерфейс ICommand предоставляет событие ICommand.CanExecuteChanged, которое используется для информирования пользовательского интерфейса, когда необходимо переопределить состояние компонентов IsEnabled компонентов, управляемых командами.

В зависимости от реализации используемого RelayCommand, вам может потребоваться поднять это событие; Многие реализации выставляют метод, например RelayCommand.RaiseCanExecuteChanged(), который вы можете вызвать, чтобы заставить пользовательский интерфейс обновляться.

В некоторых реализациях RelayCommand используется CommandManager.RequerySuggested, и в этом случае вам нужно будет вызвать CommandManager.InvalidateRequerySuggested(), чтобы заставить пользовательский интерфейс обновиться.

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

Обновление

Когда состояние кнопки определяется при изменении активного фокуса, я считаю, что используется CommandManager. Поэтому в настройщике вашего свойства после присвоения поля поддержки вызовите CommandManager.InvalidateRequerySuggested().

Обновление 2

Реализация RelayCommand из инструментария MVVM light. При использовании WPF/.NET реализация переносит методы и события, открытые с помощью CommandManager. Это будет означать, что эти команды работают автоматически в большинстве ситуаций (где пользовательский интерфейс изменяется или сфокусированный элемент изменяется). Но в некоторых случаях, таких как этот, вам необходимо вручную принудительно выполнить команду для повторного запроса. Правильный способ сделать это с помощью этой библиотеки - вызвать метод RaiseCanExecuteChanged() на RelayCommand.

Ответ 2

Это так важно и легко пропустить, я повторяю то, что @Samir сказал в комментарии. Г-н Лоран Бугнион написал в blog:

Однако в WPF 4 и WPF 4.5 есть улов: CommandManager перестанет работать после обновления MVVM Light до V5. Что вы заметите, так это то, что ваши элементы пользовательского интерфейса (кнопки и т.д.) Перестанут быть отключенными/включенными, когда делегат RelayCommands CanExecute возвращает false.

Если вы спешите, вот исправление: в любом классе, который использует RelayCommand, замените строку:

using GalaSoft.MvvmLight.Command;

с:

using GalaSoft.MvvmLight.CommandWpf;

Ответ 3

Вы можете попробовать с CommandManager.InvalidateRequerySuggested.

Во всяком случае, это не помогало мне иногда в прошлом. Для меня лучшим решением оказалось привязать логическое свойство к свойству зависимости Button.IsEnabled.

В вашем случае что-то вроде

IsEnabled={Binding IsTestrunInProgress}

Ответ 4

Проблема в том, что свойство ICommand TestrunStartCommand всегда возвращает новый объект команды всякий раз, когда к нему обращаются.

Простое исправление - создать объект ICommand один раз и использовать его снова и снова.

private ICommand _testRunCommand = null;
public ICommand TestrunStartCommand
{
    get 
    { 
        return _testRunCommand ?? (_testRunCommand = new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress)); 
    }
}

Это было довольно простое исправление, и это сработало для меня.