Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Das Analysieren von XAML-Markup zum Erstellen von Objekten im Arbeitsspeicher ist zeitaufwändig für eine komplexe Benutzeroberfläche. Hier sind einige Dinge, die Sie tun können, um die Analyse- und Ladezeit Ihres XAML-Markups und die Speichereffizienz Ihrer WinUI-App zu verbessern.
Beschränken Sie beim Starten der App das XAML-Markup, das nur auf das geladen wird, was Sie für die anfängliche Benutzeroberfläche benötigen. Überprüfen Sie das Markup auf der ersten Seite, einschließlich Seitenressourcen, und vergewissern Sie sich, dass Sie keine zusätzlichen Elemente laden, die nicht sofort benötigt werden. Eine Vielzahl von Quellen kann diese Elemente liefern, etwa Ressourcendateien, Elemente, die anfänglich ausgeblendet sind, und Elemente, die über andere Elemente gezeichnet werden.
Die Optimierung Ihres XAML-Codes für Effizienz erfordert Kompromisse; es gibt nicht immer eine einzige Lösung für jede Situation. Hier befassen wir uns mit einigen häufig auftretenden Problemen und stellen Richtlinien bereit, mit denen Sie die richtigen Kompromisse für Ihre WinUI-App erzielen können.
Minimieren der Elementanzahl
Obwohl die XAML-Plattform in der Lage ist, eine große Anzahl von Elementen anzuzeigen, können Sie das Layout ihrer App beschleunigen und schneller rendern, indem Sie die kleinste Anzahl von Elementen verwenden, die erforderlich sind, um die gewünschten visuellen Elemente zu erzielen.
Die Auswahlmöglichkeiten, die Sie beim Layout der UI-Steuerelemente treffen, wirken sich auf die Anzahl der UI-Elemente aus, die beim Starten der App erstellt werden. Ausführlichere Informationen zum Optimieren des Layouts finden Sie unter Optimieren des XAML-Layouts.
Die Elementanzahl ist in Datenvorlagen äußerst wichtig, da jedes Element für jedes Datenelement erneut erstellt wird. Informationen zum Reduzieren der Elementanzahl in einer Liste oder einem Raster finden Sie unter "Elementreduzierung pro Element " im Artikel " Optimieren von ListView" und "GridView" für WinUI .
Hier sehen wir uns einige andere Möglichkeiten an, wie Sie die Anzahl der Elemente verringern können, die Ihre App beim Start laden muss.
Zurückstellen der Elementerstellung
Wenn Ihr XAML-Markup Elemente enthält, die nicht sofort angezeigt werden, können Sie das Laden dieser Elemente zurückstellen, bis sie angezeigt werden. Sie können z. B. die Erstellung von nicht sichtbaren Inhalten wie einer sekundären Registerkarte in einer registerkartenähnlichen Benutzeroberfläche verzögern. Alternativ können Sie Elemente in einer Rasteransicht standardmäßig anzeigen, aber dem Benutzer eine Option zum Anzeigen der Daten in einer Liste bereitstellen. Sie können das Laden der Liste verzögern, bis sie benötigt wird.
Verwenden Sie das x:Load-Attribut anstelle der Visibility-Eigenschaft , um zu steuern, wann ein Element angezeigt wird. Wenn die Sichtbarkeit eines Elements auf "Collapsed" festgelegt ist, wird es während des Renderdurchlaufs übersprungen, aber Sie zahlen weiterhin die Kosten der Objektinstanz im Arbeitsspeicher. Wenn Sie stattdessen "x:Load" verwenden, erstellt das Framework die Objektinstanz erst, wenn sie benötigt wird, sodass die Speicherkosten noch niedriger sind. Der Nachteil ist, dass Sie einen kleinen Arbeitsspeicheraufwand (ca. 600 Bytes) bezahlen, wenn die Benutzeroberfläche nicht geladen wird.
Hinweis
Im Windows App SDK ist "x:Load " das empfohlene Muster für das verzögerte Laden von XAML-Inhalten, das nicht sofort benötigt wird.
Die folgenden Beispiele zeigen den Unterschied bei der Elementanzahl und der Speichernutzung, wenn verschiedene Techniken zum Ausblenden von UI-Elementen verwendet werden. Eine ListView und eine GridView mit identischen Elementen werden im Stammraster einer Seite platziert. Die ListView ist nicht sichtbar, aber die GridView wird angezeigt. Der XAML-Code in jedem dieser Beispiele erzeugt dieselbe Benutzeroberfläche auf dem Bildschirm. Verwenden Sie Tools für Profilerstellung und Leistung , um die Elementanzahl und die Speichernutzung in Ihrer App zu überprüfen.
Option 1 – Ineffizient
Hier wird die ListView geladen, ist aber nicht sichtbar, weil ihr Width0 ist. Die ListView und die einzelnen untergeordneten Elemente werden im visuellen Baum erstellt und in den Speicher geladen.
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="List1" Width="0">
<ListViewItem>Item 1</ListViewItem>
<ListViewItem>Item 2</ListViewItem>
<ListViewItem>Item 3</ListViewItem>
<ListViewItem>Item 4</ListViewItem>
<ListViewItem>Item 5</ListViewItem>
<ListViewItem>Item 6</ListViewItem>
<ListViewItem>Item 7</ListViewItem>
<ListViewItem>Item 8</ListViewItem>
<ListViewItem>Item 9</ListViewItem>
<ListViewItem>Item 10</ListViewItem>
</ListView>
<GridView x:Name="Grid1">
<GridViewItem>Item 1</GridViewItem>
<GridViewItem>Item 2</GridViewItem>
<GridViewItem>Item 3</GridViewItem>
<GridViewItem>Item 4</GridViewItem>
<GridViewItem>Item 5</GridViewItem>
<GridViewItem>Item 6</GridViewItem>
<GridViewItem>Item 7</GridViewItem>
<GridViewItem>Item 8</GridViewItem>
<GridViewItem>Item 9</GridViewItem>
<GridViewItem>Item 10</GridViewItem>
</GridView>
</Grid>
Visueller Live-Baum mit geladener ListView. Die Gesamtanzahl der Elemente für die Seite beträgt 89.
ListView und die untergeordneten Elemente werden in den Arbeitsspeicher geladen.
Option 2 - Besser
Hier wird die ListView Visibility auf Collapsed gesetzt (der andere XAML-Code ist identisch mit dem Original). Die ListView wird im visuellen Baum erstellt, die untergeordneten Elemente jedoch nicht. Sie werden jedoch weiterhin in den Arbeitsspeicher geladen, sodass die Speichernutzung mit dem vorherigen Beispiel identisch ist.
<ListView x:Name="List1" Visibility="Collapsed">
Visuelle Live-Struktur mit eingeklappter ListView. Die Gesamtanzahl der Elemente für die Seite beträgt 46.
ListView und die untergeordneten Elemente werden in den Arbeitsspeicher geladen.
Option 3 – effizienteste
Hier ist das "x:Load"-Attribut auf "False" festgelegt (der andere XAML ist identisch mit dem Original). Die ListView wird nicht im visuellen Baum erstellt oder beim Start der Anwendung in den Arbeitsspeicher geladen.
<ListView x:Name="List1" Visibility="Collapsed" x:Load="False">
Visualisierung des Live-Baums, während die ListView nicht geladen ist. Die Gesamtanzahl der Elemente für die Seite beträgt 45.
ListView und die untergeordneten Elemente werden nicht in den Arbeitsspeicher geladen.
Hinweis
Die Elementanzahl und die Speichernutzung in diesen Beispielen sind sehr klein und werden nur gezeigt, um das Konzept zu veranschaulichen. In diesen Beispielen ist der Mehraufwand für die Verwendung von "x:Load" größer als die Speichereinsparungen, sodass die App nicht profitieren würde. Mithilfe von Profilerstellungstools in Ihrer App können Sie ermitteln, ob das verzögerte Laden hilfreich ist.
Verwenden von Layout-Panel-Eigenschaften
Layoutpanels verfügen über eine Hintergrundeigenschaft , sodass kein Rechteck vor einem Panel platziert werden muss, um es zu färben.
Ineffizient
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid>
<Rectangle Fill="Black"/>
</Grid>
Effizient
<Grid Background="Black"/>
Layoutpanels verfügen auch über integrierte Rahmeneigenschaften, sodass Sie kein Rahmenelement um einen Layoutbereich platzieren müssen. Weitere Informationen und Beispiele finden Sie unter Optimieren des XAML-Layouts .
Verwenden von Bildern anstelle von vektorbasierten Elementen
Wenn Sie dasselbe vektorbasierte Element ausreichend wiederverwenden, wird es effizienter, stattdessen ein Image-Element zu verwenden. Vektorbasierte Elemente können teurer sein, da die CPU jedes einzelne Element separat erstellen muss. Die Bilddatei muss nur einmal decodiert werden.
Optimieren von Ressourcen und Ressourcenwörterbüchern
Normalerweise verwenden Sie Ressourcenwörterbücher , um Ressourcen auf einer etwas globalen Ebene zu speichern, auf die Sie an mehreren Stellen in Ihrer App verweisen möchten. Beispielsweise Stile, Pinsel, Vorlagen usw.
Im Allgemeinen ist ResourceDictionary darauf optimiert, Ressourcen erst dann zu instanziieren, wenn sie angefordert werden. Es gibt jedoch Situationen, die Sie vermeiden sollten, damit Ressourcen nicht unnötig instanziiert werden.
Ressourcen mit x:Name
Verwenden Sie das x:Key-Attribut , um auf Ihre Ressourcen zu verweisen. Jede Ressource mit dem x:Name-Attribut profitiert nicht von der Plattformoptimierung; Stattdessen wird sie instanziiert, sobald das ResourceDictionary erstellt wird. Dies geschieht, da x:Name der Plattform angibt, dass Ihre App Feldzugriff auf diese Ressource benötigt, sodass die Plattform einen Verweis darauf erstellen muss.
ResourceDictionary in einem UserControl
Ein in einem UserControl-Objekt definiertes ResourceDictionary führt zu einer Strafe. Die Plattform erstellt eine Kopie eines solchen ResourceDictionary für jede Instanz von UserControl. Wenn Sie über ein UserControl-Objekt verfügen, das viel verwendet wird, verschieben Sie das ResourceDictionary aus dem UserControl-Element, und legen Sie es auf Seitenebene ab.
Ressourcen- und ResourceDictionary-Bereich
Wenn eine Seite auf ein Benutzersteuerelement oder eine Ressource verweist, die in einer anderen Datei definiert ist, analysiert das Framework diese Datei ebenfalls.
Da InitialPage.xaml eine Ressource aus ExampleResourceDictionary.xaml verwendet, muss das gesamte BeispielResourceDictionary.xaml beim Start analysiert werden.
InitialPage.xaml
<Page x:Class="ExampleNamespace.InitialPage" ...>
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ExampleResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<Grid>
<TextBox Foreground="{StaticResource TextBrush}"/>
</Grid>
</Page>
ExampleResourceDictionary.xaml
<ResourceDictionary>
<SolidColorBrush x:Key="TextBrush" Color="#FF3F42CC"/>
<!--This ResourceDictionary contains many other resources that
are used in the app, but are not needed during startup.-->
</ResourceDictionary>
Wenn Sie eine Ressource auf vielen Seiten in der gesamten App verwenden, empfiehlt es sich, sie in "App.xaml " zu speichern und Duplizierungen zu vermeiden. App.xaml wird jedoch beim Starten der App analysiert. Daher sollte jede Ressource, die nur auf einer Seite verwendet wird, in die lokalen Ressourcen der Seite eingefügt werden, es sei denn, diese Seite ist die erste Seite. In diesem Beispiel wird "App.xaml " mit Ressourcen gezeigt, die nur von einer Seite verwendet werden, die nicht die erste Seite ist. Dadurch wird die Startzeit unnötig erhöht.
App.xaml
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Application ...>
<Application.Resources>
<SolidColorBrush x:Key="DefaultAppTextBrush" Color="#FF3F42CC"/>
<SolidColorBrush x:Key="InitialPageTextBrush" Color="#FF3F42CC"/>
<SolidColorBrush x:Key="SecondPageTextBrush" Color="#FF3F42CC"/>
<SolidColorBrush x:Key="ThirdPageTextBrush" Color="#FF3F42CC"/>
</Application.Resources>
</Application>
InitialPage.xaml
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Page x:Class="ExampleNamespace.InitialPage" ...>
<StackPanel>
<TextBox Foreground="{StaticResource InitialPageTextBrush}"/>
</StackPanel>
</Page>
SecondPage.xaml
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Page x:Class="ExampleNamespace.SecondPage" ...>
<StackPanel>
<Button Content="Submit" Foreground="{StaticResource SecondPageTextBrush}"/>
</StackPanel>
</Page>
Um dieses Beispiel effizienter zu gestalten, wechseln Sie SecondPageTextBrush zu SecondPage.xaml , und wechseln Sie ThirdPageTextBrush zu ThirdPage.xaml.
InitialPageTextBrush kann in "App.xaml" verbleiben, da Anwendungsressourcen bei app-Start in jedem Fall analysiert werden müssen.
Konsolidieren Sie mehrere Pinsel, die gleich aussehen, zu einer Ressource
Die XAML-Plattform versucht, häufig verwendete Objekte zwischenzuspeichern, damit sie so oft wie möglich wiederverwendet werden können. Xaml kann jedoch nicht leicht erkennen, ob ein in einem Teil von Markup deklarierter Pinsel mit einem in einem anderen deklarierten Pinsel identisch ist. Im folgenden Beispiel wird SolidColorBrush verwendet, um zu veranschaulichen, aber der Fall ist mit GradientBrush wahrscheinlicher und wichtiger. Überprüfen Sie auch, ob Pinsel vordefinierte Farben verwenden; Beispielsweise "Orange" und "#FFFFA500" sind die gleiche Farbe.
Ineffizient
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Page ... >
<StackPanel>
<TextBlock>
<TextBlock.Foreground>
<SolidColorBrush Color="#FFFFA500"/>
</TextBlock.Foreground>
</TextBlock>
<Button Content="Submit">
<Button.Foreground>
<SolidColorBrush Color="#FFFFA500"/>
</Button.Foreground>
</Button>
</StackPanel>
</Page>
Um die Duplizierung zu beheben, definieren Sie den Pinsel als Ressource. Wenn Steuerelemente auf anderen Seiten denselben Pinsel verwenden, verschieben Sie ihn in App.xaml.
Effizient
<Page ... >
<Page.Resources>
<SolidColorBrush x:Key="BrandBrush" Color="#FFFFA500"/>
</Page.Resources>
<StackPanel>
<TextBlock Foreground="{StaticResource BrandBrush}" />
<Button Content="Submit" Foreground="{StaticResource BrandBrush}" />
</StackPanel>
</Page>
Vermeiden von Überzeichnung
Überzeichnung erfolgt, wenn mehrere Objekte in denselben Bildschirmpixeln gezeichnet werden. Beachten Sie, dass es manchmal einen Kompromiss zwischen dieser Anleitung und dem Wunsch gibt, die Elementanzahl zu minimieren.
Verwenden Sie DebugSettings.IsOverdrawHeatMapEnabled als visuelle Diagnose. Möglicherweise finden Sie Objekte, die gezeichnet werden, von denen Sie nicht wussten, dass sie sich in der Szene befanden.
Transparente oder ausgeblendete Elemente
Wenn ein Element nicht sichtbar ist, da es transparent oder hinter anderen Elementen verborgen ist und nicht zum Layout beiträgt, löschen Sie es. Wenn das Element nicht im anfänglichen visuellen Zustand sichtbar ist, aber in anderen visuellen Zuständen sichtbar ist, verwenden Sie "x:Load", um den Zustand zu steuern oder die Sichtbarkeit für das Element selbst auf "Collapsed " festzulegen und den Wert in " Visible " in den entsprechenden Zuständen zu ändern. Es gibt Ausnahmen von dieser Heuristik: Im Allgemeinen wird der Wert, den eine Eigenschaft in den meisten visuellen Zuständen hat, am besten lokal für das Element festgelegt.
Zusammengesetzte Elemente
Verwenden Sie ein zusammengesetztes Element, anstatt mehrere Elemente zu überschichten, um einen Effekt zu erzeugen. In diesem Beispiel ist das Ergebnis eine zweizehnige Form, bei der die obere Hälfte vom Hintergrund des Rasters schwarz ist und die untere Hälfte grau von der halbtransparenten weißen Rechteck-Alpha-Blendung über dem schwarzen Hintergrund des Rasters ist. Hier werden 150% der zum Erreichen des Ergebnisses erforderlichen Pixel gefüllt.
Ineffizient
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="1" Fill="White" Opacity=".5"/>
</Grid>
Effizient
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Fill="Black"/>
<Rectangle Grid.Row="1" Fill="#FF7F7F7F"/>
</Grid>
LayoutPanels
Ein Layoutpanel kann zwei Zwecke haben: zum Einfärben eines Bereichs und zum Layout untergeordneter Elemente. Wenn ein Element weiter hinten in der Z-Ordnung bereits einen Bereich einfärbt, muss ein Layout-Panel an der Vorderseite diesen Bereich nicht zeichnen. Stattdessen kann es sich darauf konzentrieren, seine untergeordneten Elemente anzupassen. Hier finden Sie ein Beispiel dafür.
Ineffizient
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<GridView Background="Blue">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Background="Blue"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Effizient
<GridView Background="Blue">
<GridView.ItemTemplate>
<DataTemplate>
<Grid/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Wenn das Raster treffertestbar sein muss, legen Sie einen Hintergrundwert Transparent dafür fest.
Ränder
Verwenden Sie ein Border-Element , um einen Rahmen um ein Objekt zu zeichnen. In diesem Beispiel wird ein Raster als beschiebbarer Rahmen um ein TextBox-Objekt verwendet. Aber alle Pixel in der mittleren Zelle werden überschrieben.
Ineffizient
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid Background="Blue" Width="300" Height="45">
<Grid.RowDefinitions>
<RowDefinition Height="5"/>
<RowDefinition/>
<RowDefinition Height="5"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5"/>
<ColumnDefinition/>
<ColumnDefinition Width="5"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Row="1" Grid.Column="1"></TextBox>
</Grid>
Effizient
<Border BorderBrush="Blue" BorderThickness="5" Width="300" Height="45">
<TextBox/>
</Border>
Ränder
Achten Sie auf Ränder. Zwei benachbarte Elemente überlappen sich möglicherweise versehentlich, wenn sich negative Ränder in die Rendergrenzen eines anderen Elements erstrecken und eine Überzeichnung verursachen.
Zwischenspeichern statischer Inhalte
Eine weitere Ursache für Überzeichnungen ist eine Form, die aus vielen sich überschneidenden Elementen besteht. Wenn Sie CacheMode auf BitmapCache für das UIElement festlegen, das die zusammengesetzte Form enthält, rendert die Plattform das Element einmal als Bitmap und nutzt diese Bitmap in jedem Frame anstelle des Überzeichnens.
Ineffizient
<Canvas Background="White">
<Ellipse Height="40" Width="40" Fill="Blue"/>
<Ellipse Canvas.Left="21" Height="40" Width="40" Fill="Blue"/>
<Ellipse Canvas.Top="13" Canvas.Left="10" Height="40" Width="40" Fill="Blue"/>
</Canvas>
Das obige Bild ist das Ergebnis, aber hier ist eine Karte der übergezeichneten Regionen. Dunkleres Rot gibt höhere Überzeichnungsbeträge an.
Effizient
<Canvas Background="White" CacheMode="BitmapCache">
<Ellipse Height="40" Width="40" Fill="Blue"/>
<Ellipse Canvas.Left="21" Height="40" Width="40" Fill="Blue"/>
<Ellipse Canvas.Top="13" Canvas.Left="10" Height="40" Width="40" Fill="Blue"/>
</Canvas>
Beachten Sie die Verwendung von CacheMode. Verwenden Sie diese Technik nicht, wenn eines der Unterformen animiert ist, da der Bitmapcache wahrscheinlich jeden Frame neu generiert werden muss, was den Zweck zunichtemacht.
Verwenden der kompilierten XAML-Ausgabe
Das Windows App SDK kompiliert XAML als Teil des Builds in eine binäre Darstellung, wodurch textanalysekosten zur Laufzeit vermieden werden. Das kompilierte Format optimiert auch die Lade- und Baumerstellung, um allgemeine XAML-Typen wie visuelle Zustände, Ressourcenwörterbücher und Stile zu verbessern.
Integrierte WinUI-Steuerelemente und Wörterbücher profitieren bereits von dieser Pipeline. Behalten Sie für Ihre eigene WinUI-App die normalen XAML-Kompilierungsschritte aktiviert, sodass die generierte Markupkompilierungsausgabe zur Laufzeit verfügbar ist.
Verwandte Artikel
Windows developer