Améliorer les Xamarin.Forms performances des applications

Evolve 2016 : Optimisation des performances des applications avec Xamarin.Forms

Le mauvais niveau de performance d’une application se présente de plusieurs façons. L’application semble ne pas répondre, le défilement de l’affichage est ralenti et la durée de vie de la batterie de l’appareil réduite. Toutefois, l’optimisation des performances implique davantage de choses que l’implémentation d’un code efficace. L’expérience utilisateur liée au niveau de performance de l’application doit également être prise en compte. Par exemple, pour contribuer à améliorer l’expérience utilisateur, vous devez vérifier que les opérations s’exécutent sans empêcher l’utilisateur d’effectuer d’autres activités.

Il existe de nombreuses techniques permettant d’augmenter les performances et les performances perçues des Xamarin.Forms applications. Utilisées conjointement, ces techniques peuvent considérablement réduire la charge de travail d’une UC, ainsi que la quantité de mémoire consommée par une application.

Notes

Avant de lire cet article, vous devez lire Performances entre plateformes, qui décrit des techniques non spécifiques aux plateformes pour améliorer l’utilisation de la mémoire et les performances des applications générées à l’aide de la plateforme Xamarin.

Activer le compilateur XAML

XAML peut être éventuellement compilé directement en langage intermédiaire (IL) avec le compilateur XAML (XAMLC). XAMLC offre un certain nombre d’avantages :

  • Il effectue une vérification au moment de la compilation du code XAML et informe l’utilisateur des erreurs rencontrées.
  • Il supprime une partie du temps de chargement et d’instanciation pour les éléments XAML.
  • Il permet de réduire la taille de fichier de l’assembly final en n’incluant plus les fichiers .xaml.

XAMLC est activé par défaut dans les nouvelles Xamarin.Forms solutions. Il peut toutefois être nécessaire de l’activer dans des solutions plus anciennes. Pour plus d’informations, consultez Compilation XAML.

Utiliser des liaisons compilées

Les liaisons compilées améliorent les performances de liaison de données dans les applications en Xamarin.Forms résolvant les expressions de liaison au moment de la compilation, plutôt qu’au moment de l’exécution avec réflexion. La compilation d’une expression de liaison génère du code compilé qui résout généralement une liaison 8 à 20 fois plus rapidement qu’avec une liaison classique. Pour plus d’informations, consultez Liaisons compilées.

Réduire les liaisons inutiles

N’utilisez pas de liaisons pour le contenu qui peut être aisément défini de manière statique. Il n’existe aucun avantage à lier des données qui n’ont pas besoin de l’être, car les liaisons ne sont pas rentables. Par exemple, le paramètre Button.Text = "Accept" a moins de surcharge que la liaison Button.Text à une propriété viewmodel string avec la valeur « Accept ».

Utiliser des renderers rapides

Les convertisseurs rapides réduisent l’inflation et les coûts de rendu des Xamarin.Forms contrôles sur Android en aplatissant la hiérarchie de contrôle native résultante. Cette technique améliore davantage les performances en créant moins d’objets, ce qui aboutit à une arborescence d’éléments visuels moins complexe et à une utilisation moindre de la mémoire.

À partir de Xamarin.Forms la version 4.0, toutes les applications ciblant FormsAppCompatActivity utilisent des convertisseurs rapides par défaut. Pour plus d’informations, consultez Renderers rapides.

Activer le suivi de démarrage sur Android

La compilation Ahead Of Time (AOT) sur Android réduit la charge de démarrage de l’application juste-à-temps (JIT) et l’utilisation de la mémoire, au détriment de la création d’un APK de plus grande taille. Une alternative consiste à utiliser le suivi de démarrage, qui fournit un compromis entre taille d’APK Android et temps de démarrage par rapport à la compilation AOT conventionnelle.

Au lieu de compiler autant de l’application que possible en code non managé, le suivi de démarrage compile uniquement l’ensemble de méthodes managées qui représentent les parties les plus coûteuses du démarrage d’une Xamarin.Forms application vide. Cette approche entraîne une réduction de la taille de l’APK par rapport à la compilation AOT conventionnelle, tout en fournissant des améliorations similaires au démarrage.

