Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Het parseren van XAML-markeringen om objecten in het geheugen te maken, kost veel tijd voor een complexe gebruikersinterface. Hier volgen enkele dingen die u kunt doen om de parse- en laadtijd van uw XAML-markeringen en de geheugenefficiëntie van uw WinUI-app te verbeteren.
Beperk bij het opstarten van de app de XAML-markeringen die alleen worden geladen tot wat u nodig hebt voor uw eerste gebruikersinterface. Bekijk de markeringen op de eerste pagina, inclusief paginabronnen, en controleer of u geen extra elementen laadt die niet meteen nodig zijn. Deze elementen kunnen afkomstig zijn van verschillende bronnen, zoals bronwoordenlijsten, elementen die in eerste instantie zijn samengevouwen en elementen die zijn geplaatst over andere elementen.
Voor het optimaliseren van uw XAML voor efficiëntie is het noodzakelijk om compromissen te maken; er is niet altijd één oplossing voor elke situatie. Hier kijken we naar enkele veelvoorkomende problemen en bieden we richtlijnen die u kunt gebruiken om de juiste afwegingen te maken voor uw WinUI-app.
Aantal elementen minimaliseren
Hoewel het XAML-platform grote aantallen elementen kan weergeven, kunt u uw app indelen en sneller weergeven door het minste aantal elementen te gebruiken dat nodig is om de gewenste visuals te bereiken.
De keuzes die u maakt in de indeling van uw ui-besturingselementen zijn van invloed op het aantal ui-elementen dat wordt gemaakt wanneer uw app wordt gestart. Zie Uw XAML-indeling optimaliseren voor meer gedetailleerde informatie over het optimaliseren van de indeling.
Het aantal elementen is uiterst belangrijk in gegevenssjablonen omdat elk element opnieuw wordt gemaakt voor elk gegevensitem. Zie Elementreductie per item in het artikel Optimize ListView en GridView voor WinUI voor informatie over het verminderen van het aantal elementen in een lijst of raster.
Hier kijken we naar een aantal andere manieren waarop u het aantal elementen kunt verminderen dat uw app moet laden bij het opstarten.
Het maken van items uitstellen
Als uw XAML-markering elementen bevat die u niet meteen weergeeft, kunt u het laden van deze elementen uitstellen totdat ze worden weergegeven. U kunt bijvoorbeeld het maken van niet-zichtbare inhoud, zoals een secundair tabblad, uitstellen in een tabbladachtige gebruikersinterface. Of u kunt items in een rasterweergave standaard weergeven, maar in plaats daarvan een optie opgeven voor de gebruiker om de gegevens in een lijst weer te geven. U kunt het laden van de lijst vertragen totdat deze nodig is.
Gebruik het kenmerk x:Load in plaats van de eigenschap Zichtbaarheid om te bepalen wanneer een element wordt weergegeven. Wanneer de zichtbaarheid van een element is ingesteld op Collapsed, wordt het overgeslagen tijdens de render-pas, maar betaalt u nog steeds de geheugenkosten van objectinstanties. Wanneer u in plaats daarvan x:Load gebruikt, maakt het framework het objectexemplaar pas aan wanneer het nodig is, zodat het geheugengebruik nog lager is. Het nadeel is dat u een kleine geheugenoverhead (ongeveer 600 bytes) betaalt wanneer de gebruikersinterface niet wordt geladen.
Opmerking
In de Windows App SDK is x:Load het aanbevolen uitgestelde laadpatroon voor XAML-inhoud die niet onmiddellijk nodig is.
In de volgende voorbeelden ziet u het verschil in het aantal elementen en het geheugengebruik wanneer verschillende technieken worden gebruikt om UI-elementen te verbergen. Een ListView en een GridView met identieke items worden in het hoofdraster van een pagina geplaatst. De ListView is niet zichtbaar, maar de GridView wordt weergegeven. De XAML in elk van deze voorbeelden produceert dezelfde gebruikersinterface op het scherm. Gebruik hulpprogramma's voor profilering en prestaties om het aantal elementen en het geheugengebruik in uw app te controleren.
Optie 1: inefficiënt
Hier wordt de ListView geladen, maar is niet zichtbaar omdat het Width is 0. De ListView en elk van de onderliggende elementen worden gemaakt in de visuele boomstructuur en in het geheugen 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>
Live-visuele boom met de ListView geladen. Het totale aantal elementen voor de pagina is 89.
ListView en zijn kinderelementen worden in het geheugen geladen.
Optie 2: beter
Hier is de ListView Visibility ingesteld op Collapsed (de andere XAML is identiek aan het origineel). De ListView wordt gemaakt in de visualstructuur, maar de onderliggende elementen zijn dat niet. Ze worden echter nog steeds in het geheugen geladen, dus het geheugengebruik is identiek aan het vorige voorbeeld.
<ListView x:Name="List1" Visibility="Collapsed">
Live visuele structuur met de ListView samengevouwen. Het totale aantal elementen voor de pagina is 46.
ListView en zijn onderdelen worden in het geheugen geladen.
Een bijgewerkte schermopname van de Managed Memory Test App 1 dot E X E tabel, waarin te zien is dat ListView en de onderliggende items in het geheugen worden geladen.
Optie 3: Meest efficiënt
Hier is in ListView het kenmerk x:Load ingesteld op False (de andere XAML is identiek aan het origineel). De ListView wordt niet aangemaakt in de visuele boom of in het geheugen geladen bij het opstarten.
<ListView x:Name="List1" Visibility="Collapsed" x:Load="False">
Live visuele boom met de ListView niet geladen. Het totale aantal elementen voor de pagina is 45.
ListView en zijn onderdelen worden niet in het geheugen geladen.
Opmerking
Het aantal elementen en het geheugengebruik in deze voorbeelden zijn erg klein en worden alleen weergegeven om het concept te demonstreren. In deze voorbeelden is de overhead van het gebruik van x:Load groter dan de geheugenbesparing, zodat de app geen voordeel zou hebben. U moet profileringshulpprogramma's in uw app gebruiken om te bepalen of uitgestelde laadtijden helpen.
Eigenschappen van het indelingsvenster gebruiken
Lay-outpanelen hebben de eigenschap Achtergrond, dus een Rechthoek voor een paneel plaatsen is niet nodig om deze te kleuren.
Inefficiënt
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid>
<Rectangle Fill="Black"/>
</Grid>
Efficiënte
<Grid Background="Black"/>
Indelingspanelen hebben ook ingebouwde randeigenschappen, dus u hoeft geen randelement rond een indelingspaneel te plaatsen. Zie Uw XAML-indeling optimaliseren voor meer informatie en voorbeelden.
Afbeeldingen gebruiken in plaats van vectorelementen
Als u hetzelfde vectorelement genoeg gebruikt, wordt het efficiënter om in plaats daarvan een afbeeldingselement te gebruiken. Vectorelementen kunnen duurder zijn omdat de CPU elk afzonderlijk element moet maken. Het afbeeldingsbestand hoeft slechts één keer te worden gedecodeerd.
Resources en resourcewoordenlijsten optimaliseren
Doorgaans gebruikt u resourcewoordenlijsten om op een enigszins globaal niveau resources op te slaan waarnaar u op meerdere plaatsen in uw app wilt verwijzen. Bijvoorbeeld stijlen, borstels, sjablonen, enzovoort.
Over het algemeen is ResourceDictionary geoptimaliseerd om te voorkomen dat resources instantiëren totdat ze worden gevraagd. Maar er zijn situaties die u moet vermijden, zodat resources niet onnodig worden geïnstantieerd.
Resources met x:Name
Gebruik het kenmerk x:Key om te verwijzen naar uw resources. Elke resource met het kenmerk x:Name profiteert niet van de platformoptimalisatie; In plaats daarvan wordt deze geïnstantieerd zodra de ResourceDictionary is gemaakt. Dit gebeurt omdat x:Name aangeeft dat uw app veldtoegang tot deze resource nodig heeft, zodat het platform iets moet maken om er een verwijzing naar te bewaren.
ResourceDictionary in een UserControl
Een ResourceDictionary die binnen een UserControl is gedefinieerd, heeft een boete. Het platform maakt een kopie van een dergelijke ResourceDictionary voor elk exemplaar van UserControl. Als u een UserControl hebt die veel wordt gebruikt, verplaatst u de ResourceDictionary uit de UserControl en plaatst u deze op paginaniveau.
Resource- en ResourceDictionary-bereik
Als een pagina verwijst naar een gebruikersbesturingselement of een resource die is gedefinieerd in een ander bestand, parseert het framework dat bestand ook.
Omdat InitialPage.xaml één resource uit ExampleResourceDictionary.xaml gebruikt, moet het hele bestand ExampleResourceDictionary.xaml worden geparseerd bij het opstarten.
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>
Als u een resource op veel pagina's in uw app gebruikt, is het opslaan ervan in App.xaml een goede gewoonte en voorkomt u duplicatie. Maar App.xaml wordt geparseerd bij het opstarten van de app, dus elke resource die wordt gebruikt op slechts één pagina, tenzij die pagina de eerste pagina is, moet worden geplaatst in de lokale bronnen van de pagina. In dit voorbeeld laat App.xaml zien dat het resources bevat die worden gebruikt door slechts één pagina die niet de eerste pagina is. Dit verhoogt onnodig de opstarttijd.
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>
Als u dit voorbeeld efficiënter wilt maken, gaat u naar SecondPageTextBrushSecondPage.xaml en gaat u naar ThirdPageTextBrushThirdPage.xaml.
InitialPageTextBrush kan in App.xaml blijven, omdat toepassingsbronnen in elk geval moeten worden geparseerd bij het opstarten van de app.
Meerdere borstels samenvoegen die er hetzelfde uitzien in één resource
Het XAML-platform probeert veelgebruikte objecten in de cache op te slaan, zodat ze zo vaak mogelijk opnieuw kunnen worden gebruikt. Maar XAML kan niet gemakkelijk zien of een kwast die is gedeclareerd in één stuk opmaak hetzelfde is als een kwast die in een ander deel van de opmaak is gedeclareerd. In het voorbeeld hier wordt SolidColorBrush gebruikt om te demonstreren, maar de case is waarschijnlijker en belangrijker met GradientBrush. Controleer ook op borstels die vooraf gedefinieerde kleuren gebruiken; bijvoorbeeld, "Orange" en "#FFFFA500" zijn dezelfde kleur.
Inefficiënt
<!-- 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>
Als u de duplicatie wilt herstellen, definieert u het kwast als een resource. Als besturingselementen op andere pagina's dezelfde kwast gebruiken, verplaats deze dan naar App.xaml.
Efficiënte
<Page ... >
<Page.Resources>
<SolidColorBrush x:Key="BrandBrush" Color="#FFFFA500"/>
</Page.Resources>
<StackPanel>
<TextBlock Foreground="{StaticResource BrandBrush}" />
<Button Content="Submit" Foreground="{StaticResource BrandBrush}" />
</StackPanel>
</Page>
Overtekening minimaliseren
Overtekening treedt op wanneer meer dan één object wordt getekend in dezelfde scherm pixels. Houd er rekening mee dat er soms een compromis is tussen deze richtlijnen en de wens om het aantal elementen te minimaliseren.
Gebruik DebugSettings.IsOverdrawHeatMapEnabled als visuele diagnose. Misschien ziet u objecten die worden getekend waarvan u niet wist dat ze in de scène zaten.
Transparante of verborgen elementen
Als een element niet zichtbaar is omdat het transparant of verborgen is achter andere elementen en niet bijdraagt aan de indeling, verwijdert u het. Als het element niet zichtbaar is in de oorspronkelijke visuele toestand, maar zichtbaar is in andere visuele toestanden, gebruikt u x:Load om de status te bepalen of stelt u Zichtbaarheid in op Samengevouwen op het element zelf en wijzigt u de waarde in Zichtbaar in de juiste statussen. Er zijn uitzonderingen op deze heuristiek: in het algemeen is de waarde die een eigenschap heeft in het merendeel van de visuele statussen het beste lokaal op het element ingesteld.
Samengestelde elementen
Gebruik een samengesteld element in plaats van meerdere elementen in lagen aan te brengen om een effect te creëren. In dit voorbeeld is het resultaat een vorm met twee tinten waarin de bovenste helft zwart is van de achtergrond van het Grid en de onderste helft grijs is doordat de semitransparante witte Rechthoek alpha-geblend is over de zwarte achtergrond van het Grid. Hier worden 150% van de pixels die nodig zijn om het resultaat te bereiken opgevuld.
Inefficiënt
<!-- 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>
Efficiënte
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Fill="Black"/>
<Rectangle Grid.Row="1" Fill="#FF7F7F7F"/>
</Grid>
Indelingspanelen
Een indelingspaneel kan twee doeleinden hebben: een gebied kleuren en kinder-elementen indelen. Als een element lager in z-volgorde al een gebied kleurt, hoeft een indelingspaneel dat zich daarboven bevindt, dat gebied niet te schilderen; in plaats daarvan kan het zich richten op het positioneren van zijn kinderen. Dit is een voorbeeld.
Inefficiënt
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<GridView Background="Blue">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Background="Blue"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Efficiënte
<GridView Background="Blue">
<GridView.ItemTemplate>
<DataTemplate>
<Grid/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Als het raster testbaar moet zijn, stelt u er een achtergrondwaarde van Transparent in.
Grenzen
Gebruik een randelement om een rand rond een object te tekenen. In dit voorbeeld wordt een raster gebruikt als een geïmproviseerde rand rond een tekstvak. Maar alle pixels in de middelste cel zijn overgetekend.
Inefficiënt
<!-- 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>
Efficiënte
<Border BorderBrush="Blue" BorderThickness="5" Width="300" Height="45">
<TextBox/>
</Border>
Marges
Let op de paginamarges. Twee aangrenzende elementen overlappen elkaar, mogelijk per ongeluk, als negatieve marges zich uitbreiden naar de rendergrenzen van een ander element en leiden tot overtekening.
Statische inhoud in cache opslaan
Een andere bron van overtekening is een vorm die is gemaakt van veel overlappende elementen. Als u CacheMode instelt op BitmapCache op het UIElement dat de samengestelde vorm bevat, wordt het element eenmaal weergegeven op een bitmap en wordt dat bitmap per frame gebruikt in plaats van overtekening.
Inefficiënt
<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>
De bovenstaande afbeelding is het resultaat, maar hier volgt een kaart van de overschreven regio's. Donkerder rood wijst op grotere hoeveelheden overdraw.
Efficiënte
<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>
Let op het gebruik van CacheMode. Gebruik deze techniek niet als een van de subvormen geanimeerd worden, omdat de bitmapcache waarschijnlijk elk frame opnieuw moet worden gegenereerd, wat het doel tenietdoet.
Gecompileerde XAML-uitvoer gebruiken
Windows App SDK compileert XAML in een binaire weergave als onderdeel van de build, waardoor tekstparseringskosten tijdens runtime worden voorkomen. De gecompileerde indeling optimaliseert ook het laden en het creëren van boomstructuren voor algemene XAML-typen, zoals visuele statussen, resourcedictionaries en stijlen.
Ingebouwde WinUI-besturingselementen en -woordenlijsten profiteren al van deze pijplijn. Houd voor uw eigen WinUI-app de normale XAML-compilatiestappen ingeschakeld, zodat de gegenereerde compilatie-uitvoer tijdens runtime beschikbaar is.
Verwante artikelen
Windows developer