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.
Créez des applications WinUI avec le Kit de développement logiciel (SDK) d’application Windows qui commencent rapidement en réduisant le travail de démarrage, en simplifiant la première image et en chargeant des fonctionnalités non critiques une fois la fenêtre interactive.
Meilleures pratiques en matière de performances lors du démarrage de votre application
En partie, les utilisateurs perçoivent si votre application est rapide ou lente en fonction du temps nécessaire pour démarrer. Dans le cadre de cette rubrique, l’heure de démarrage d’une application commence lorsque l’utilisateur démarre l’application et se termine lorsque l’utilisateur peut interagir avec l’application de manière significative. Cet article fournit des suggestions sur la façon d’améliorer les performances de démarrage d’une application WinUI.
Mesure du temps de démarrage de votre application
Veillez à démarrer votre application quelques fois avant de mesurer son temps de démarrage. Cela vous donne une base de référence pour votre mesure et vous permet de vous assurer que vous mesurez une durée de démarrage aussi courte que raisonnablement possible.
Prenez des mesures représentatives de ce que l’utilisateur final rencontrera. Mesure Release s’appuie sur du matériel représentatif, examinez le démarrage froid et chaud, et concentrez-vous sur le temps pour la première image interactive plutôt que seulement le temps jusqu’à ce que le processus existe.
Différer le travail aussi longtemps que possible
Pour améliorer le temps de démarrage de votre application, effectuez uniquement le travail qui doit absolument être effectué pour permettre à l’utilisateur de commencer à interagir avec l’application. Cela peut être particulièrement utile si vous pouvez retarder le chargement d’assemblys supplémentaires. Le Common Language Runtime charge un assembly la première fois qu’il est utilisé. Si vous pouvez réduire le nombre d’assemblys chargés, vous pouvez améliorer le temps de démarrage de votre application et sa consommation de mémoire.
Effectuer un travail de longue durée indépendamment
Votre application peut être interactive même s’il existe des parties de l’application qui ne sont pas entièrement fonctionnelles. Par exemple, si votre application affiche des données qui prennent un certain temps à récupérer, vous pouvez faire en sorte que ce code s’exécute indépendamment du code de démarrage de l’application en récupérant les données de manière asynchrone. Lorsque les données sont disponibles, renseignez l’interface utilisateur de l’application avec les données.
La plupart des API qui récupèrent des données sont asynchrones. Vous allez donc probablement récupérer des données de façon asynchrone. Pour plus d’informations, consultez Programmation asynchrone avec async et await. Si vous effectuez un travail qui n’utilise pas d’API asynchrones, vous pouvez utiliser la Task classe pour effectuer un travail de longue durée afin de ne pas empêcher l’utilisateur d’interagir avec l’application. Cela permet à votre application de répondre pendant le chargement des données.
Si votre application prend un temps particulièrement long pour charger une partie de son interface utilisateur, envisagez d’afficher un message dans cette zone, par exemple « Obtention des données les plus récentes » afin que vos utilisateurs sachent que l’application est toujours en cours de traitement.
Réduire le temps de démarrage
Toutes les applications les plus simples nécessitent un temps de chargement de ressources, d’analyse XAML, de configuration de structures de données et d’exécution logique pendant le lancement. Pour les applications WinUI, il permet de réfléchir au démarrage en quatre étapes : lancement de processus, création de fenêtre, création de page principale et mise en page/rendu pour le premier cadre.
La période de démarrage est le temps entre le moment où un utilisateur démarre l’application et le moment où l’application devient fonctionnelle. Il s’agit d’un moment critique, car il s’agit de la première impression d’un utilisateur de votre application. Les utilisateurs attendent des commentaires instantanés et continus du système et des applications. Le système et l’application sont perçus comme rompus ou mal conçus lorsque les applications ne démarrent pas rapidement.
Présentation des phases de démarrage
Le démarrage implique un certain nombre de pièces mobiles, et tous doivent être coordonnés pour la meilleure expérience utilisateur. Les étapes suivantes se produisent entre l’utilisateur qui lance votre application et le contenu de l’application affiché.
- Le processus se lance et le code de démarrage généré par un modèle appelle
Main. - L’objet
Applicationest créé.- Le constructeur d'application appelle
InitializeComponent, ce qui entraîne l'analyse deApp.xamlet la création d'objets.
- Le constructeur d'application appelle
-
Application.OnLaunched est déclenchée.
- Le code de l’application crée la fenêtre principale, affecte le contenu initial et les appels
Activate. - Le constructeur de la page principale appelle
InitializeComponent, ce qui entraîne l'analyse du XAML de la page et la création d’objets.
- Le code de l’application crée la fenêtre principale, affecte le contenu initial et les appels
- Le framework XAML exécute le processus de mise en page, y compris la mesure et la disposition.
-
ApplyTemplateprovoque la création du contenu du modèle de contrôle pour chaque contrôle, ce qui constitue généralement la majeure partie du temps de mise en page au démarrage.
-
- Le rendu crée des visuels pour le contenu de la fenêtre.
- La première trame est présentée et le travail post-démarrage se poursuit de façon asynchrone.
Faites-en moins dans votre parcours de startup
Laissez votre chemin de code de démarrage libre de tout ce qui n’est pas nécessaire pour votre première image.
- Si vous avez des DLL utilisateur contenant des contrôles qui ne sont pas nécessaires pendant la première image, envisagez de les charger plus tard.
- Si vous avez une partie de votre interface utilisateur qui dépend des données du cloud, fractionnez cette interface utilisateur. Tout d’abord, affichez l’interface utilisateur qui n’est pas dépendante des données cloud, puis affichez de manière asynchrone l’interface utilisateur dépendante du cloud. Vous devez également envisager de mettre en cache les données localement afin que l’application puisse fonctionner hors connexion ou ne pas être affectée par la connectivité réseau lente.
- Affichez l’interface utilisateur de progression si votre interface utilisateur attend des données.
- Soyez prudent quant aux conceptions d’applications qui impliquent un grand nombre d’analyse de fichiers de configuration ou d’interface utilisateur générées dynamiquement par le code.
Réduire le nombre d’éléments
Les performances de démarrage dans une application XAML sont directement corrélées au nombre d’éléments que vous créez au démarrage. Moins d’éléments que vous créez, moins votre application prendra de temps pour démarrer. À titre de référence approximative, envisagez que chaque élément prend 1 ms pour être créé.
- Les modèles utilisés dans les contrôles d’éléments peuvent avoir le plus d’impact, car ils sont répétés plusieurs fois. Consultez l’optimisation de l’interface utilisateur ListView et GridView.
- Les modèles UserControls et de contrôle sont développés. Ceux-ci doivent donc également être pris en compte.
- Si vous créez un code XAML qui n’apparaît pas sur l’écran, vous devez justifier si ces éléments de XAML doivent être créés au démarrage.
La fenêtre Arborescence de Visual Studio Live affiche le nombre d’éléments enfants pour chaque nœud de l’arborescence.
Utilisez le report. La réduction d’un élément ou la définition de son opacité sur 0 n’empêche pas la création de l’élément. À l’aide x:Load ou x:DeferLoadStrategy, vous pouvez retarder le chargement d’un élément d’interface utilisateur et le charger si nécessaire. Il s’agit d’un bon moyen de retarder l’interface utilisateur de traitement qui n’est pas visible pendant le démarrage afin de pouvoir la charger si nécessaire ou dans le cadre d’un ensemble de logiques retardées. Pour déclencher le chargement, il vous suffit d'appeler FindName pour l’élément. Pour obtenir un exemple et plus d’informations, consultez l’attribut x :Load et l’attribut x :DeferLoadStrategy.
Virtualisation. Si vous avez du contenu de liste ou de répéteur dans votre interface utilisateur, il est vivement recommandé d’utiliser la virtualisation de l’interface utilisateur. Si l’interface utilisateur de liste n’est pas virtualisée, vous payez le coût de la création de tous les éléments à l’avance, ce qui peut ralentir votre démarrage. Consultez l’optimisation de l’interface utilisateur ListView et GridView.
Les performances des applications ne concernent pas seulement les performances brutes ; c’est aussi à propos de la perception. Modifier l'ordre des opérations pour que les aspects visuels se produisent en premier donne souvent à l'utilisateur l'impression que l'application est plus rapide. Les utilisateurs considèrent l’application chargée lorsque le contenu est sur l’écran. Les applications doivent généralement effectuer plusieurs opérations au démarrage, et toutes ces tâches ne sont pas requises pour afficher l’interface utilisateur. Ces éléments doivent donc être retardés ou hiérarchisés plus bas que l’interface utilisateur.
Cet article traite de la première image, qui provient de la terminologie de l’animation et de la vidéo et est une mesure du temps nécessaire jusqu’à ce que le contenu soit vu par l’utilisateur final.
Améliorer la perception du démarrage
Utilisons l’exemple d’un jeu en ligne simple pour identifier chaque phase de démarrage et différentes techniques pour donner à l’utilisateur des commentaires tout au long du processus.
Dans la première phase, le processus démarre et l’application crée sa fenêtre. Pendant ce temps, l’utilisateur n’a pas encore vu le contenu de l’application. Votre objectif est d’obtenir rapidement une fenêtre légère affichée à l’écran.
La deuxième phase englobe la création et l’initialisation des structures critiques pour le jeu. Si l’application peut rapidement créer son interface utilisateur initiale avec les données disponibles au lancement, cette phase est triviale et vous pouvez afficher immédiatement l’interface utilisateur. Sinon, affichez une page de chargement légère pendant l’initialisation de l’application.
C'est à vous de décider de l'apparence de la page de chargement : elle peut être aussi simple que d'afficher une barre de progression ou un anneau de progression. Le point clé est que l’application indique qu’elle effectue un travail avant qu’elle ne devienne entièrement réactive. Dans le cas du jeu, l’écran initial nécessite que certaines images et sons soient chargés à partir du disque en mémoire. Ces tâches prennent du temps, de sorte que l’application conserve l’utilisateur informé en affichant une page de chargement avec une animation simple liée au thème du jeu.
La troisième étape commence une fois que le jeu a un ensemble minimal d’informations pour créer une interface utilisateur interactive, qui remplace la page de chargement. À ce stade, les seules informations disponibles pour le jeu en ligne peuvent être le contenu que l’application a chargé à partir du disque. Le jeu peut être fourni avec suffisamment de contenu pour créer une interface utilisateur interactive, mais parce qu’il s’agit d’un jeu en ligne, il ne sera pas entièrement fonctionnel tant qu’il ne se connecte pas à Internet et télécharge des informations supplémentaires. Tant qu’il n’a pas toutes les informations dont il a besoin, l’utilisateur peut interagir avec l’interface utilisateur, mais les fonctionnalités qui ont besoin de données supplémentaires à partir du web doivent fournir des commentaires sur le chargement du contenu. Il peut prendre un certain temps pour qu’une application devienne entièrement fonctionnelle. Il est donc important que la fonctionnalité soit rendue disponible dès que possible.
Maintenant que nous avons identifié les trois phases de démarrage dans le jeu en ligne, nous allons les lier au code réel.
Phase 1 et Phase 2
Utilisez le constructeur de l’application uniquement pour initialiser des structures de données critiques pour l’application. Concentrez-vous sur la création rapide de la première fenêtre, l'affectation de contenu léger et l'activation de la fenêtre afin que l'application puisse afficher un retour immédiatement.
public partial class App : Application
{
public static Window MainWindow { get; private set; } = null!;
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
base.OnLaunched(args);
MainWindow = new MainWindow();
MainWindow.Content = new LoadingPage();
MainWindow.Activate();
_ = InitializeAsync();
}
private async Task InitializeAsync()
{
// Asynchronously restore state and load the minimum data needed
// to create the first interactive UI.
await LoadInitialDataAsync();
MainWindow.Content = new GameHomePage();
}
private static Task LoadInitialDataAsync()
{
// Download data to populate the initial UI.
return Task.CompletedTask;
}
}
L’une des tâches clés dans OnLaunched consiste à créer une interface utilisateur, à l’affecter à Window.Content, puis à appeler Window.Activate. Si vous avez besoin de plusieurs flux d’activation, gardez le même principe : affichez rapidement du contenu léger et déplacez le travail coûteux hors du chemin de démarrage critique.
Les applications qui affichent une page de chargement pendant le lancement peuvent commencer à créer l’interface utilisateur principale en arrière-plan. Une fois cet élément créé, son événement FrameworkElement.Loaded se produit. Dans le gestionnaire d’événements, vous pouvez remplacer le contenu de la fenêtre, qui est actuellement l’écran de chargement, par la page d’accueil nouvellement créée.
Il est essentiel qu’une application avec une période d’initialisation prolongée affiche une page de chargement. En plus de fournir des commentaires sur le processus de démarrage, la fenêtre doit être activée rapidement afin que les utilisateurs voient que l’application progresse.
partial class GameHomePage : Page
{
public GameHomePage()
{
InitializeComponent();
// Add a handler to be called when the home page has been loaded.
Loaded += GameHomePageLoaded;
// Load the minimal amount of image and sound data from disk necessary
// to create the home page.
}
private void GameHomePageLoaded(object sender, RoutedEventArgs e)
{
// Set the content of the main window to the home page now that it's
// ready to be displayed.
App.MainWindow.Content = this;
}
}
Phase 3
Simplement parce que l’application a affiché l’interface utilisateur ne signifie pas qu’elle est entièrement prête à être utilisée. Dans le cas de notre jeu, l’interface utilisateur s’affiche avec des espaces réservés pour les fonctionnalités qui nécessitent des données à partir d’Internet. À ce stade, le jeu télécharge les données supplémentaires nécessaires pour rendre l’application entièrement fonctionnelle et active progressivement les fonctionnalités à mesure que les données sont acquises.
Parfois, une grande partie du contenu nécessaire au démarrage peut être empaquetée avec l’application. C’est le cas avec un jeu simple. Cela rend le processus de démarrage assez simple. Mais de nombreux programmes, tels que les lecteurs d’actualités et les visionneuses de photos, doivent tirer des informations du web pour devenir fonctionnels. Ces données peuvent être volumineuses et peuvent prendre un certain temps de téléchargement. La façon dont l’application obtient ces données au démarrage peut avoir un impact considérable sur les performances perçues.
Vous pouvez afficher une page de chargement trop longue si une application a essayé de télécharger l’ensemble d’un jeu de données dont elle a besoin pour des fonctionnalités dans la première ou la deuxième phase du démarrage. Cela donne l'impression qu'une application est bloquée. Nous recommandons à une application de télécharger la quantité minimale de données nécessaires pour afficher une interface utilisateur interactive avec des éléments d’espace réservé dans la phase 2, puis de charger progressivement des données, qui remplacent les éléments d’espace réservé, dans la phase 3. Pour plus d’informations sur la gestion des données, consultez Optimiser ListView et GridView.
La façon dont une application réagit exactement à chaque phase de démarrage est entièrement à vous, mais fournir à l’utilisateur autant de commentaires que possible en utilisant l’interface utilisateur initiale légère, le chargement des écrans et le chargement progressif des données rend l’application plus rapide.
Réduire les assemblys managés dans le chemin de démarrage
Le code réutilisable se présente souvent sous la forme de modules (DLL) inclus dans un projet. Le chargement de ces modules nécessite l’accès au disque et le coût peut s’ajouter. Cela a le plus d’impact sur le démarrage à froid, mais il peut également affecter le démarrage chaud. Dans les applications .NET, le CLR tente de retarder ce coût autant que possible en chargeant des assemblys à la demande. Autrement dit, le CLR ne charge pas un module tant qu’une méthode exécutée ne l’a pas référencée. Par conséquent, référencez uniquement les assemblys nécessaires au lancement de votre application dans le code de démarrage afin que le CLR ne charge pas les modules inutiles. Si vous avez des chemins de code inutilisés dans votre chemin d’accès de démarrage qui ont des références inutiles, déplacez ces chemins de code vers d’autres méthodes pour éviter les charges inutiles.
Une autre façon de réduire les chargements de modules consiste à combiner des modules d’application. Le chargement d’un assembly volumineux prend généralement moins de temps que le chargement de deux petits. Cela n’est pas toujours possible et vous devez combiner des modules uniquement s’il ne fait aucune différence matérielle à la productivité des développeurs ou à la réutilisation du code. Vous pouvez utiliser des outils tels que PerfView ou WPA (Windows Performance Analyzer) pour savoir quels modules sont chargés au démarrage.
Effectuer des requêtes web intelligentes
Vous pouvez améliorer considérablement le temps de chargement d’une application en empaquetant son contenu localement, y compris XAML, images et tous les autres fichiers importants pour l’application. Les opérations de disque sont plus rapides que les opérations réseau. Si une application a besoin d’un fichier particulier lors de l’initialisation, vous pouvez réduire le temps de démarrage global en le chargeant à partir du disque au lieu de le récupérer à partir d’un serveur distant.
Journalisez et mettez en cache les pages efficacement
Le Frame contrôle fournit des fonctionnalités de navigation. Il offre une navigation vers une page (Navigateméthode), journalisation de navigation (BackStacket ForwardStack propriétés et GoForwardGoBack méthodes), mise en cache de page (Page.NavigationCacheMode) et prise en charge de la sérialisation (GetNavigationStateméthode).
Les performances à prendre en compte avec Frame concernent principalement la journalisation et la mise en cache des pages.
Journalisation de trames. Lorsque vous naviguez vers une page avec Frame.Navigate, une PageStackEntry pour la page courante est ajoutée à la collection Frame.BackStack.
PageStackEntry est relativement petit, mais il n’y a pas de limite intégrée à la taille de la BackStack collection. Potentiellement, un utilisateur peut naviguer dans une boucle et développer indéfiniment cette collection.
Le PageStackEntry inclut également le paramètre passé à la méthode Frame.Navigate. Il est recommandé que ce paramètre soit un type sérialisable primitif tel qu’un int ou string, afin d’autoriser la Frame.GetNavigationState méthode à fonctionner. Ce paramètre peut toutefois potentiellement référencer un objet qui engage des quantités plus significatives d'ensemble de travail ou d’autres ressources, rendant ainsi chaque entrée dans le BackStack encore plus coûteuse. Par exemple, vous pouvez utiliser un StorageFile paramètre comme paramètre et, par conséquent, conserver BackStack un nombre indéfini de fichiers ouverts.
Par conséquent, il est recommandé de conserver les paramètres de navigation petits et de limiter la taille du BackStack. Il BackStack s’agit d’une collection standard en C#. Elle peut donc être supprimée simplement en supprimant les entrées.
Mise en cache de page. Par défaut, lorsque vous accédez à une page avec la Frame.Navigate méthode, une nouvelle instance de la page est instanciée. De même, si vous revenez à la page précédente avec Frame.GoBack, une nouvelle instance de la page précédente est allouée.
Frame offre également un cache de page facultatif qui peut éviter ces instanciations. Pour obtenir une page placée dans le cache, utilisez la Page.NavigationCacheMode propriété. Définir ce mode à Required force la mise en cache de la page, tandis que le définir à Enabled permet à la page d'être mise en cache. Par défaut, la taille du cache est de 10 pages, mais elle peut être remplacée par la Frame.CacheSize propriété. Toutes les Required pages sont mises en cache et, s’il y a moins de CacheSize pages requises, Enabled les pages peuvent également être mises en cache.
La mise en cache des pages peut aider les performances en évitant les instanciations et en améliorant ainsi les performances de navigation. La mise en cache des pages peut nuire aux performances en raison d'une cache excessive, ce qui a un impact sur l'ensemble actif.
Par conséquent, il est recommandé d’utiliser la mise en cache des pages selon les besoins de votre application. Par exemple, supposons que vous disposez d'une application qui affiche une liste d'éléments dans un Frame, et lorsque vous sélectionnez un élément, elle dirige le cadre vers une page de détails pour cet élément. La page de liste devrait probablement être mise en cache. Si la page de détails est identique pour tous les éléments, elle doit probablement être mise en cache également. Mais si la page de détails est plus hétérogène, il peut être préférable de laisser la mise en cache désactivée.
Windows developer