Activer la compression des dispositions

La compression des dispositions supprime les dispositions spécifiées de l’arborescence d’éléments visuels dans le but d’améliorer les performances de rendu des pages. Les avantages en matière de performances de cette technique varient selon la complexité d’une page, la version du système d’exploitation utilisé et l’appareil sur lequel l’application est en cours d’exécution. Toutefois, les gains en termes de performances les plus importants seront visibles sur les appareils les plus anciens. Pour plus d’informations, consultez Compression des dispositions.

Choisir la disposition correcte

Une disposition qui est capable d’afficher plusieurs enfants, mais qui n’en a qu’un seul, est inutile. Par exemple, l’exemple de code suivant montre un élément StackLayout avec un seul enfant :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DisplayImage.HomePage">
    <StackLayout>
        <Image Source="waterfront.jpg" />
    </StackLayout>
</ContentPage>

Cela est inutile et l’élément StackLayout doit être supprimé, comme indiqué dans l’exemple de code suivant :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DisplayImage.HomePage">
    <Image Source="waterfront.jpg" />
</ContentPage>

En outre, n’essayez pas de reproduire l’apparence d’une disposition spécifique à l’aide de combinaisons d’autres dispositions, car cela aboutirait à des calculs de dispositions inutiles. Par exemple, n’essayez pas de reproduire une disposition Grid à l’aide d’une combinaison d’instances de StackLayout. L’exemple de code ci-dessous illustre cette mauvaise pratique :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Details.HomePage"
             Padding="0,20,0,0">
    <StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Name:" />
            <Entry Placeholder="Enter your name" />
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Age:" />
            <Entry Placeholder="Enter your age" />
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Occupation:" />
            <Entry Placeholder="Enter your occupation" />
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Address:" />
            <Entry Placeholder="Enter your address" />
        </StackLayout>
    </StackLayout>
</ContentPage>

Cela ne sert à rien, car des calculs de dispositions inutiles sont effectués. Au lieu de cela, vous pouvez obtenir la disposition souhaitée à l’aide d’un élément Grid, comme illustré dans l’exemple de code suivant :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Details.HomePage"
             Padding="0,20,0,0">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition Height="30" />
            <RowDefinition Height="30" />
            <RowDefinition Height="30" />
        </Grid.RowDefinitions>
        <Label Text="Name:" />
        <Entry Grid.Column="1" Placeholder="Enter your name" />
        <Label Grid.Row="1" Text="Age:" />
        <Entry Grid.Row="1" Grid.Column="1" Placeholder="Enter your age" />
        <Label Grid.Row="2" Text="Occupation:" />
        <Entry Grid.Row="2" Grid.Column="1" Placeholder="Enter your occupation" />
        <Label Grid.Row="3" Text="Address:" />
        <Entry Grid.Row="3" Grid.Column="1" Placeholder="Enter your address" />
    </Grid>
</ContentPage>

Optimiser les performances de disposition

