{"id":2548,"date":"2012-03-30T16:58:37","date_gmt":"2012-03-30T14:58:37","guid":{"rendered":"http:\/\/www.centigrade.de\/blog\/en\/?p=2548"},"modified":"2020-02-13T16:25:30","modified_gmt":"2020-02-13T15:25:30","slug":"wpf-performance","status":"publish","type":"blog","link":"https:\/\/www.centigrade.de\/de\/blog\/wpf-performance\/","title":{"rendered":"WPF Performance \u2013 Was geht mich das auf dem User Interface \u00fcberhaupt an?"},"content":{"rendered":"<p>Ein Thema, welches bei der Entwicklung von Software immer eine gro\u00dfe Rolle spielt, ist unumstritten das Thema Performance. Auch wenn uns bei der Softwareentwicklung mit .NET im WPF Umfeld schon sehr viel Arbeit bez\u00fcglich gutem Laufzeitverhalten durch Windows abgenommen wird, gibt es eine Vielzahl von Performance Aspekten, welche bei der Implementierung beachtet werden sollten.<\/p>\n<p>Doch was wird eigentlich in der Informatik durch das Wort \u201cPerformance\u201d oder \u201ePerformanz\u201c beschrieben? Allgemein wird das Wort Performance (deutsch: Leistung) verwendet, um das Verm\u00f6gen einer Software zu beschreiben, Aufgaben auszuf\u00fchren (siehe <a href=\"http:\/\/de.wikipedia.org\/wiki\/Leistung_(Informatik)\">Wikipedia<\/a>). Umgangssprachlich geht es beim Begriff Performance meist darum, wie \u201cschnell\u201d eine Anwendung ist. Dabei wird normalerweise jedoch kein Unterschied zwischen der Performance des User Interface und der Performance der Anwendungslogik gemacht.<\/p>\n<p>Trotzdem sollte innerhalb des Entwicklungsteams eine klare Trennung gemacht werden, welche Performance Aspekte f\u00fcr wen von Relevanz sind. Ein h\u00e4ufiger Fehler besteht darin, die Optimierung der Performance in die Verantwortung eines einzelnen Entwicklers zu geben. Obwohl das Thema Performance an sich die gesamte Applikation betrifft, ist es aber vorteilhaft, dass Optimierungen nicht nur durch eine einzelne Person aus dem Entwicklerteam abgedeckt, sondern entsprechend Fachkompetenzen und Spezialisierungen an die richtigen Personen verteilt werden. Genau aus diesem Grund, bem\u00fche ich mich als <a href=\"http:\/\/www.centigrade.de\/de\/blog\/user-interface-design-engineering-eine-neue-disziplin-mit-zukunft\/\">UI Design Engineer<\/a> bei Centigrade h\u00e4ufig darum, in Performance Analysen unserer Kunden bei .NET basierten Softwareprojekten einbezogen zu werden, um gerade an den Stellen, die den auf XAML-basierenden Teil des User Interface betreffen eine Optimierung zu realisieren, w\u00e4hrend unsere Kunden Performance-Optimierungen oftmals eher an der C#-basierten User Interface Logik oder noch tiefer liegenden Schichten vornehmen.\u201c<br \/>\n<!--more--><\/p>\n<h2>Performanceprobleme erkennen<\/h2>\n<p>Damit eine Performanceoptimierung erfolgen kann, m\u00fcssen zu Beginn erst einmal die \u201eProblemstellen\u201c der Software erkannt und lokalisiert werden. Ohne entsprechende Daten lassen sich Performanceanalysen nur schwer durchf\u00fchren, da das Entwicklungssystem in den seltensten F\u00e4llen dem sp\u00e4teren Zielsystem entspricht und durch reines \u201eAusprobieren\u201c daher keine genaue Beurteilung bez\u00fcglich des Laufzeitverhaltens getroffen werden kann. Um relevante und aussagekr\u00e4ftige Daten f\u00fcr .NET basierte Softwaresysteme zu erhalten, gibt es eine Vielzahl n\u00fctzlicher Tools. Am bekanntesten d\u00fcrfte hier die WPF Performance Suite sein. Diese ist im <a href=\"http:\/\/msdn.microsoft.com\/de-de\/windowsserver\/bb980924.aspx\">Windows SDK<\/a> enthalten.<\/p>\n<p>Um ein genaues Performance Profil einer Anwendung erstellen zu k\u00f6nnen, sind nach der Installation der Performance Suite folgende Tools verf\u00fcgbar.<\/p>\n<h3><strong>Perforator<\/strong><\/h3>\n<p>Das Perforator Tool hilft vor allem bei der Analyse des Renderingverhaltens, also des Zeichenverhaltens einer WPF-Anwendung. Durch verschiedene Diagramme kann so eine genauere Analyse bez\u00fcglich des Renderingvorgangs durchgef\u00fchrt werden, da maximale Auslastungen der CPU so schnell zu erkennen sind. Mit Hilfe einer Vielzahl von Einstellungen k\u00f6nnen verschiedenste Konfigurationen einer Anwendung, wie beispielsweise das Laufzeitverhalten mit oder ohne Opacity Effekten durchgespielt werden. Dank der als \u201edirty rectangle\u201c bezeichneten Renderingtechnik von WPF, werden in einer .NET Anwendung nur Bereiche welche sich \u00e4ndern neu gezeichnet. Mit Hilfe der Funktionen \u201eShow dirty-region update Overlay\u201c werden genau diese Bereiche in der Anwendung eingef\u00e4rbt. So erh\u00e4lt man als UI Design Engineer schon einmal einen kleinen \u00dcberblick, welche Teile der Anwendung bei welchen Aktionen neu gezeichnet werden m\u00fcssen und somit einen negativen Einfluss auf die Performance haben k\u00f6nnen. Schon durch kleine \u00c4nderungen, wie z.B. das Tauschen eines Layout Containers, k\u00f6nnen so erste Erfolge verbucht werden.<\/p>\n<p>Hier ein Ausschnitt aus Perforator, um den Unterschied zwischen einer Anwendung mit vielen Renderingoperationen und wenigen in Zahlen verdeutlichen zu k\u00f6nnen.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/DirtyRect1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2639\" title=\"Dirty Rectangle Beispiel\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/DirtyRect1.png\" alt=\"\" width=\"605\" height=\"347\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/DirtyRect1.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/DirtyRect1-300x172.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>In diesem Beispiel wurde durch die Funktion \u201eDisable dirty region support\u201c (rot eingekreist) einmal der Extremfall, n\u00e4mlich dass sich bei jeder Aktion auf dem UI die komplette Anwendung neu rendern muss, simuliert. Ob dieser Fall in einer Anwendung auftritt, kann durch die oben beschriebene Funktion (blau eingekreist) herausgefunden werden. Beispielsweise k\u00f6nnen Animationen welche mit der <em>FluidLayout<\/em> Funktionalit\u00e4t von Expression Blend realisiert wurden zu solchen Effekten f\u00fchren. Denn mit Hilfe des <em>FluidLayout<\/em> k\u00f6nnen Eigenschaften, wie z.B. die Visibility, welche eigentlich keine \u00dcberg\u00e4nge haben, animiert werden. Dies kann zu einem st\u00e4ndigen Neuzeichnen f\u00fchren. Ein Zeichenvorgang in dieser Beispielanwendung hatte bis zu 79rects\/s welche sich w\u00e4hrend einer Animation zum Ausklappen einer Men\u00fcleiste ge\u00e4ndert haben. Wird diese Animation durch <em>FluidLayout<\/em> realisiert, wodurch Expression Blend intern einen Custom Visual State Manager installiert, hat dies zur Folge, dass sich das komplette Fenster neu zeichnet. F\u00fcr die gleiche Animation wie zuvor wurden jetzt bis zu 231rects\/s neu gerendert. Wenn man einmal ber\u00fccksichtigt, dass die Beispielanwendung wirklich minimale Anforderungen hatte, kann man sich vorstellen, wie negativ sich eine ausufernde Animation bei komplexen Businessanwendungen auf die Performance auswirken kann. Gerade bei Animationen ist ist daher darauf zu achten, den Spagat zwischen \u201esexy UI\u201c und guter Performance zu schaffen. Grunds\u00e4tzlich gilt ohnehin die Regel, m\u00f6glichst nur dann Animationen einzusetzen, wenn diese f\u00fcr den Nutzer auch einen Mehrwert haben anstatt sie zum reinen Selbstzweck zu machen.<\/p>\n<h3>VisualProfiler<\/h3>\n<p>Das zweite Tool aus der WPF Performance Suite bietet die M\u00f6glichkeit ein einzelnes UI Element im Visual Tree zu ermitteln, welches Leistungsengp\u00e4sse verursacht \u2013 der sprichw\u00f6rtliche \u201eFlaschenhals\u201c. Durch eine Baumansicht in der Benutzeroberfl\u00e4che des VisualProfiler kann so der komplette Visual Tree der Applikation analysiert werden. Ermittelt VisualProfiler ein Element, welches sich negativ auf die Performance auswirkt, so wird dieses in verschiedenen Rotschattierungen hervorgehoben. Je dunkler das Rot dargestellt wird, desto gr\u00f6\u00dfer ist der relative Ressourcenverbrauch eines Objektes.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VisualTree2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2640\" title=\"Visual Tree Beispiel\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VisualTree2.png\" alt=\"\" width=\"605\" height=\"346\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VisualTree2.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VisualTree2-300x171.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>Das Beispiel zeigt die Analysedaten aus einem <em>StackPanel<\/em> welches im <em>ItemsPanelTemplate<\/em> einer <em>ListBox<\/em> verwendet wird. Interessant ist hier auch der rechte Bereich, welcher Informationen bez\u00fcglich der CPU Auslastung der Anwendung bereitstellt. Visuell werden die Daten als Diagramm veranschaulicht. So k\u00f6nnen maximale Auslastungen in den drei wichtigsten Bereichen Layout, Rendering und Animation schnell erkannt werden.<\/p>\n<p>Detaillierte Informationen zur <a href=\"http:\/\/msdn.microsoft.com\/de-de\/library\/aa969767.aspx\">WPF Performance Suite<\/a> gibt es direkt bei Microsoft:<\/p>\n<h3>DotTrace<\/h3>\n<p>Ein weiteres n\u00fctzliches Tool, um Performanceprobleme aufzusp\u00fcren, ist das von der Firma \u201eJetBrains\u201c entwickelte Tool DotTrace. DotTrace bietet neben Performance Analysen auch die M\u00f6glichkeit den Speicherverbrauch einer Anwendung zu untersuchen. Dieser spielt bez\u00fcglich der Geschwindigkeit einer Anwendung eine Rolle, da ein hoher Speicherverbrauch oftmals darauf schlie\u00dfen l\u00e4sst, dass viele und schwergewichtige Objekte erzeugt werden. Da jede Erzeugung eines Objektes Zeit kostet, entstehen dadurch auch Performanceverluste. Im Gegensatz zu der WPF Performance Suite, welche gut zum Analysieren von Performance Aspekten auf View Ebene geeignet ist, ist dieser Profiler eher f\u00fcr die Analyse von C# Code geeignet. Das Tool zeigt in der Analyse unter anderem den kompletten \u201eCall Stack\u201c der Anwendung mit Angaben der Anzahl der Aufrufe und der daf\u00fcr ben\u00f6tigten Zeit. So kann beispielsweise bei einer gro\u00dfen Anzahl von Aufrufen eines Konstruktors davon ausgegangen werden, dass evtl. eine Virtualisierung in einer Liste nicht korrekt arbeitet. Um dieses Tool effizient nutzen zu k\u00f6nnen, sollte aber ein Grundwissen \u00fcber die verwendeten C# Klassen der Anwendung vorhanden sein.<\/p>\n<p>Weitere Informationen finden Sie bei <a href=\"http:\/\/www.jetbrains.com\/profiler\/\">JetBrains<\/a>.<\/p>\n<p><!--more--><\/p>\n<h2>Welche Faustregeln sollte ich nun als UI Design Engineer beachten um meine Anwendung performant zu gestalten?<\/h2>\n<p>Wie bereits gesehen gibt es eine Vielzahl von potentiellen Performanceproblemen. Aber die meisten Probleme stellen gar keine so gro\u00dfe H\u00fcrde da, wie man auf den ersten Blick meinen sollte. Warum viele Probleme recht einfach zu l\u00f6sen sind, werden Sie in diesem Abschnitt erfahren. Ausserdem hat Microsoft seit dem .NET Framework 4.0 schon einige Verbesserungen bez\u00fcglich der Performance vorgenommen. Gerade im Hinblick auf die Verwendung von Pixel Shadern und das Rendering von komplex gestylten Elementen wurden Optimierungen eingef\u00fchrt.<\/p>\n<h3>Effekte<\/h3>\n<p>So k\u00f6nnen seither <strong>Effekte<\/strong> geschrieben werden, welche Pixel Shader (PS) in der Version 3.0 nutzen. Das PS 3.0-Shadermodell ist im Gegensatz zur alten Version dramatisch verbessert worden. Es bietet noch mehr Effekte, welche auf unterst\u00fctzte Hardware zur\u00fcckgreifen, was im Hinblick auf die Performance einen gro\u00dfen Vorteil gegen\u00fcber Effekten, welche Softwaregerendert sind, bietet, da diese in der Grafikkarte abgewickelt werden und der Prozessor sich um seine eigentlichen Aufgaben k\u00fcmmern kann. Trotzdem sollte man als UI Design Engineer immer abw\u00e4gen, ob ein visueller Effekt nicht auch einfacher realisiert werden kann. Ein ressourcenlastiger Dropshadow-Effekt um einen Schatten unter einem Label zu visualisieren, kann auch vermieden werden, indem ein zweites Label in anderer Farbe, welches um einen Pixel verschoben ist verwendet wird. Gerade solche Vereinfachungen haben sich in der Praxis bew\u00e4hrt und sollten daher beim Styling einer Anwendung in Erw\u00e4gung gezogen werden.<\/p>\n<h3>Caching<\/h3>\n<p>Eine weitere Unterst\u00fctzung zur Performancesteigerung kann die Klasse <strong>BitmapCache<\/strong> sein. Durch diese k\u00f6nnen visuell komplexe UI Elemente in WPF als Bitmap zwischengespeichert werden. Der <em>BitmapCache<\/em> kann durch das <em>CacheMode<\/em> Property f\u00fcr ein beliebiges UI Element gesetzt werden.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheCodeSnippet1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2641\" title=\"Bitmap Cache Beispiel\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheCodeSnippet1.png\" alt=\"\" width=\"605\" height=\"77\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheCodeSnippet1.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheCodeSnippet1-300x38.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>Dies f\u00fchrt gerade bei Animationen zu einer signifikanten Reduzierung des Rendering Aufwandes. Trotzdem ist das Element weiterhin komplett interaktionsf\u00e4hig und erh\u00e4lt alle WPF Events, wie z.B. Mausklicks oder Tastatureingaben. Dadurch wird aber der Cache auch revalidiert, was zu einem Neuzeichnen f\u00fchrt. Auch eine Skalierung des Objektes ist m\u00f6glich. Durch das <em>RenderAtScale<\/em> Property kann angegeben werden, mit welchem Skalierungsfaktor das Bild zu Beginn zwischengespeichert werden soll. Im Standard wird das Element in seiner urspr\u00fcnglichen Gr\u00f6\u00dfe (also bei 96 ppi) als Bitmap gespeichert. Hierbei ist aber darauf zu achten, dass keine visuellen Nebeneffekte entstehen. Denn gerade bei Elementen mit Texten ist davon abzuraten den BitmapCache auf das gesamte Element inklusive der Text Repr\u00e4sentation anzuwenden, da die Qualit\u00e4t des Textes sehr schnell darunter leidet. Zudem sollte man nur eine vertretbare Anzahl von UI Elementen wirklich zwischenspeichern, da man sonst wiederum Gefahr l\u00e4uft in Arbeitsspeicherprobleme zu rennen. Ein wesentlicher Punkt bei der Verwendung des BitmapCache ist das Layout des verwendeten Elementes. Denn durch eine Ver\u00e4nderung des Layouts wird das Bitmap neu gespeichert, was eine \u201eteure\u201c Operation darstellt. Es sollte dementsprechend darauf geachtet werden, dass sich das Layout des Elementes \u00fcber die Laufzeit des Programms hinweg so wenig wie m\u00f6glich, im besten Falle gar nicht \u00e4ndert. Eine <em>RenderTransform<\/em> Operation kann hier im Gegensatz zur <em>LayoutTransform<\/em> bedenkenlos verwendet werden, da diese erst zum Zeitpunkt des Renderings ausgef\u00fchrt wird.<br \/>\nMicrosoft bietet eine weitere M\u00f6glichkeit Elemente zwischenzuspeichern. Die Klasse <strong>BitmapCacheBrush<\/strong> kann ein zuvor zwischengespeichertes BitmapCache Element als BitmapCacheBrush definieren, welcher beispielsweise als Background auf mehreren Elementen angewandt werden kann.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheBrushCodeSnippet1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2642\" title=\"Bitmap Cache Brush Beispiel\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheBrushCodeSnippet1.png\" alt=\"\" width=\"605\" height=\"201\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheBrushCodeSnippet1.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheBrushCodeSnippet1-300x99.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>Durch die Wiederverwendung des zwischengespeicherten Elementes und der damit verbundenen Minimierung des Zeichenaufwandes kann so eine gute Performance erzielt werden.<br \/>\nDurch die Verwendung dieser Klassen kann die CPU Auslastung bez\u00fcglich des Rendering in bestimmten F\u00e4llen um das bis zu Dreifache verringert werden.<\/p>\n<h3>Listen<\/h3>\n<p>In vielen F\u00e4llen kommt es in einer Anwendung genau dort zu Performanceengp\u00e4ssen, wo viele Daten visualisiert werden. Die drei am h\u00e4ufigsten verwendeten Controls zur Darstellung von Daten auf dem User Interface sind in der WPF <em>ListBox<\/em>, <em>ItemsControl<\/em> und <em>DataGrid<\/em>. Hierbei spielt vor allem das Thema <strong>Scrolling Performance<\/strong> eine gro\u00dfe Rolle. Die WPF bietet hier durch die Klasse <em>VirtualizingPanel<\/em> eine M\u00f6glichkeit, Elemente einer Liste erst dann zu instanziieren, wenn diese auch wirklich sichtbar werden. Dies f\u00fchrt zu einer beachtlichen Verbesserung des Laufzeitverhaltens, gerade im Hinblick auf die Ladezeit einer Liste. \u00dcberschreibt man also das <em>ItemsPanel<\/em> einer Liste, sollte darauf geachtet werden, dass man hier ein <em>VirtualizingPanel<\/em> verwendet. Standardm\u00e4\u00dfig wird hier immer ein <em>VirtualizingStackPanel<\/em> verwendet.<br \/>\nZus\u00e4tzlich kann durch das <em>VirtualizationMode<\/em> Property des <em>VirtualizingPanel<\/em> eine gute Verbesserung bez\u00fcglich der Scrolling Performance erzielt werden. Im WPF Standard werden die Elemente in der Liste nachdem diese aus der View verschwinden verworfen und bei jedem Erscheinen wieder neu erstellt. Nicht immer ist der Standard die beste L\u00f6sung. In der Praxis, haben wir festgestellt, dass oft immer wieder die gleichen Elementcontainer in einer Liste verwendet werden. Ist dies gew\u00e4hrleistet, kann ein st\u00e4ndiges Wegwerfen und Neuerstellen evtl. ausgeschaltet werden. Setzt man also das <em>VirtualizationMode<\/em> Property auf \u201eRecycling\u201c, werden die Elementcontainer wiederverwendet (recycelt)<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VirtualizingPanel1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2643\" title=\"Virtualizing Panel Beispiel\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VirtualizingPanel1.png\" alt=\"\" width=\"605\" height=\"38\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VirtualizingPanel1.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VirtualizingPanel1-300x18.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>Dadurch kann ich mit nur einem Property schon eine Verbesserung von bis zu 40% bez\u00fcglich der Scrolling Performance erzielen.<\/p>\n<p>Zu Schwierigkeiten kann es kommen, wenn man das Scrollen in Listen pixelweise, statt elementweise realisieren will. Eine einfache M\u00f6glichkeit besteht darin, das Property <em>CanContentScroll<\/em> auf \u201eFalse\u201c zu setzen. Dadurch f\u00fchlt sich das Scrollen zwar sehr fl\u00fcssig an, f\u00fchrt aber auch zu einem unerw\u00fcnschten Seiteneffekt. Der gro\u00dfe Nachteil bei diesem Property ist, dass die Virtualisierung einfach deaktiviert wird, auch wenn ein <em>VirtualizingPanel<\/em> im <em>ItemsPanel<\/em> der Liste verwendet wird. Dementsprechend ist gerade im Hinblick auf das Styling von Listen Vorsicht geboten.<\/p>\n<h3>Resource Dictionaries<\/h3>\n<p>Ein sehr wichtiges Thema in gro\u00dfen Softwareprojekten ist immer wieder das Verwalten der Resourcen in den <strong>ResourceDictionaries<\/strong>. Eine Besonderheit in WPF, ob nun immer w\u00fcnschenswert oder nicht, ist es, das Merged Dictionaries immer wieder neu instanziiert werden, wenn diese beispielsweise in einer View via <em>MergedDictionary<\/em> inkludiert wurden. Ber\u00fccksichtigt man nun, dass Frameworks wie Prism, bei denen Views dynamisch aus mehreren Views zusammengesetzt und geladen werden, immer st\u00e4rker genutzt werden, wird klar dass die Organisation von ResourceDictionaries gut durchdacht sein sollte. Um ein besseres Verst\u00e4ndnis f\u00fcr entstehenden Probelematiken zu bekommen, dient hier diese Grafik einer View, wie sie in einem realen Softwareprojekt durchaus auftreten k\u00f6nnte.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/ResourcesDiagram6.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2658\" title=\"Resourcen Diagramm\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/ResourcesDiagram6.png\" alt=\"\" width=\"559\" height=\"412\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/ResourcesDiagram6.png 931w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/ResourcesDiagram6-300x221.png 300w\" sizes=\"auto, (max-width: 559px) 100vw, 559px\" \/><\/a><\/p>\n<p>In diesem einfachen Beispiel ist durch die schlechte ResourceDictionary Struktur, BasicResources.xaml dreimal und BrushResources.xaml zweimal inkludiert. W\u00e4re in der App.xaml nur ButtonResources.xaml inkludiert, w\u00fcrden weiterhin alle Ressourcen zur Verf\u00fcgung stehen. Der Speicher w\u00fcrde aber im Gegensatz zu der in der Grafik gew\u00e4hlten Variante nicht durch die f\u00fcnf gedoppelten ResourceDictionaries gef\u00fcllt werden.<br \/>\nDurch eine h\u00e4ufige Dopplung von ResourceDictionaries in einer Anwendung l\u00e4uft man somit als UI Design Engineer also Gefahr, dass das User Interface einen enormen Speicherverbrauch in der Anwendung verursacht.<\/p>\n<p>Da dies ein bekanntes \u201eProblem\u201c in WPF ist, wird man nat\u00fcrlich schon nach kurzem Googlen mit Verbesserungsvorschl\u00e4gen \u00fcberh\u00e4uft. Hierbei sollte allerdings beachtet werden, dass nicht jeder als Antwort markierte Beitrag in einem Forum auch wirklich ohne Weiteres verwendet werden kann.<\/p>\n<p>Ein auf den ersten Blick vielversprechender L\u00f6sungsansatz bietet hier ein sogenanntes <em>SharedResourceDictionary<\/em>. Dabei wird jedes ResourceDictionary jeweils nur ein einziges Mal instanziiert und ab dann gemeinsam verwendet. Ein gro\u00dfer Nachteil hierbei ist, dass durch jedes ResourceDictionary eine Referenz auf den Owner gehalten wird. Bei dem von ResourceDictionary abgeleiteten SharedResourceDictionary f\u00fchrt dies dazu, dass der Speicher, den eine View belegt nicht mehr durch den Garbagecollector freigegeben werden kann. Dadurch k\u00f6nnen enorme Speicherl\u00f6cher entstehen, welche nicht ohne weiteres geschlossen werden k\u00f6nnen.<\/p>\n<p>Allgemein sollte darauf geachtet werden, dass Ressourcen, welche an mehreren Stellen verwendet werden, einmal global \u00fcber die App.xaml eingebunden werden.<br \/>\nAuch die Art, wie Ressourcen im XAML Code referenziert werden, spielt bez\u00fcglich des Laufzeitverhaltens eine Rolle. Die WPF bietet uns hierf\u00fcr zwei Vorgehen an.<\/p>\n<p><strong>1)<\/strong> Verwendet man, wie es uns Expression Blend vorschl\u00e4gt, <strong>DynamicResources<\/strong>, so hat dies folgende Auswirkungen: Zum einen k\u00f6nnen Ressourcen w\u00e4hrend der Laufzeit ausgetauscht werden. Dies f\u00fchrt dazu, dass beispielsweise bei jeder Initilialisierung einer View die Ressourcen neu geladen werden. Folglich kann das \u00d6ffnen einer View eine gewisse Ladezeit zur Folge haben, wenn DynamicResources verwendet werden.<\/p>\n<p><strong>2)<\/strong> Nutzt man hingegen <strong>StaticResources<\/strong>, werden die Ressourcen gleich zu Beginn, beim Start der Anwendung alle geladen. Dementsprechend hat man nach dem Start der Anwendung keine weiteren Ladezeiten f\u00fcr Ressourcen zu verbuchen. Doch StaticResources k\u00f6nnen umgekehrt die Startzeit einer Applikation erheblich erh\u00f6hen. An dieser Stelle sollte man sich idealerweise schon zu Beginn der Entwicklung entscheiden, ob eher eine l\u00e4ngere Startzeit der Gesamtapplikation in Kauf genommen wird, oder mit einer gr\u00f6\u00dferen Ladezeit w\u00e4hrend die Applikation l\u00e4uft gelebt werden soll.<\/p>\n<h3>Trigger vs. Visual States<\/h3>\n<p>Oft habe ich mir, als die Entwicklung im WPF Umfeld noch relativ neu f\u00fcr mich war, die Frage gestellt, warum in den Standard WPF Templates immer wieder Zust\u00e4nde, wie z.B. Pressed bei einem Button, mit Hilfe von <strong>Triggern<\/strong> visualisiert werden, wo es doch in jedem Template eigene <strong>VisualStates<\/strong> mit <em>VisualStateGroups<\/em> gibt. Doch wenn man einmal die Performance von Controls mit Ber\u00fccksichtigt, macht dies durchaus Sinn. Denn jeder Aufruf, um in einen State zu wechseln, welcher wiederum ein <em>Storyboard<\/em> startet und ausf\u00fchrt, kostet Zeit. Dass dies nat\u00fcrlich eine gr\u00f6\u00dfere Dauer zur Folge hat als einfach ein Property in einem Trigger zu setzen, liegt auf der Hand. Es ist also je nachdem, wie ein Zustand visualisiert werden soll, zu vergleichen, mit welchen Mitteln man die Visualisierung erreichen will oder kann.<\/p>\n<p>Zuletzt m\u00f6chte ich Ihnen noch einen recht einfach zu ber\u00fccksichtigenden Ratschlag zur Optimierung der User Interface Performance mit auf den Weg geben. Denn schon beim Definieren eines <strong>Layouts<\/strong> k\u00f6nnen ungl\u00fcckliche Strukturen, welche zu einer gro\u00dfen Anzahl von Elementen im Visual Tree f\u00fchren, zu Performanceverlusten f\u00fchren. So sollte darauf geachtet werden, dass m\u00f6glichst flache Container Hierarchien angelegt werden. Auch der Containertyp sollte nicht nach dem Zufallsprinzip oder aus Gewohnheit gew\u00e4hlt werden. Schwergewichtige <em>ContentControls<\/em> sollten, sofern die M\u00f6glichkeit besteht, nicht als Layout Container verwendet werden. Gerade diese einfache Regel sollte beim Anlegen von Control Templates ber\u00fccksichtigt werden. Denn Templates werden oft wiederverwendet. Weist man beispielsweise 10 Buttons ein Template zu, welches wiederum 10 Elemente beinhaltet, so kommt man schon auf 100 Elemente!<br \/>\n<!--more--><\/p>\n<h2>Fazit<\/h2>\n<p>Wie in diesem Blogartikel dargestellt, kann eine Optimierung bez\u00fcglich der Performance einer .NET Applikation nicht nur von einem Bereich eines Entwicklungsteams optimal gew\u00e4hrleistet werden. Vielmehr sollte eine Verbesserung des Laufzeitverhaltens im jeweiligen Fachbereich vorgenommen werden, um ein optimales Ergebnis zu erzielen. Und genau darum geh\u00f6ren Performance Analysen und Optimierungen auch zum Aufgabengebiet eines UI Design Engineers. Zumindest bei Centigrade.<\/p>\n<p><span style=\"font-size: xx-small;\">Microsoft, Windows, Expression Blend und Expression sind Marken oder eingetragene Marken der Microsoft Corporation in den USA und\/oder anderen L\u00e4ndern.<\/span><\/p>\n","protected":false},"author":24,"featured_media":0,"template":"","tags":[42,82,73,34,44],"class_list":["post-2548","blog","type-blog","status-publish","hentry","tag-blend","tag-kollaboration","tag-user-interface-entwicklung","tag-user-interface-tools","tag-wpf"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.centigrade.de\/de\/wp-json\/wp\/v2\/blog\/2548","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.centigrade.de\/de\/wp-json\/wp\/v2\/blog"}],"about":[{"href":"https:\/\/www.centigrade.de\/de\/wp-json\/wp\/v2\/types\/blog"}],"author":[{"embeddable":true,"href":"https:\/\/www.centigrade.de\/de\/wp-json\/wp\/v2\/users\/24"}],"version-history":[{"count":1,"href":"https:\/\/www.centigrade.de\/de\/wp-json\/wp\/v2\/blog\/2548\/revisions"}],"predecessor-version":[{"id":11275,"href":"https:\/\/www.centigrade.de\/de\/wp-json\/wp\/v2\/blog\/2548\/revisions\/11275"}],"wp:attachment":[{"href":"https:\/\/www.centigrade.de\/de\/wp-json\/wp\/v2\/media?parent=2548"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.centigrade.de\/de\/wp-json\/wp\/v2\/tags?post=2548"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}