2015-02-05 10 views
5

Ich habe ein Formular mit einem Textfeld und einer Schaltfläche.Button-Befehl CanExecute nicht aufgerufen, wenn Eigenschaft geändert

Wenn der Wert dieses Textfelds geändert wurde, ruft der Schaltflächenbefehl die CanExecute-Methode des Befehls nicht auf.

Der Befehlsparameter ist gesetzt, scheint sich aber nicht zu ändern. Nach dem Laden des Fensters bleibt die Schaltfläche deaktiviert.

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

Ich weiß, dass die Bindung funktioniert, weil ich ein Verhalten geschaffen, die ein Ziel empfängt Bindung und erhöhen die CanExecute, wenn die die Bindung ändert.

Mit diesem Verhalten wird das CanExecute normalerweise aufgerufen.

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

Ansichtsmodell:

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

Weiß jemand, warum die Schaltfläche nicht die CanExecute nicht nennen?

+0

Wie Schaltfläche Befehl wird ausgelöst, wenn Sie Textbox Text ändern? –

+0

Da das Textfeld an eine Eigenschaft mit Benachrichtigung gebunden ist und das CommandParameter der Schaltfläche an dieselbe Eigenschaft gebunden ist, wird es benachrichtigt und ruft die CanExecute-Methode des Befehls auf. –

Antwort

8

In Ihrer DelegateCommand Implementierung CanExecuteChanged sollte

Tritt zu CommandManager.RequerySuggested Ereignis hinzufügen/entfernen, wenn die Befehlsmanager Bedingungen erkennt, die die Fähigkeit eines Befehls auszuführen ändern könnte.

Änderung es

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

Ich benötige eine öffentliche Methode zum Auslösen von CanExecuteChanged. Kann ich auch zu einem privaten _canExecuteChanged hinzufügen/entfernen? Oder gibt es einen besseren Weg? –

+1

Technisch können Sie, aber wenn Sie Befehl erneut validieren möchten, können Sie ['CommandManager.InvalidateRequerySuggested'] (https://msdn.microsoft.com/en-us/library/system.windows.input.commandmanager.invalidaterequerussuggespeichert (v = vs.110) .aspx) Methode. Sie erzwingt, dass der CommandManager das RequerySuggested-Ereignis _ auslöst. – dkozl

+0

Aktualisiert CommandManager.InvalidateRequerySuggested alle Befehle der Anwendung? –

Verwandte Themen