Pour obtenir les meilleures performances de disposition possibles, suivez ces instructions :

  • Réduisez la profondeur des hiérarchies de dispositions en spécifiant les valeurs de propriété Margin, ce qui permet de créer des dispositions avec moins de retours à la ligne. Pour plus d’informations, consultez Marges et remplissage.
  • Quand vous utilisez un élément Grid, essayez de vous assurer que le moins de lignes et de colonnes possible sont définies sur une taille Auto. Pour chaque ligne ou colonne dimensionnée automatiquement, le moteur de disposition effectue des calculs de dispositions supplémentaires. Utilisez plutôt des lignes et colonnes de taille fixe si possible. Vous pouvez également définir des lignes et des colonnes pour occuper un montant proportionnel d’espace avec la valeur d’énumération GridUnitType.Star, à condition que l’arborescence parente respecte ces instructions de disposition.
  • Ne définissez pas les propriétés VerticalOptions et HorizontalOptions d’une disposition, sauf si cela est obligatoire. Les valeurs par défaut de LayoutOptions.Fill et LayoutOptions.FillAndExpand permettent la meilleure optimisation de la disposition. La modification de ces propriétés a un coût et consomme de la mémoire, même en leur affectant les valeurs par défaut.
  • Évitez d’utiliser un élément RelativeLayout autant que possible. Le processeur aurait considérablement plus de travail à effectuer.
  • Quand vous utilisez un élément AbsoluteLayout, évitez d’utiliser la propriété AbsoluteLayout.AutoSize autant que possible.
  • Quand vous utilisez un élément StackLayout, vérifiez qu’un seul enfant est défini sur LayoutOptions.Expands. Cette propriété permet de garantir que l’enfant spécifié occupe le plus grand espace que l’élément StackLayout peut lui donner, et il est inutile d’effectuer ces calculs plusieurs fois.
  • Évitez d’appeler une des méthodes de la classe Layout, car elles entraînent l’exécution de calculs de dispositions coûteux. Au lieu de cela, il est probable que vous puissiez obtenir le comportement de disposition souhaité en définissant les propriétés TranslationX et TranslationY. Vous pouvez également sous-classer la classe Layout<View> pour obtenir le comportement de disposition souhaité.
  • Ne mettez à jour aucune instance de Label plus fréquemment que nécessaire, car la modification de la taille de l’étiquette peut entraîner le recalcul de l’intégralité de la disposition de l’écran.
  • Ne définissez pas la propriété Label.VerticalTextAlignment, sauf si cela est obligatoire.
  • Affectez à l’élément LineBreakMode des instances de Label la valeur NoWrap autant que possible.

Utiliser la programmation asynchrone

La réactivité globale de votre application peut être améliorée et les goulots d’étranglement des performances souvent évités à l’aide de la programmation asynchrone. Dans .NET, le modèle asynchrone basé sur les tâches (TAP) est le modèle de conception recommandé pour les opérations asynchrones. Toutefois, une utilisation incorrecte du TAP peut entraîner des applications non performantes. Par conséquent, les instructions suivantes doivent être suivies lors de l’utilisation du TAP.

Fondamentaux

  • Comprendre le cycle de vie des tâches, qui est représenté par l’énumération TaskStatus . Pour plus d’informations, consultez La signification de TaskStatus et task status.

  • Utilisez la Task.WhenAll méthode pour attendre de manière asynchrone la fin de plusieurs opérations asynchrones, plutôt que d’une série d’opérations asynchrones individuellement await . Pour plus d’informations, consultez Task.WhenAll.

  • Utilisez la Task.WhenAny méthode pour attendre de manière asynchrone la fin de l’une des multiples opérations asynchrones. Pour plus d’informations, consultez Task.WhenAny.

  • Utilisez la Task.Delay méthode pour produire un Task objet qui se termine après l’heure spécifiée. Cela est utile pour les scénarios tels que l’interrogation des données et le délai de gestion des entrées utilisateur pendant une durée prédéterminée. Pour plus d’informations, consultez Task.Delay.

  • Exécutez des opérations de processeur synchrones intensives sur le pool de threads avec la Task.Run méthode . Cette méthode est un raccourci pour la TaskFactory.StartNew méthode, avec les arguments les plus optimaux définis. Pour plus d’informations, consultez Task.Run.

  • Évitez d’essayer de créer des constructeurs asynchrones. Au lieu de cela, utilisez des événements de cycle de vie ou une logique d’initialisation distincte pour une await initialisation correcte. Pour plus d’informations, consultez Constructeurs asynchrones sur blog.stephencleary.com.

  • Utilisez le modèle de tâche paresseux pour éviter d’attendre que les opérations asynchrones se terminent au démarrage de l’application. Pour plus d’informations, consultez AsyncLazy.

  • Créez un wrapper de tâches pour les opérations asynchrones existantes, qui n’utilisent pas le TAP, en créant des TaskCompletionSource<T> objets. Ces objets bénéficient des avantages de Task la programmabilité et vous permettent de contrôler la durée de vie et l’achèvement du associé Task. Pour plus d’informations, consultez La nature de TaskCompletionSource.

  • Retourne un Task objet, au lieu de retourner un objet attendu Task , lorsqu’il n’est pas nécessaire de traiter le résultat d’une opération asynchrone. Cela est plus performant en raison de moins de basculement de contexte effectué.

  • Utilisez la bibliothèque de flux de données TPL (Task Parallel Library) dans des scénarios tels que le traitement des données à mesure qu’elles deviennent disponibles ou lorsque vous avez plusieurs opérations qui doivent communiquer entre elles de manière asynchrone. Pour plus d’informations, consultez Flux de données (bibliothèque parallèle de tâches).

