7 Bewährte WPF-Praktiken

In Fortsetzung unserer WPF-Themenreihe lade ich Sie ein, diese Sammlung von sieben Best Practices durchzugehen.

Ganz gleich, ob Sie mit einer neuen oder einer bestehenden Anwendung beginnen, es kann nicht schaden, sich der Leistung Ihres Codes bewusst zu sein und zu wissen, was in dieser Richtung getan werden kann.

All dies sind Erkenntnisse, die ich im Laufe der Zeit gewonnen habe, als ich sah, wie bestimmte von mir geschriebene Codeteile funktionierten. Einige von ihnen konnte ich vom Standpunkt der Leistung aus verbessern. Andere wiederum vom Standpunkt des Codes oder sogar der Logik aus gesehen.

wpf best practices

Hier sind sie:

#1 IsVisible Boolesche Eigenschaft

Wenn Sie die Sichtbarkeit eines UIElements aktualisieren müssen, ist die Standardempfehlung, die Sie (z. B. auf StackOverflow) finden, die Verwendung der booleschen Eigenschaft im Ansichtsmodell „IsVisible“ und eines Konverters, in dem Sie das boolesche IsVisible in Visibility.Visible oder Visibilty.Collapsed umwandeln.

Falscher Ansatz

Die Verwendung eines Konverters bedeutet zusätzlichen Code. Um eine Eigenschaft sichtbar oder unsichtbar zu machen, müssen Sie einen Konverter aufrufen, den Sie instanziieren müssen. Das ist zeit- und energieaufwendig.

IsVisibile Boolean bad approach

Optimaler Ansatz

Die optimale und logischere Lösung wäre es, genau die Daten zu verwenden, die Sie benötigen, d. h. direkt den Sichtbarkeitstyp für die Eigenschaft IsVisible im Ansichtsmodell zu verwenden. Sie müssen das Rad nicht neu erfinden.

is visible bool good

#2 Aktualisieren Sie nur, wenn es nötig ist

Manchmal fängt ein Benutzer an, einen Wert in einem Feld zu ändern, nur um ihn dann wieder zu ändern. In diesem Fall besteht keine Notwendigkeit, eine Aktualisierung an die Datenbank zu senden, da sich nichts geändert hat. Ich habe jedoch festgestellt, dass die am häufigsten verwendete Vorgehensweise die folgende ist:

Falscher Ansatz

update when need to bad approach

Dies ist nicht gerade der optimale Ansatz, da die Aktualisierung unabhängig von der Änderung der Eigenschaft gesendet wird.

Optimaler Ansatz

Die bessere Methode wäre, wenn der neu eingegebene Wert gleich dem alten ist, dass keine Aktualisierung gesendet wird:

update when need to good approach

Optimaler Ansatz II

Als zweite gute Möglichkeit bietet Microsoft die Klasse BindableBase an, die den gesamten Code in einer Zeile behandelt.

Sie können also BindableBase von Prism verwenden und das Ereignis über die Methode SetProperty auslösen. Wenn BindableBase für Ihr aktuelles Projekt nicht verfügbar ist, implementieren Sie einfach in einer Basisklasse die SetProperty-Methode.

#3 Allgemeine Stile

Mittlerweile ist es vernünftig geworden, alle Stile an einem Ort zu haben. Wenn Sie sie über alle Dateien Ihrer Anwendung verstreut haben, müssen Sie, wenn Sie zum Beispiel alle Schaltflächen grün statt grau darstellen wollen, Änderungen an 20, 50 oder 100 verschiedenen Stellen vornehmen. Wenn Sie die Stile in einer einzigen Datei haben und dieser Stil von dort aus von jedem Element aufgerufen wird, das ihn benötigt, können Sie die Änderung an einer Stelle vornehmen, und dann wird sie überall, wo der Stil verwendet wird, übernommen.

Das spart nicht nur Arbeit, sondern verhindert auch, dass Sie doppelten Code verwenden. Verschieben Sie allgemeine Stile, Farben oder Daten in Ressourcendictionaries und Dictionaries, die in der App.xaml hinzugefügt werden, und verwenden Sie von dort aus StaticResource, um darauf zu verweisen. Dies ist auch nützlich, wenn Sie Themes haben.

#4 Konverter

Bei Konvertern sehe ich nicht unbedingt einen schlechten oder optimalen Ansatz. Sie können sie entweder von MarkupExtension ableiten – einer Klasse von Microsoft – und sie direkt dort verwenden, wo Sie sie brauchen; oder Sie können eine Instanz in der Ressource-Region des Steuerelements erstellen und sie dann mit Resource referenzieren – Sie erhalten das gleiche Ergebnis, aber der XAML-Code wird schwerer zu lesen sein.

Erster Ansatz

Der Konverter ist nicht von MarkupExtension abgeleitet. Sie müssen diese Instanziierung von zusätzlichem Code in XAML durchführen, und dies „verschmutzt“ die Datei mit nutzlosem Code, wie im folgenden Beispiel:

