2015-02-05 17 views
5

Ho un modulo con una casella di testo e un pulsante.Pulsante Comando CanExecute non chiamato quando la proprietà è cambiata

Quando la casella di testo ha il suo valore modificato, il comando di pulsante non chiama il metodo CanExecute del suo comando.

Il parametro di comando è impostato ma non sembra cambiare. Dopo aver caricato la finestra, il pulsante rimane disabilitato.

<TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
<Button Content="Save" Command="{Binding SaveChangesCommand}" CommandParameter="{Binding Name}" /> 

So che il legame funziona perché ho creato un comportamento che riceve un obiettivo vincolante ed aumentare il CanExecute quando i cambiamenti vincolanti.

Con questo comportamento, CanExecute viene chiamato normalmente.

<Button Content="Save" Command="{Binding SaveChangesCommand}"> 
    <i:Interaction.Behaviors> 
     <behaviors:CallCommandCanExecuteWhenBindingChange Target="{Binding Name}" /> 
    </i:Interaction.Behaviors> 
</Button> 

ViewModel:

public class EditViewModel : INotifyPropertyChanged 
{ 
    private string _name; 

    public EditViewModel() 
    { 
     SaveChangesCommand = new DelegateCommand(p => SaveChanges(), p => CanSaveChanges()); 
    } 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      if (value == _name) return; 
      _name = value; 
      OnPropertyChanged(); 
     } 
    } 

    public DelegateCommand SaveChangesCommand { get; private set; } 

    private void SaveChanges() 
    { 
    } 
    private bool CanSaveChanges() 
    { 
     return !string.IsNullOrWhiteSpace(Name); 
    } 
} 

DelegateCommand:

public interface IBaseCommand : ICommand 
{ 
    void OnCanExecuteChanged(); 
} 

public class DelegateCommand : IBaseCommand 
{ 
    private readonly Action<object> _execute; 
    private readonly Func<object, bool> _canExecute; 

    public DelegateCommand(Action<object> execute, Func<object, bool> canExecute) 
    { 
     _execute = execute; 
     _canExecute = canExecute; 
    } 

    public event EventHandler CanExecuteChanged; 

    public bool CanExecute(object parameter) 
    { 
     return _canExecute(parameter); 
    } 
    public void Execute(object parameter) 
    { 
     _execute(parameter); 
     OnCanExecuteChanged(); 
    } 

    public void OnCanExecuteChanged() 
    { 
     var handler = CanExecuteChanged; 
     if (handler != null) 
      handler(this, EventArgs.Empty); 
    } 
} 

CallCommandCanExecuteWhenBindingChange:

public class CallCommandCanExecuteWhenBindingChange : Behavior<FrameworkElement> 
{ 
    public static readonly DependencyProperty<CallCommandCanExecuteWhenBindingChange, object> TargetProperty; 
    private ICommandBase _command; 

    static CallCommandCanExecuteWhenBindingChange() 
    { 
     var dependency = new DependencyRegistry<CallCommandCanExecuteWhenBindingChange>(); 

     TargetProperty = dependency.Register(b => b.Target, s => s.OnTargetChange()); 
    } 

    public object Target 
    { 
     get { return TargetProperty.Get(this); } 
     set { TargetProperty.Set(this, value); } 
    } 

    private void OnTargetChange() 
    { 
     if (_command == null && AssociatedObject != null) 
     { 
      var field = AssociatedObject.GetType().GetProperty("Command"); 
      _command = (IBaseCommand)field.GetValue(AssociatedObject); 
     } 

     if (_command != null) 
      _command.OnCanExecuteChanged(); 
    } 
} 

Qualcuno sa il motivo per cui il pulsante non chiama il CanExecute?

+0

Come pulsante di comando si attiva quando si cambia il testo Casella di testo? –

+0

Poiché la casella di testo è vincolante per una proprietà con notifica e CommandParameter del pulsante è vincolante per la stessa proprietà, verrà notificato e richiamerà il metodo CanExecute del comando –

risposta

8

Nella tua DelegateCommand implementazione CanExecuteChanged dovrebbe aggiungere/rimuovere a CommandManager.RequerySuggested evento

Si verifica quando il CommandManager rileva le condizioni che potrebbero cambiare la capacità di un comando da eseguire.

cambiamento a

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

Ho bisogno di un metodo pubblico per aumentare CanExecuteChanged. Posso aggiungere/rimuovere anche a un _canExecuteChanged privato? O c'è un modo migliore? –

+1

Tecnicamente è possibile ma se si desidera riconvalere il comando è possibile chiamare ['CommandManager.InvalidateRequerySuggested'] (https://msdn.microsoft.com/en-us/library/system.windows.input.commandmanager.invalidaterequerysuggested (v = vs.110) .aspx) metodo. _forces il CommandManager per aumentare l'evento RequerySuggested_. – dkozl

+0

Does CommandManager.InvalidateRequerySuggested aggiorna tutti i comandi dell'applicazione? –

Problemi correlati