Interface utilisateur du service

  • Appelez une version asynchrone d’une API, si elle est disponible. Ainsi, le thread d’interface utilisateur reste non bloqué, ce qui améliore l’expérience utilisateur.

  • Mettez à jour des éléments d’interface utilisateur avec des données provenant d’opérations asynchrones sur le thread d’interface utilisateur, pour éviter que des exceptions ne soient levées. Toutefois, les mises à jour de la ListView.ItemsSource propriété sont automatiquement marshalées sur le thread d’interface utilisateur. Pour plus d’informations sur la détermination du code en cours d’exécution sur le thread d’interface utilisateur, consultez Xamarin.Essentials: MainThread.

    Important

    Toutes les propriétés de contrôle mises à jour via la liaison de données sont automatiquement marshalées sur le thread d’interface utilisateur.

Gestion des erreurs

  • Découvrez la gestion asynchrone des exceptions. Les exceptions non gérées levées par du code qui s’exécute de façon asynchrone sont propagées au thread appelant, sauf dans certains scénarios. Pour plus d’informations, consultez Gestion des exceptions (bibliothèque parallèle de tâches).
  • Évitez de créer des async void méthodes et créez plutôt des async Task méthodes. Celles-ci facilitent la gestion des erreurs, la composabilité et la testabilité. L’exception à cette directive est les gestionnaires d’événements asynchrones, qui doivent retourner void. Pour plus d’informations, consultez Éviter Async Void.
  • Ne mélangez pas de code bloquant et asynchrone en appelant les Task.Waitméthodes , Task.Resultou GetAwaiter().GetResult , car elles peuvent entraîner un blocage. Toutefois, si cette règle doit être enfreinte, l’approche recommandée consiste à appeler la GetAwaiter().GetResult méthode, car elle conserve les exceptions de tâche. Pour plus d’informations, consultez Async All the Way et Gestion des exceptions de tâche dans .NET 4.5.
  • Utilisez la méthode dans la ConfigureAwait mesure du possible pour créer du code sans contexte. Le code sans contexte offre de meilleures performances pour les applications mobiles et est une technique utile pour éviter l’interblocage lors de l’utilisation d’une base de code partiellement asynchrone. Pour plus d’informations, consultez Configurer le contexte.
  • Utilisez des tâches de continuation pour des fonctionnalités telles que la gestion des exceptions levées par l’opération asynchrone précédente et l’annulation d’une continuation avant son démarrage ou pendant son exécution. Pour plus d’informations, consultez Chaînage de tâches à l’aide de tâches continues.
  • Utilisez une implémentation asynchrone ICommand lorsque des opérations asynchrones sont appelées à partir du ICommand. Cela garantit que toutes les exceptions dans la logique de commande asynchrone peuvent être gérées. Pour plus d’informations, consultez Programmation asynchrone : modèles pour les applications MVVM asynchrones : commandes.

Choisir un conteneur d’injection de dépendances avec précaution

Les conteneurs d’injection de dépendances introduisent des contraintes de performances supplémentaires dans les applications mobiles. L’inscription et la résolution des types avec un conteneur ont un coût en termes de performances en raison de l’utilisation par le conteneur de la réflexion pour créer chaque type, et plus particulièrement si les dépendances sont reconstruites pour chaque navigation entre les pages de l’application. S’il existe de nombreuses dépendances ou des dépendances profondes, le coût de création peut augmenter de manière significative. En outre, l’inscription de type, qui se produit généralement au démarrage de l’application, peut avoir un impact notable sur le temps de démarrage selon le conteneur utilisé.