converters first approach

Zweiter Ansatz

Wenn Sie die MarkupExtension verwenden, können Sie sie direkt in XAML verwenden, ohne dass Sie weitere 2-3 Zeilen Code benötigen. Auf diese Weise wird jeder Konverter, der mit dieser Methode durchgeführt wird, direkt dort verwendet, wo Sie ihn benötigen. Dies würde sich in leichterem, besser lesbarem und weniger unübersichtlichem Code niederschlagen, wie im nächsten Beispiel:

converters second approach

Keine der beiden Methoden ist ein Fehler, es liegt an den Vorlieben des Programmierers. Aber diese Auszeichnungserweiterung ist auf Stack Overflow nicht sehr beliebt.

Dritter Ansatz

Wenn Sie noch effizienter sein wollen, können Sie einen Konverter mit MarkupExtension zu einem Ressourcenwörterbuch hinzufügen – auf diese Weise wird er nur einmal instanziert. Wie das folgende:

converters-third

#5 Verzögerungen bei der Bindung

Dies ist nützlich für Textfelder. Standardmäßig sendet die App bei jedem eingegebenen Buchstaben die Information an die Datenbank, dass ein weiterer Buchstabe zu dem eingegebenen Wort hinzugefügt wurde. Wenn Sie jedoch eine Bindungsverzögerung von 1 bis 2 Sekunden einstellen, wird je nach Bedarf nur alle 2 Sekunden eine Aktualisierung an die Datenbank gesendet. Und in zwei Sekunden hat der Benutzer Zeit, sechs bis sieben Zeichen zu tippen. Dies bedeutet eine Aktualisierung anstelle von bis zu 6 Aktualisierungen alle 2 Sekunden bei Verwendung von Bindungsverzögerungen.

Dies führt zu einer besseren Leistung, weniger Energieverbrauch usw.

#6 Auslöser vs. VisualStates

Auch hier geht es nicht um die Frage, ob ein Ansatz gut oder schlecht ist. In den meisten Fällen sind Trigger der einfachste Weg, um einen visuellen Effekt zu erzielen, aber in einigen Fällen führt dies zu einer schlechten Leistung (z. B. führt der Mauszeiger über eine Liste von Elementen via Trigger zu einer „Geister-/Verzögerungsmarkierung“, während der VisualStates-Mechanismus die Markierung verbessert). Bedenken Sie also, dass VisualStates in diesem Fall der bessere Ansatz sind.

Hier sind einige Beispiele für einen einfachen Vergleich:

Verwendung von Triggern

Trigger sind viel einfacher zu verwenden (3 Zeilen Code). Das wäre einfacher zu schreiben:

using triggers

Verwendung von VisualStates

VisualStates sind nativer in WPF als Triggers. Sie erfordern mehr Code, aber sie sind schneller und leistungsfähiger. Der Vorteil ist, dass ein Teil dieses Codes Standard ist:

using visual states

Ich hatte z. B. eine Situation, in der ich einen Geisterschatten verwenden musste, und ich konnte den Unterschied deutlich sehen, da die Hervorhebung weit hinter der Maus zurückblieb, was man nicht möchte.

Manchmal kommt es auf den Test an: Wenn die Verzögerung für den Benutzer nicht spürbar ist, kann es in Ordnung sein, Auslöser zu verwenden, die weniger Code erfordern. Aber in Fällen, in denen die Leistung wichtig ist, ist es besser, visuelle Zustände zu verwenden.

#7 TemplateBinding

Meiner Meinung nach ist es am besten, TemplateBinding zu verwenden, wenn man innerhalb eines Templates arbeitet. Andernfalls können einige UI-Bugs erzeugt werden (UI-Inkonsistenz).

TemplateBinding ermöglicht es Ihnen, eine Schaltfläche an einige Eigenschaften innerhalb der Schaltfläche zu binden.

Innerhalb der Schaltfläche besteht das Styling aus mehreren Elementen: einem Rahmen, innerhalb des Rahmens einem Panel, innerhalb des Panels einem Symbol und innerhalb des Symbols einem Textfeld. Wenn wir einen roten Hintergrund für die Schaltfläche festlegen, müssen wir bei der Definition des Rahmens und des Feldes die Farben für jedes Element festlegen.

Hier sind zwei Beispiele, um dies zu veranschaulichen:

Schlechter Ansatz

template binding bad approach

Richtiger Ansatz

template binding correct approach

#… Die Liste ist offen

Dies sind natürlich nur einige der besseren Alternativen, die Sie beim Schreiben Ihres Codes verwenden können. Wenn Sie auf andere Beispiele für leistungsorientierte WPF-Code-Schreibtipps gestoßen sind oder eine andere Sichtweise als die in der aktuellen Liste teilen möchten, tun Sie dies bitte im Kommentarbereich unten.