Dies ist MVVM-Anwendung. Es gibt ein Fenster und eine zugehörige Ansichtsmodellklasse.
Es gibt TextBox
, Button
und ListBox
auf dem Formular. Button ist an DelegateCommand
gebunden, das CanExecute
function hat. Idee ist, dass der Benutzer einige Daten in das Textfeld eingibt, die Taste drückt und die Daten an das Listenfeld angehängt werden.
Ich möchte den Befehl (und die Schaltfläche) aktivieren, wenn der Benutzer korrekte Daten in TextBox
eingibt. Die Dinge funktionieren jetzt so:
CanExecute()
enthält Code, der überprüft, ob Daten in der an das Textfeld gebundenen Eigenschaft korrekt sind. UpdateSourceTrigger
wird auf PropertyChanged
gesetzt und die Eigenschaft im Ansichtsmodell wird aktualisiert, nachdem jeder Schlüsselbenutzer gedrückt hat. Problem ist, dass CanExecute()
nicht ausgelöst wird, wenn Benutzer Daten in ein Textfeld eingibt. Es wird nicht ausgelöst, selbst wenn die Textbox den Fokus verliert.
Wie könnte ich das schaffen?
Bearbeiten:
Re Yankos Kommentar:
Der Delegate-Befehl ist in der MVVM-Toolkit-Vorlage implementiert. Wenn Sie ein neues MVVM-Projekt erstellen, befindet sich der Delegate-Befehl in der Lösung. So viel wie ich in Prism-Videos gesehen habe, sollte dies die gleiche Klasse (oder zumindest sehr ähnlich) sein.
Hier ist XAML-Ausschnitt:
%Vor%Modell anzeigen:
%Vor%Wie ich im ersten Teil der Frage schrieb, funktionieren folgende Dinge:
ObjectName
wird bei jedem Tastendruck in der Textbox return true;
in CanAddObject()
einstelle, ist der Befehl aktiv (Schaltfläche zu) Es scheint mir, dass die Bindung korrekt ist.
Was ich nicht weiß ist, wie CanExecute()
fire im Set von ObjectName
property vom obigen Code gemacht wird.
Antworten von Re Ben und Abe:
CanExecuteChanged()
ist Event-Handler und Compiler beschwert sich:
Die Veranstaltung 'System.Windows.Input.ICommand.CanExecuteChanged' kann nur auf der linken Seite erscheinen von + = oder - =
Es gibt nur zwei weitere Mitglieder von ICommand
: Execute()
und CanExecute()
Haben Sie ein Beispiel, das zeigt, wie ich den Befehlsaufruf CanExecute()
machen kann.
Ich habe in DelegateCommand.cs
die Kommandomanager-Hilfsklasse gefunden und werde mich darum kümmern, vielleicht gibt es einen Mechanismus, der helfen könnte.
Wie auch immer, die Idee, dass, um den Befehl basierend auf Benutzereingaben zu aktivieren, man das Objektobjekt "anstupsen" im Eigenschaftseinstellungs-Code anstupsen muss, ist unbeholfen. Es wird Abhängigkeiten einführen und einer der großen Punkte von MVVM ist es, sie zu reduzieren.
Bearbeiten 2:
Ich habe versucht, CanExecute
zu aktivieren, indem ich addObjectCommand.RaiseCanExecuteChanged()
auf ObjectName
property setter vom obigen Code aufruft. Dies hilft auch nicht. CanExecute()
wird einige Male ausgelöst, wenn das Formular initialisiert wird, danach wird es jedoch nie erneut ausgeführt. Dies ist der Code:
Bearbeiten 3: Lösung
Als Yanko Yankov und JerKimball schrieb, Problem ist statische Ressource. Als ich die Tastenbindung änderte, schlug Yanko vor:
%Vor% Dinge begannen sofort zu arbeiten. Ich brauche nicht einmal RaiseCanExecuteChanged()
. Jetzt wird CanExecute
automatisch ausgelöst.
Warum habe ich statische Ressource an erster Stelle verwendet?
Ursprünglicher Code war von WPF MVVM Toolkit Handbuch. Beispiel in diesem Handbuch definiert Befehle als statische Ressource und bindet sie dann an Menüelement. Der Unterschied besteht darin, dass das MVVM-Handbuch in meinem Beispiel statt der Zeichenfolgeeigenschaft mit ObservableCollection
arbeitet.
Bearbeiten Sie 4: Abschließende Erklärung
Ich habe es endlich verstanden. Alles, was ich tun musste, war, Kommentare in CommandReference
klasse zu lesen. Es sagt:
Also wird CommandReference
für KeyBinding
verwendet, nicht für visuelle Elemente. In obigem Code würden Befehlsverweise, die in Ressourcen definiert sind, für KeyBinding funktionieren, das ich nicht für dieses Benutzersteuerelement habe.
Natürlich war der Beispielcode, der mit WPF MVVM Toolkit geliefert wurde, korrekt, aber ich habe ihn falsch gelesen und CommandReference
in den visuellen Elementen verwendet, die binden.
Diese WPF MVVM ist wirklich manchmal schwierig.
Da Sie den DelegateCommand verwenden, können Sie die RaiseCanExecuteChanged-Methode aufrufen, wenn sich die Texteigenschaft ändert. Ich bin mir nicht sicher, was Sie mit Ihrer CommandReference-Ressource erreichen wollen, aber normalerweise binden Sie die Befehle einfach direkt an die Command-Eigenschaft des Schaltflächenelements:
%Vor%Dies wäre der relevante Teil Ihres Ansichtsmodells:
%Vor% Versuchen Sie, CanExecuteChanged
zu erhöhen, wenn sich Ihre Eigenschaft ändert. Die Befehlsbindung unterscheidet sich deutlich von der Eigenschaftsbindung, und Schaltflächen, die an Befehle gebunden sind, werden durch das CanExecuteChanged
-Ereignis auf eine Statusänderung hingewiesen.
In Ihrem Fall könnten Sie eine Überprüfung auslösen, wenn Sie die PropertyChanged
für die gebundene Eigenschaft ausführen, die sie auswerten würde, und das interne CanExecute
-Flag des Befehls setzen und dann CanExecuteChanged
erhöhen. Mehr von einem "Push" in das ICommand
-Objekt als ein "Pull".
Abe hier abhören, aber der "richtige" Pfad, den du hier nehmen willst, benutzt:
%Vor%wird auf DelegateCommand angezeigt. Soweit Abhängigkeiten bestehen, glaube ich nicht, dass Sie wirklich etwas "Schlechtes" tun, indem Sie dies erhöhen, wenn die Eigenschaft, dass der Befehl von Änderungen innerhalb des ViewModels abhängt. In diesem Fall ist die Kopplung mehr oder weniger vollständig innerhalb des ViewModels enthalten.
Wenn Sie also Ihr Beispiel nehmen, würden Sie in Ihrem Setter für "ObjectName" RaiseCanExecuteChanged mit dem Befehl "AddObjectCommand" aufrufen.