En guise d’alternative, l’injection de dépendances peut être rendue plus performante en l’implémentant manuellement à l’aide de fabriques.

Créer des applications d’interpréteur de commandes

Xamarin.Forms Les applications shell offrent une expérience de navigation avisée basée sur des menus volants et des onglets. Si l’expérience utilisateur de votre application peut être implémentée avec l’interpréteur de commandes, il est préférable de le faire. Les applications d’interpréteur de commandes permettent d’éviter une mauvaise expérience de démarrage, car les pages sont créées à la demande en réponse à la navigation plutôt qu’au démarrage de l’application, ce qui est le cas avec les applications qui utilisent un « TabbedPage ». Pour plus d’informations, consultez Xamarin.Forms Shell.

Utiliser CollectionView au lieu de ListView

CollectionView est une vue de présentation de listes de données à l’aide de différentes spécifications de disposition. Il offre une alternative plus flexible et plus performante à ListView. Pour plus d’informations, consultez Xamarin.Forms CollectionView.

Optimiser les performances de ListView

Lorsque vous utilisez ListView, un certain nombre d’expériences utilisateur doit être optimisé :

  • Initialisation : intervalle de temps qui commence quand le contrôle est créé et se termine quand les éléments sont affichés à l’écran.
  • Défilement : possibilité de faire défiler la liste et de vérifier que l’interface utilisateur est synchrone avec les entrées tactiles.
  • Interaction pour l’ajout, la suppression et la sélection d’éléments.

Le contrôle ListView requiert une application pour fournir des modèles de données et de cellules. Cette opération aura un impact important sur les performances du contrôle. Pour plus d’informations, consultez Performances de ListView.

Optimiser les ressources d’images

L’affichage de ressources d’images peut augmenter considérablement l’encombrement mémoire d’une application. Par conséquent, elles ne doivent être créées que si elles sont nécessaires, et doivent être libérées dès que l’application n’en a plus besoin. Par exemple, si une application affiche une image en lisant les données à partir d’un flux, vérifiez que ce flux est créé uniquement si nécessaire et qu’il est libéré quand il ne l’est plus. Pour cela, créez le flux quand la page est créée ou que l’événement Page.Appearing se déclenche, puis supprimez-le quand l’événement Page.Disappearing se déclenche.

Quand vous téléchargez une image à afficher avec la méthode ImageSource.FromUri, mettez en cache l’image téléchargée en vérifiant que la propriété UriImageSource.CachingEnabled a la valeur true. Pour plus d’informations, consultez Utilisation des images.

Pour plus d’informations, consultez Optimiser les ressources d’images.

Réduire la taille de l’arborescence d’éléments visuels

La réduction du nombre d’éléments dans une page accélère l’affichage de la page. Pour ce faire, il existe deux techniques principales. La première consiste à masquer les éléments qui ne sont pas visibles. La propriété IsVisible de chaque élément détermine si l’élément doit faire partie de l’arborescence d’éléments visuels ou pas. Par conséquent, si un élément n’est pas visible parce qu’il est masqué par d’autres éléments, supprimez l’élément ou affectez à sa propriété IsVisible la valeur false.

La seconde technique consiste à supprimer les éléments inutiles. Par exemple, l’exemple de code suivant illustre une mise en page contenant plusieurs objets Label :

<StackLayout>
    <StackLayout Padding="20,20,0,0">
        <Label Text="Hello" />
    </StackLayout>
    <StackLayout Padding="20,20,0,0">
        <Label Text="Welcome to the App!" />
    </StackLayout>
    <StackLayout Padding="20,20,0,0">
        <Label Text="Downloading Data..." />
    </StackLayout>
</StackLayout>

La même mise en page peut être maintenue avec un nombre réduit d’éléments, comme indiqué dans l’exemple de code suivant :

<StackLayout Padding="20,35,20,20" Spacing="25">
  <Label Text="Hello" />
  <Label Text="Welcome to the App!" />
  <Label Text="Downloading Data..." />
