Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
L’analyse du balisage XAML pour construire des objets en mémoire prend beaucoup de temps pour une interface utilisateur complexe. Voici quelques opérations que vous pouvez effectuer pour améliorer l’analyse et le temps de chargement de votre balisage XAML et l’efficacité de la mémoire de votre application WinUI.
Au démarrage de l’application, limitez le balisage XAML chargé uniquement à ce dont vous avez besoin pour votre interface utilisateur initiale. Examinez le balisage dans votre page initiale, y compris les ressources de page, et vérifiez que vous ne chargez pas d’éléments supplémentaires qui ne sont pas nécessaires immédiatement. Ces éléments peuvent provenir de diverses sources, telles que les dictionnaires de ressources, les éléments qui sont initialement repliés et les éléments superposés sur d'autres éléments.
L’optimisation de votre code XAML pour améliorer l’efficacité nécessite des compromis ; il n’y a pas toujours une solution unique pour chaque situation. Ici, nous examinons certains problèmes courants et fournissons des instructions que vous pouvez utiliser pour faire les bons compromis pour votre application WinUI.
Réduire le nombre d’éléments
Bien que la plateforme XAML puisse afficher un grand nombre d’éléments, vous pouvez mettre votre application en place et effectuer un rendu plus rapide en utilisant le plus petit nombre d’éléments nécessaires pour obtenir les visuels souhaités.
Les choix que vous effectuez dans la façon dont vous disposez vos contrôles d’interface utilisateur affectent le nombre d’éléments d’interface utilisateur créés au démarrage de votre application. Pour plus d’informations sur l’optimisation de la disposition, consultez Optimiser votre disposition XAML.
Le nombre d’éléments est extrêmement important dans les modèles de données, car chaque élément est créé à nouveau pour chaque élément de données. Pour plus d’informations sur la réduction du nombre d’éléments dans une liste ou une grille, consultez La réduction des éléments par élément dans l’article Optimiser les performances ListView et GridView pour WinUI .
Ici, nous examinons d’autres façons de réduire le nombre d’éléments que votre application doit charger au démarrage.
Différer la création d’un élément
Si votre balisage XAML contient des éléments que vous n’affichez pas immédiatement, vous pouvez différer le chargement de ces éléments jusqu’à ce qu’ils soient affichés. Par exemple, vous pouvez retarder la création de contenu non visible, tel qu’un onglet secondaire dans une interface utilisateur de type tabulation. Vous pouvez également afficher les éléments d’un affichage grille par défaut, mais fournir une option permettant à l’utilisateur d’afficher les données dans une liste à la place. Vous pouvez retarder le chargement de la liste jusqu’à ce qu’elle soit nécessaire.
Utilisez l’attribut x :Load au lieu de la propriété Visibility pour contrôler lorsqu’un élément est affiché. Lorsque la visibilité d’un élément est définie sur Collapsed, elle est ignorée pendant la passe de rendu, mais vous payez toujours les coûts d’instance d’objet en mémoire. Lorsque vous utilisez x :Load à la place, l’infrastructure ne crée pas l’instance d’objet tant qu’elle n’est pas nécessaire, les coûts de mémoire sont donc encore inférieurs. L’inconvénient est que vous payez une petite surcharge mémoire (environ 600 octets) lorsque l’interface utilisateur n’est pas chargée.
Note
Dans le Kit de développement logiciel (SDK) d’application Windows, x :Load est le modèle de chargement différé recommandé pour le contenu XAML qui n’est pas nécessaire immédiatement.
Les exemples suivants montrent la différence dans le nombre d’éléments et l’utilisation de la mémoire lorsque différentes techniques sont utilisées pour masquer les éléments d’interface utilisateur. Un ListView et un GridView contenant des éléments identiques sont placés dans la grille racine d’une page. ListView n’est pas visible, mais le GridView est affiché. Le code XAML de chacun de ces exemples produit la même interface utilisateur à l’écran. Utilisez des outils pour le profilage et les performances pour vérifier le nombre d’éléments et l’utilisation de la mémoire dans votre application.
Option 1 - Inefficace
Ici, le ListView est chargé, mais il n’est pas visible car son Width est 0. Le ListView et chacun de ses Éléments Enfants sont créés dans l’arborescence visuelle et chargés en mémoire.
<!-- 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>
Arborescence visuelle dynamique avec ListView chargé. Le nombre total d’éléments pour la page est de 89.
ListView et ses enfants sont chargés en mémoire.
Option 2 - Mieux
Ici, le Visibility du ListView est défini à Collapsed (l'autre XAML est identique à l'original). ListView est créé dans l’arborescence visuelle, mais ses éléments enfants ne le sont pas. Toutefois, ils sont toujours chargés en mémoire, de sorte que l’utilisation de la mémoire est identique à l’exemple précédent.
<ListView x:Name="List1" Visibility="Collapsed">
Arborescence visuelle dynamique avec l’objet ListView réduit. Le nombre total d’éléments pour la page est de 46.
ListView et ses enfants sont chargés en mémoire.
Option 3 - Plus efficace
Ici, le ListView a l’attribut x:Load défini sur False (l’autre XAML est identique à l’original). ListView n’est pas créé dans l’arborescence visuelle ou chargé en mémoire au démarrage.
<ListView x:Name="List1" Visibility="Collapsed" x:Load="False">
Arborescence visuelle dynamique avec listView non chargé. Le nombre total d’éléments pour la page est de 45.
ListView et ses enfants ne sont pas chargés en mémoire.
Note
Les nombres d’éléments et l’utilisation de la mémoire dans ces exemples sont très petits et ne sont montrés que pour illustrer le concept. Dans ces exemples, la surcharge liée à l’utilisation de x :Load est supérieure à l’économie de mémoire, de sorte que l’application ne bénéficierait pas. Vous devez utiliser des outils de profilage sur votre application pour déterminer si le chargement différé vous aidera.
Utiliser les propriétés du panneau de disposition
Les panneaux de disposition ont une propriété d’arrière-plan . Il n’est donc pas nécessaire de placer un rectangle devant un panneau simplement pour la colorer.
Inefficace
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<Grid>
<Rectangle Fill="Black"/>
</Grid>
Efficace
<Grid Background="Black"/>
Les panneaux de disposition ont également des propriétés de bordure intégrées. Vous n’avez donc pas besoin de placer un élément Border autour d’un panneau de disposition. Pour plus d’informations et d’exemples, consultez Optimiser votre disposition XAML .
Utiliser des images à la place d’éléments vectoriels
Si vous réutilisez le même élément vectoriel suffisamment de fois, il devient plus efficace d’utiliser un élément Image à la place. Les éléments vectoriels peuvent être plus coûteux, car l’UC doit créer chaque élément individuel séparément. Le fichier image doit être décodé une seule fois.
Optimiser les ressources et les dictionnaires de ressources
En règle générale, vous utilisez des dictionnaires de ressources pour stocker, à un niveau quelque peu global, les ressources que vous souhaitez référencer à plusieurs emplacements dans votre application. Par exemple, les styles, les pinceaux, les modèles, et ainsi de suite.
En général, ResourceDictionary est optimisé pour éviter d’instancier des ressources jusqu’à ce qu’elles soient demandées. Mais il existe des situations que vous devez éviter afin que les ressources ne soient pas instanciées inutilement.
Ressources avec x :Name
Utilisez l’attribut x :Key pour référencer vos ressources. Toute ressource avec l’attribut x :Name ne bénéficie pas de l’optimisation de la plateforme ; Au lieu de cela, elle est instanciée dès la création de ResourceDictionary. Cela se produit parce que x :Name indique à la plateforme que votre application a besoin d’un accès de champ à cette ressource, de sorte que la plateforme doit créer quelque chose pour contenir une référence à celle-ci.
Dictionnaire de ressources dans un UserControl
Un ResourceDictionary défini à l’intérieur d’un UserControl entraîne une pénalité. La plateforme crée une copie d'un ResourceDictionary de ce type pour chaque instance du UserControl. Si vous avez un UserControl qui est utilisé beaucoup, déplacez le ResourceDictionary hors de UserControl et placez-le au niveau de la page.
Portée des ressources et de ResourceDictionary
Si une page référence un contrôle utilisateur ou une ressource définie dans un autre fichier, l’infrastructure analyse également ce fichier.
Ici, étant donné que InitialPage.xaml utilise une ressource de ExampleResourceDictionary.xaml, l’ensemble de ExampleResourceDictionary.xaml doit être analysé au démarrage.
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>
Si vous utilisez une ressource sur de nombreuses pages dans votre application, la stocker dans App.xaml est une bonne pratique et évite la duplication. Toutefois , App.xaml est analysé au démarrage de l’application. Par conséquent, toute ressource utilisée dans une seule page, sauf si cette page est la page initiale, doit être placée dans les ressources locales de la page. Cet exemple montre App.xaml contenant des ressources utilisées par une seule page qui n’est pas la page initiale. Cela augmente inutilement le temps de démarrage.
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>
Pour rendre cet exemple plus efficace, passez SecondPageTextBrush à SecondPage.xaml et passez ThirdPageTextBrush à ThirdPage.xaml.
InitialPageTextBrush peut rester dans App.xaml , car les ressources d’application doivent être analysées au démarrage de l’application dans tous les cas.
Consolider plusieurs pinceaux qui ont le même aspect en une seule ressource
La plateforme XAML tente de mettre en cache les objets couramment utilisés afin qu’ils puissent être réutilisés le plus souvent possible. Toutefois, XAML ne peut pas facilement indiquer si un pinceau déclaré dans un élément de balisage est identique à un pinceau déclaré dans un autre. L’exemple ici utilise SolidColorBrush pour illustrer, mais le cas est plus probable et plus important avec GradientBrush. Vérifiez également les pinceaux qui utilisent des couleurs prédéfinies ; par exemple, "Orange" et "#FFFFA500" sont de la même couleur.
Inefficace
<!-- 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>
Pour corriger la duplication, définissez le pinceau en tant que ressource. Si les contrôles d’autres pages utilisent le même pinceau, déplacez-le vers App.xaml.
Efficace
<Page ... >
<Page.Resources>
<SolidColorBrush x:Key="BrandBrush" Color="#FFFFA500"/>
</Page.Resources>
<StackPanel>
<TextBlock Foreground="{StaticResource BrandBrush}" />
<Button Content="Submit" Foreground="{StaticResource BrandBrush}" />
</StackPanel>
</Page>
Réduire le surdessin
La superposition se produit lorsque plusieurs objets sont dessinés sur les mêmes pixels d'écran. Notez qu’il existe parfois un compromis entre ces conseils et le désir de réduire le nombre d’éléments.
Utilisez DebugSettings.IsOverdrawHeatMapEnabled comme diagnostic visuel. Vous pouvez trouver des objets dessinés que vous ne connaissiez pas étaient dans la scène.
Éléments transparents ou masqués
Si un élément n’est pas visible, car il est transparent ou masqué derrière d’autres éléments, et qu’il ne contribue pas à la disposition, puis supprimez-le. Si l’élément n’est pas visible dans l’état visuel initial, mais est visible dans d’autres états visuels, utilisez x :Load pour contrôler son état ou définir Visibility sur Collapsed sur l’élément lui-même et modifiez la valeur en Visible dans les états appropriés. Il y aura des exceptions à cette heuristique : en général, la valeur qu’une propriété a dans la majorité des états visuels est la meilleure définie localement sur l’élément.
Éléments composites
Utilisez un élément composite au lieu de calquer plusieurs éléments pour créer un effet. Dans cet exemple, le résultat est une forme bicolore où la moitié supérieure est noire, provenant de l’arrière-plan de la Grille, et la moitié inférieure est grise du Rectangle blanc semi-transparent, fusionné en alpha sur l’arrière-plan noir de la Grille. Ici, 150% des pixels nécessaires pour obtenir le résultat sont remplis.
Inefficace
<!-- 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>
Efficace
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Fill="Black"/>
<Rectangle Grid.Row="1" Fill="#FF7F7F7F"/>
</Grid>
Panneaux de mise en page
Un panneau de disposition peut avoir deux objectifs : colorer une zone et mettre en place des éléments enfants. Si un élément plus loin dans l’ordre z colorie déjà une zone, un panneau de disposition en face n’a pas besoin de peindre cette zone ; au lieu de cela, il peut se concentrer sur la disposition de ses enfants. Voici un exemple.
Inefficace
<!-- NOTE: EXAMPLE OF INEFFICIENT CODE; DO NOT COPY-PASTE. -->
<GridView Background="Blue">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Background="Blue"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Efficace
<GridView Background="Blue">
<GridView.ItemTemplate>
<DataTemplate>
<Grid/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Si la grille doit être cliquable, définissez une valeur d’arrière-plan Transparent sur elle.
Bordures
Utilisez un élément Border pour dessiner une bordure autour d’un objet. Dans cet exemple, une grille est utilisée comme bordure de fortune autour d’une zone de texte. Mais tous les pixels de la cellule centrale sont surchargés.
Inefficace
<!-- 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>
Efficace
<Border BorderBrush="Blue" BorderThickness="5" Width="300" Height="45">
<TextBox/>
</Border>
Marges
Tenez compte des marges. Deux éléments voisins se chevauchent, éventuellement accidentellement, si les marges négatives s'étendent jusqu'aux limites de rendu d'un autre élément et provoquent un dessin en excès.
Mettre en cache du contenu statique
Une autre source de surcharge est une configuration constituée de nombreux éléments se chevauchant. Si vous définissez CacheMode sur BitmapCache sur l’UIElement qui contient la forme composite, la plateforme rend l’élément sous forme de bitmap une seule fois et utilise ce bitmap à chaque image au lieu de redessiner.
Inefficace
<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>
L’image ci-dessus est le résultat, mais voici une carte des régions retirées. Le rouge plus foncé indique des niveaux plus élevés de surconsommation.
Efficace
<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>
Notez l’utilisation de CacheMode. N’utilisez pas cette technique si l’un des sous-éléments graphiques s’anime, car le cache bitmap devra probablement être régénéré à chaque image, ce qui en annule la finalité.
Utiliser la sortie XAML compilée
Le Kit de développement logiciel (SDK) d’application Windows compile le code XAML dans une représentation binaire dans le cadre de la build, ce qui évite les coûts d’analyse de texte au moment de l’exécution. Le format compilé optimise également la charge et la création d’arborescences pour les types XAML courants tels que les états visuels, les dictionnaires de ressources et les styles.
Les contrôles et dictionnaires WinUI intégrés bénéficient déjà de ce pipeline. Pour votre propre application WinUI, conservez les étapes de compilation XAML normales activées afin que la sortie de compilation de balisage générée soit disponible au moment de l’exécution.
Articles connexes
Windows developer