2010-02-25 3 views
19

Meine App wird mit dem MVVM-Muster in WPF geschrieben, und alle meine Schaltflächen verwenden Befehlsbindungen, um Code in meinem Modell auszuführen. Alle Befehle verfügen über Code in CanExecute, um den aktivierten Status der gebundenen Schaltfläche zu bestimmen. Die Logik funktioniert einwandfrei, aber in allen Fällen bleibt die GUI in einem deaktivierten Zustand, wenn ich nicht irgendwo anders in der GUI klicke.Seltsames Problem, bei dem die Schaltfläche nicht wieder aktiviert wird, wenn die Maus nicht geklickt wird

Zum Beispiel habe ich eine Schaltfläche mit dem Namen Discard Candy. Wenn ich auf diese Schaltfläche klicke, wird ein Prozess in einem Threadpool-Thread gestartet, der eine Bool-Eigenschaft namens Running auf true setzt. Da die CanExecute Methode für Verwerfen Candy Befehl wird so etwas wie diese

public bool CanExecute(object parameter) 
{ 
    return !Running; 
} 

die Schaltfläche sieht deaktiviert werden, wenn der Prozess beginnt. Das Problem ist, dass wenn der Prozess abgeschlossen ist, wird Running auf false festgelegt, aber die GUI wird nicht aktualisiert, d. H. Discard Candy wird nicht erneut aktiviert.

Wenn ich jedoch irgendwo in der GUI klicke, wie im Fenster oder in der Titelleiste, wird die Schaltfläche Candy verwerfen plötzlich aktiviert. Die Logik funktioniert also, aber etwas passiert, das ich einfach nicht verstehe. Kann mir bitte jemand dieses Verhalten erklären?

EDIT - bis jetzt klingt es wie CommandManager.InvalidateRequerySuggested hat Menschen nicht geholfen. Ich werde es versuchen, aber im Moment bin ich vorsichtig. Ich folgte den empfohlenen Links und entschied mich, mehr über das MVVM Light Toolkit zu lesen. Es klingt sehr schön - hat jemand hier es verwendet und in der Lage zu bestätigen, dass es das Problem, das ich bisher gesehen habe, nicht ausstellen? Obwohl ich plane, das MVVM Light Toolkit in der nächsten großen rev. von meiner Anwendung möchte ich nicht alle Kommandos wiederholen, die ich momentan habe, weshalb ich wahrscheinlich mit CommandManager.InvalidateRequerySuggested beginnen werde, damit wir alle hier einen weiteren Datenpunkt bezüglich seiner Nützlichkeit bekommen können.

EDIT # 2 - sehr interessant, das MVVM Light Toolkit tatsächlich setzt auf CommandManager.InvalidateRequerySuggested um die UI-Fähigkeit zu unterstützen, zu deaktivieren/Befehle wieder aktivieren. Der Autor sagt:

"Streng genommen, in WPF, und wenn Ihr Befehl an ein Steuerelement gebunden ist, das von CommandManager überwacht wird, sollten Sie das Ereignis CanExecuteChanged nicht selbst auslösen müssen. Sie können den CommandManager behandeln lassen Aus diesem Grund können externe Ereignisse auch den Status der Benutzeroberfläche ändern. Stellen Sie sich vor, dass die Benutzeroberfläche von 9 bis 17 Uhr aktiviert und dann für die Nacht deaktiviert werden sollte. Der Benutzer löst die Benutzeroberfläche nicht aus. höflich), dass die Befehlsmanager den Zustand der Befehle erneut abfragt. Dies wird durch den Aufruf die Methode auf der Command InvalidateRequerySuggested getan. Und wie Sie die Methode RaiseCanExecuteChanged der RelayCommand Klasse vermuten, dass nicht nur. "

+0

Können Sie den Code anzeigen, der Running auf false setzt? Ist es im Callback, nachdem der Thread abgeschlossen ist? –

+0

Heben Sie CanExecuteChanged für den Befehl, wenn Sie Running festlegen? – itowlson

+0

@John: Running wird auf "false" gesetzt, nachdem der Workflow abgeschlossen wurde. Dies ist bekannt, wenn das angegebene Ereignis festgelegt wird. @itowlson: Ich hatte den Eindruck, dass alles "nur magisch funktionieren würde". Als ich dieses Zeug lernte, habe ich in CanExecute einen Haltepunkt gesetzt und es wurde immer wieder getroffen ... aber ich stelle mir vor, dass dies nur deshalb der Fall ist, weil die GUI beim Drücken von F5 neu gezeichnet wird und CanExecute dann erneut aufgerufen wird. Wie dumm von mir! – Dave

Antwort

17

WPF aktualisiert die befehlsbasierten Steuerelemente nur, wenn dies einen Grund hat. Wenn Sie auf die GUI klicken, wird WPF aktualisiert, damit das Update funktioniert.

Sie können manuell eine Aktualisierung aller befehlsgebundenen Steuerelemente durchführen, indem Sie CommandManager.InvalidateRequerySuggested aufrufen.

+1

Danke, Cameron, ich gebe das eine Chance. Ist es lahm, dies in einen Timer mit einem vernünftigen Intervall zu bringen? – Dave

+1

Wahrscheinlich. Können Sie es einfach anrufen, nachdem Sie die Verarbeitung abgeschlossen haben? –

+7

Ich habe das gleiche Verhalten Dave gesehen und CommandManager ausgeführt. InvalidateRequerySuggested hat nicht geholfen. Ich hoffe, dass jemand hier einen Einblick geben kann, warum das manchmal passiert. – Kilhoffer

0

Wenn Sie den Fokus auf das übergeordnete Steuerelement festlegen, wird manchmal CanExecute vom CommandManager ausgelöst.Versuchen Sie, die folgenden nach Laufen auf false:

... 
Running = false; 
parentControl.Focusable = true; 
parentControl.Focus(); 
2

Mein Problem an die Befehlsbindung gebunden zu sein schien - ich RelayCommand verwendet, wie ich häufig tun, aber die Wiedergabe eines Knopfes war einfach nicht richtig, bis ich ein angeklickt Fenster.

den CanExecute Code aus dem Command aus- und eine IsEnabled Eigenschaft anstelle mein Problem ohne Kopfschmerzen Geklärt - es dauerte nur ewig, bis ich versuchte, dies unter so vielen anderen Dingen, die die peoblem haben könnten ...