</StackLayout>

Réduire la taille du dictionnaire de ressources de l’application

Toutes les ressources qui sont utilisées dans l’application doivent être stockées dans le dictionnaire de ressources de l’application pour éviter la duplication. Cela permet de réduire la quantité de code XAML qui doit être analysé dans toute l’application. L’exemple de code suivant illustre la ressource HeadingLabelStyle, qui est utilisée au niveau de l’application et par conséquent définie dans le dictionnaire de ressources de l’application :

<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Resources.App">
     <Application.Resources>
         <ResourceDictionary>
            <Style x:Key="HeadingLabelStyle" TargetType="Label">
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="FontSize" Value="Large" />
                <Setter Property="TextColor" Value="Red" />
            </Style>
         </ResourceDictionary>
     </Application.Resources>
</Application>

Toutefois, le code XAML qui est spécifique à une page ne doit pas être inclus dans le dictionnaire de ressources de l’application, car les ressources sont alors analysées au démarrage de l’application et non lorsqu’une page le demande. Si une ressource est utilisée par une page qui n’est pas la page de démarrage, elle doit être placée dans le dictionnaire de ressources pour cette page, ce qui contribue à réduire le code XAML qui est analysé quand l’application démarre. L’exemple de code suivant illustre la ressource HeadingLabelStyle, qui figure uniquement dans une seule page et est par conséquent définie dans le dictionnaire de ressources de la page :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Test.HomePage"
             Padding="0,20,0,0">
    <ContentPage.Resources>
        <ResourceDictionary>
          <Style x:Key="HeadingLabelStyle" TargetType="Label">
              <Setter Property="HorizontalOptions" Value="Center" />
              <Setter Property="FontSize" Value="Large" />
              <Setter Property="TextColor" Value="Red" />
          </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

Pour plus d’informations sur les ressources d’application, consultez Styles XAML.

Utiliser le modèle de renderer personnalisé

La plupart des Xamarin.Forms classes de renderer exposent la OnElementChanged méthode , qui est appelée lorsqu’un Xamarin.Forms contrôle personnalisé est créé pour afficher le contrôle natif correspondant. Les classes de renderers personnalisés dans chaque projet de plateforme remplacent ensuite cette méthode pour instancier et personnaliser le contrôle natif. La méthode SetNativeControl est utilisée pour instancier le contrôle natif, et cette méthode attribue également la référence de contrôle à la propriété Control.

Toutefois, dans certains cas, la méthode OnElementChanged peut être appelée plusieurs fois. Par conséquent, pour éviter les fuites de mémoire qui peuvent avoir un impact sur les performances, vous devez être vigilant lors de l’instanciation d’un nouveau contrôle natif. L’approche à utiliser lors de l’instanciation d’un nouveau contrôle natif dans un renderer personnalisé est indiquée dans l’exemple de code suivant :

protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)
{
  base.OnElementChanged (e);

  if (e.OldElement != null)
  {
    // Unsubscribe from event handlers and cleanup any resources
  }

  if (e.NewElement != null)
  {
    if (Control == null)
    {
      // Instantiate the native control with the SetNativeControl method
    }
    // Configure the control and subscribe to event handlers
  }
}

Un nouveau contrôle natif doit uniquement être instancié une seule fois, quand la propriété Control a la valeur null. En outre, le contrôle doit être créé, configuré et les gestionnaires d’événements abonnés uniquement lorsque le convertisseur personnalisé est attaché à un nouvel Xamarin.Forms élément. De même, vous devez vous désabonner des gestionnaires d’événements auxquels vous vous êtes abonné uniquement quand l’élément auquel le renderer est attaché change. L’adoption de cette approche permet de créer un renderer personnalisé efficace qui ne connaît pas les fuites de mémoire.

Important

La méthode SetNativeControl ne doit être appelée que si la propriété e.NewElement n’est pas null, et si la propriété Control est null.

Pour plus d’informations sur les renderers personnalisés, consultez Personnalisation des contrôles sur chaque plateforme.