2016-03-01 4 views
2

Я использую Josh Smith's implementation of RelayCommand в нескольких крупных проектах уже несколько лет. Однако сегодня я столкнулся с сценарием, когда CanExecute по одной из моих команд не освежает. Я в недоумении относительно того, что вызывает это - модель представления не делает ничего, что я уже не делал уже десятки раз.В каких сценариях ICommand CanExecute не обновляется?

Конструктор VM создает пару команд. Первый из них является команда "Пуск": -

StartCommand = new RelayCommand(o => StartAsync(), o => true); 

метод StartAsync() выглядит следующим образом: -

private async void StartAsync() 
{ 
    IsRunning = true; 
    await Task.Run(() => SomeLongRunningProcess(); } 
    IsRunning = false; 
} 

Существует также команда "сохранить": -

SaveCommand = new RelayCommand(o => Save(), o => !IsRunning); 

('IsRunning' - это свойство bog-standard, реализующее INotifyPropertyChanged. Также, как и для делегата CanExecute, он также привязан к свойству IsEnabled нескольких элементов управления в представлении, чтобы включить/отключить их).

Когда я нажимаю кнопку «Пуск» (привязана к «StartCommand»), кнопка «Сохранить» правильно отключена. Процесс b/g завершается, тогда значение IsRunning установлено на false, но это не приводит к включению кнопки «Сохранить». Он позволяет только щелкнуть где-нибудь на моем представлении.

(Элементы управления которых IsEnabled свойство связано со свойством В. М. IsRunningсделать включать и выключать правильно, кстати).

Я натолкнулся на несколько статей SO об этом, но ничего не объясняет , почему это происходит. Моим обходным путем было привязать свойство кнопки IsEnabled к «IsRunning», но это разочаровывает, что этот конкретный вид отказался играть в мяч. Любые мысли о том, что может быть причиной этого? Здравый смысл говорит, что это что-то особенное для этого взгляда/VM, но я в тупик (и я не буду публиковать код здесь - слишком много).

+0

Является 'SomeLongRunningProcess()' фоновый поток или поток, кроме потока пользовательского интерфейса? Может ли это быть проблемой сквозного доступа к компонентам пользовательского интерфейса? – CodingGorilla

+0

Ваши команды могут реализовать событие CanExecuteChanged. Вы пробовали это? – XAMlMAX

+0

@CodingGorilla Это поток b/g, однако, когда он заканчивается в ожидании, в потоке пользовательского интерфейса происходит «IsRunning = false». Я использовал ту же технику в командах на других видах/виртуальных машинах без проблем. –

ответ

5

Да, потому что версия RelayCommand, которую вы используете, зависит от события CommandManager.RequerySuggested, и это не точно.

Его documentation states что

Occurs when the CommandManager detects conditions that might change the ability of a command to execute.

В основном это угадывает все возможные события, где ваши данные могут быть изменены. Он никогда не узнает, когда изменилась ваша модель ViewModel/Model. Он не слушает уведомления об изменении свойств.

Если вы хотите немедленно отреагировать, не дожидаясь, пока у вас не будет CommandManager, вам необходимо вручную запустить ICommand.CanExecuteChanged, когда будет обновлена ​​модель.

Вы видели, что событие не уволили, если вы нажмете на окно или что-то, но не отметить, что it could fire several times too

+0

Любопытно, почему это работает на моих других видах/виртуальных машинах, но, к сожалению, я не вижу ничего, что я делаю по-другому, поэтому я думаю, что это очень тонкая разница. Я где-то читал, что только команды мыши и клавиатуры запускают CommandManager, но я немного скептически отношусь к этому. В моих виртуальных машинах много и много мест, где я устанавливаю значения свойств (или даже просто частные вары), которые используются в логике команд CanExecute, и обычно это «работает», когда я нигде не приближаюсь к мыши или клавиатуре , –

+1

@AndrewStephens Трудно догадаться. Но события клавиатуры или мыши - это не единственные вещи, которые, как я полагаю, вызывает недействительность. Если я не ошибаюсь, они возникают, когда окно активируется/деактивируется и т. Д. Вы можете [проверить источник] (http://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Input/ Command/CommandManager.cs, fb01095b2fe73140, ссылки), если вам интересно –