2014-02-08 2 views
2

OK. Вот сценарий. Это WPF + MVVM (.net 4.0) приложение:Как вызвать ICommand.CanExecute в этом случае?

  1. Вид: Имеет DataGrid и две кнопки Вверх/Вниз, которые, как предполагается, чтобы переместить выбранную запись вверх или вниз в DataGrid. И сетка, и кнопки используют привязку на основе XAML.
  2. ViewModel: имеет общедоступное свойство DataView, к которому привязано мое DataGrid. Затем есть две версии ICommand, перечисленные ниже. Эти две команды свяжутся с двумя кнопками. И последнее, но не менее важное, есть две функции: MoveUp() и MoveDown(), которые делают очевидные.
  3. Два ICommand реализация: В каждой команде, CanExecute() возвращает ли выбранная запись может перемещаться вверх или вниз, соответственно, и Execute() фактически перемещает запись по телефону MoveUp() и MoveDown() функции ViewModel, я описанная выше. Эти объекты команд получают ссылку на объект VM в своих конструкторах.

Во-первых, я хочу знать, правильная ли эта архитектура и соответствие шаблону MVVM? Во-вторых, проблема под рукой, что мои кнопки не получить включен/выключен при изменении выбранной записи в DataGrid, которая воспитывает 2 подвопросы:

  1. Кто называет CanExecute() и когда?
  2. Как это можно назвать вручную? Я пробовал CommandManager.InvalidateRequerySuggested() после прочтения некоторых других вопросов, но это тоже не помогло.

Вот мой CommandBase класс, из которого оба мои классы команд унаследовать:

internal abstract class CommandBase : DependencyObject, ICommand 
{ 
    public virtual bool CanExecute(Object parameter) 
    { 
     return true; 
    } 

    public abstract void Execute(Object parameter); 
    public event EventHandler CanExecuteChanged; 

    protected void OnCanExecuteChanged(Object sender, EventArgs e) 
    { 
     CanExecuteChanged(sender, e); 
    } 
} 
+0

Какую версию 'ICommand' вы используете? –

+0

Что вы подразумеваете под версией? в 'System.Windows.Input' (PresentationCore.dll 4.0.0) есть только одна« ICommand ». – dotNET

+0

Да, я имел в виду 'DelegateCommand' или' RelayCommand' или собственную производную реализацию 'ICommand'? –

ответ

0

Замените ваш 'OnExcuteChanged' с этим ...

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

Супер! Можете ли вы ввести некоторые объяснения? – dotNET

4

Я хочу знать, если эта архитектура правильная и соответствует шаблону MVVM ?

Да, это полностью соответствует шаблону MVVM.


Кто называет CanExecute() и когда?

CanExecute() вызывается всякий раз, когда CanExecuteChanged возникает событие.

Команды внутренне привязаны к этому событию и кнопка включения/выключения или любой элемент структуры на основе свойства bool, возвращаемого делегатом CanExecute.


Как я могу назвать это вручную?

Прежде всего создайте метод в вашей конкретной реализации (если он еще не), чтобы его можно было вызвать вручную. Это будет выглядеть следующим образом:

public void RaiseCanExecuteChanged() 
    { 
     EventHandler canExecuteChangedHandler = CanExecuteChanged; 
     if (canExecuteChangedHandler != null) 
     { 
      canExecuteChangedHandler(this, EventArgs.Empty); 
     } 
    } 

Так как в вашем случае, вам нужно вызвать CanExecute() всякий раз, когда SelectedItem в изменениях DataGrid. Я бы предложил связать SelectedItem DataGrid с некоторым свойством в ViewModel и в setter, вы вручную вызываете RaiseCanExecuteChanged(), чтобы CanExecute можно было вызвать в вашем экземпляре команды.


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

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

RequerySuggested событие Происходит, когда System.Windows.Input.CommandManager определяет условия, которые могут изменить способность команды для выполнения.

Таким образом, всякий раз, когда CommandManager.RequerySuggested получает рейз, он будет в конечном итоге повышает ваш CanExecuteChanged тем самым вызывая CanExecute вашей команды. Следовательно, включить/отключить кнопку на основе bool, возвращаемую делегатом CanExecute.

+0

Спасибо за подробный ввод. Один вопрос: «RaiseCanExecuteChanged()» отмечен как защищенный.Моя ViewModel не сможет получить к ней доступ. Нет? – dotNET

+0

Правильно, я просто скопировал ваш 'OnCanExecuteChanged()'. Он должен быть общедоступным или быть внутренним, что вам подходит. Обновлено в ответе. –

+0

Еще раз спасибо. Я закончил с 'CommandManager.RequerySposed + = значение;' вещь. Он работает красиво. Не может принять более одного ответа, но он определенно заслуживает +1. – dotNET

0

Я лично всегда использовать реализацию RelayCommand от Джоша Смита:

internal class RelayCommand : ICommand 
{ 
    private readonly Action<object> _execute; 
    private readonly Predicate<object> _canExecute; 

    public RelayCommand(Action<object> execute) : this(execute, null) 
    { 
    } 

    public RelayCommand(Action<object> execute, Predicate<object> canExecute) 
    { 
     if (execute == null) 
     { 
      throw new ArgumentNullException("execute"); 
     } 

     _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); 
    } 
} 

ЦЕНУ о CanExecutedChanged событие из этого link:

В мероприятии CanExecuteChanged, который является частью реализации интерфейса ICommand, имеет некоторые интересные функции. Он делегирует подписку на событие CommandManager.RequerySposed. Это гарантирует, что инфраструктура команд WPF запрашивает все объекты RelayCommand, если они могут выполняться всякий раз, когда запрашивает встроенные команды.

В вашем случае это событие не работает, и объект не получил информацию о возможности выполнения команды.

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