2013-02-22 6 views
8

Ich habe ein einfaches Fenster mit einer Schaltfläche, die an ein ViewModel mit einem Befehl gebunden ist.Die Schaltfläche wird nicht deaktiviert, wenn der Befehl CanExecute falsch ist.

Ich erwarte, dass die Schaltfläche deaktiviert wird, wenn MyCommand.CanExecute() false ist. Aber es scheint, dass WPF die IsEnabled-Eigenschaft nur festlegen wird, wenn das Fenster zum ersten Mal gezeichnet wird. Jede nachfolgende Aktion wirkt sich nicht auf den sichtbaren Status der Schaltfläche aus. Ich verwende einen DelegateCommand von Prism.

Meine Ansicht:

<Window x:Class="WpfApplication1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"> 
<Grid> 
    <Button Content="Click Here" Command="{Binding MyCommand}" Width="100" Height="50"/> 
</Grid> 

und mein Viewmodel:

public class MyVM : NotificationObject 
{ 
    public MyVM() 
    { 
     _myCommand = new DelegateCommand(DoStuff, CanDoStuff); 
    } 

    private void DoStuff() 
    { 
     Console.WriteLine("Command Executed"); 
     _myCommand.RaiseCanExecuteChanged(); 
    } 

    private bool CanDoStuff() 
    { 
     var result = DateTime.Now.Second % 2 == 0; 
     Console.WriteLine("CanExecute is {0}", result); 
     return result; 
    } 

    private DelegateCommand _myCommand; 

    public ICommand MyCommand 
    { 
     get 
     { 
      return _myCommand; 
     } 
    } 
} 

50% der Zeit, wenn meine Anwendung geladen wird, wird der Button ordnungsgemäß deaktiviert. Wenn es jedoch aktiviert wird, wenn das Fenster geladen wird, und ich auf die Schaltfläche zum Ausführen des Befehls klicke, erwarte ich, dass die Schaltfläche 50% der Zeit deaktiviert wird, aber das geht nicht. Der Befehl wird nicht ausgeführt, aber ich kann trotzdem auf die Schaltfläche klicken. Wie bekomme ich WPF zu verstehen, dass die Schaltfläche deaktiviert werden sollte, wenn CanExecute() falsch ist?

+0

Das erste, was Sie tun müssen, um Debug-Nachrichten für Datenbindung wieder auftauchen: http://i.stack.imgur.com/MF8i5.png Als nächstes erneut ausführen und überprüfen Sie das Ausgabefenster und sehen Sie, welche Fehler vorhanden sind. Wenn sich keiner auf Ihre Befehlsbindung bezieht, ist Ihre Implementierung von 'RaiseCanExecuteChanged()' falsch/fehlerhaft. – Will

+0

Ihre CanDOStuff-Methode ist wirklich seltsam! Es könnte Ihre Schaltfläche deaktivieren, aber in der nächsten Sekunde könnte Ihr Befehl ausgeführt werden, aber die Schaltfläche ist deaktiviert ... Wirklich seltsam. Sie sollten jedoch [CommandManager.InvalidateRequerySuggested()] (http://msdn.microsoft.com/en-us/library/system.windows.input.commandmanager.invalidaterequerysuggested.aspx) aufrufen, wenn Ihr CanExecute geändert werden kann und die UI dies nicht ist aktualisiert, weil CanExecuteChanged nicht ausgelöst wurde. –

+0

@Viktor Ich weiß, es ist wirklich komisch, es soll ein dummes Beispiel sein, das nach dem Zufallsprinzip wahr/falsch zurückgibt. CommandManager.InvalidateRequerySuggested hat keine Auswirkungen. –

Antwort

6

Ich sehe, dass Sie Prism und seine NotificationObject und DelegateCommand verwenden, also sollten wir erwarten, dass es keinen Fehler in RaiseCanExecuteChanged() gibt.

jedoch der Grund für das Verhalten ist, dass Prism RaiseCanExecuteChanged synchron arbeitet, so CanDoStuff() aufgerufen wird, während wir erscheint noch in der Umsetzung von ICommand.Execute() und das Ergebnis dann ignoriert werden.

Wenn Sie eine weitere Schaltfläche mit einem eigenen Befehl erstellen und _myCommand.RaiseCanExecuteChanged() über diesen Befehl/Schaltfläche aufrufen, wird die erste Schaltfläche wie erwartet aktiviert/deaktiviert.

Oder, wenn Sie die gleiche Sache mit MVVM Licht und RelayCommand Code versuchen arbeiten, weil MVVM RaiseCanExecuteChanged Anrufe CommandManager.InvalidateRequerySuggested() des Lichts, das den Rückruf zu CanDoStuff ruft asynchron Dispatcher.CurrentDispatcher.BeginInvoke verwenden, um das Verhalten zu vermeiden Sie mit Prism-Implementierung sind zu sehen.

+0

Danke für die Erklärung. Ich habe beide Vorschläge ausprobiert und sie sind genau richtig. Scheint wie eine unglückliche Einschränkung von Prism. –

0

Sie können versuchen, diese (Microsoft.Practices.Prism.dll ist erforderlich)

public class ViewModel 
{ 
    public DelegateCommand ExportCommand { get; } 

    public ViewModel() 
    { 
     ExportCommand = new DelegateCommand(Export, CanDoExptor); 
    } 

    private void Export() 
    { 
     //logic 
    } 

    private bool _isCanDoExportChecked; 

    public bool IsCanDoExportChecked 
    { 
     get { return _isCanDoExportChecked; } 
     set 
     { 
      if (_isCanDoExportChecked == value) return; 

      _isCanDoExportChecked = value; 
      ExportCommand.RaiseCanExecuteChanged(); 
     } 
    } 

    private bool CanDoExptor() 
    { 
     return IsCanDoExportChecked; 
    } 
} 
Verwandte Themen