WPF-Leistungsproblem mit CommandManager

8

Wir haben eine neue, recht komplexe WPF-Anwendung von Grund auf neu erstellt und sind auf ein Performance-Problem gestoßen, als sich die Anzahl der mit CommandManager registrierten Befehle erhöhte. Wir verwenden einfache Lightweight-Befehle in unserer MVVM-Implementierung, verwenden jedoch die Steuerelemente von Drittanbietern, die wir verwenden (Infragistics), und rufen CommandManager.RegisterClassCommandBinding großzügig auf, um RoutedCommands hinzuzufügen. Das Leistungsproblem manifestiert sich als eine wahrgenommene Trägheit in der Benutzeroberfläche, wenn auf Benutzereingaben reagiert wird, beispielsweise ist das Tabbing zwischen Steuerelementen langsam, die Texteingabe ist "ruckartig" und die Popup-Animation ist "klobig". Wenn die App zum ersten Mal gestartet wird, ist die Benutzeroberfläche schnell. Wenn mehr Bildschirme mit Infragistics-Grids geöffnet werden, verschlechtert sich die Leistung.

Intern verfügt der CommandManager über ein privates Feld namens _requerySuggestedHandlers, das eine List & lt; WeakReference & gt ;. Ich habe Reflektionen verwendet, um einen Verweis auf diese Sammlung zu erhalten, und mir ist aufgefallen, dass die Reaktionsfähigkeit der Benutzeroberfläche beim Aufruf von .Clear () wieder in den ursprünglichen Zustand zurückkehrt. Offensichtlich möchte ich nicht Sammlungen aufräumen, von denen ich wenig weiß, vor allem mit Reflektion (!), Aber ich habe es getan, um zu sehen, ob es die Performance-Probleme heilen würde, und voila es tat.

Normalerweise würde sich diese Situation nach einer gewissen Zeit aufräumen. Die Auflistung von WeakReferences (_requerySuggestedHandlers) wird jedoch nur getrimmt, sobald eine Garbage Collection initiiert wird, die nicht deterministisch ist. Wenn wir Fenster schließen, die Raster enthalten (Infragistics XamDataGrid), wird die CanExecute-Eigenschaft für "tote" Rasterbefehle daher auch nach dem Schließen des Fensters weiterhin unnötig ausgewertet. Dies bedeutet auch, dass wenn wir eine Anzahl von Fenstern schließen, die Leistung immer noch langsam ist, bis eine Müllsammlung eingeleitet wird. Ich verstehe, dass dies bei der Zuweisung passieren kann, und ich habe das selbst gesehen, weil, wenn ich ein weiteres Fenster öffne, dies dazu führt, dass der anfängliche Speicher (aus dem entsorgten Windows) gesammelt wird und die Leistung wieder normal wird.

Also, angesichts der obigen, hier sind meine Fragen:

  1. Wie und wo wird CommandManager.InvalidateRequerySuggested () aufgerufen? Ich habe keine Dokumentation auf MSDN gefunden, die dies im Detail erklärt. Ich habe mich an das CommandManager.RequerySuggested-Ereignis angeschlossen und es sieht so aus, als ob es aufgerufen wird, wenn die Steuerung den Fokus verliert.
  2. Ist es möglich zu unterdrücken, dass CommandManager.InvalidateRequerySuggested () als Reaktion auf Benutzereingaben aufgerufen wird?
  3. Ist noch jemand auf dieses Problem gestoßen, und wenn ja, wie haben Sie es gemieden?

Danke!

    
Lee F 28.02.2011, 16:03
quelle

1 Antwort

4

Das hört sich nach einem der seltenen Fälle an, in denen deterministisch GC.Collect() aufgerufen werden muss. Das übliche Argument dagegen ist, dass der Müllsammler schlauer ist als Sie. Wenn Sie jedoch mit WeakReference -Objekten arbeiten, betreten Sie ein Gebiet, in dem Sie möglicherweise etwas wissen, was der Garbage Collector nicht tut. Das Aufheben der Garbage Collection ist sicherlich besser als das Löschen von _requerySuggestedHandlers - unter anderem wird es nichts mit den WeakReference -Objekten tun, die auf noch lebende Controls zeigen.

Ich würde dies wählen, um herauszufinden, wie RequerySuggested unterdrückt werden kann, da dies das Verhalten der Befehle stören würde, die Sie immer noch interessieren.

    
Robert Rossney 28.02.2011, 18:11
quelle

Tags und Links