Partager via


ListView

Browse sample.Parcourez l’exemple. Parcourir l'exemple

.NET Multi-platform App UI (.NET MAUI) ListView affiche une liste verticale déroulante d’éléments de données sélectionnables. Tandis que ListView gère l’apparence de la liste, chaque élément de la liste est défini par un DataTemplate qui utilise un Cell pour l'affichage. .NET MAUI inclut cinq types de cellules pour afficher différentes combinaisons de textes et d’images. Vous pouvez également définir des cellules personnalisées qui affichent le contenu souhaité. ListView prend en charge l’affichage des en-têtes et pieds de page, des données groupées, de la fonction tirer-pour-rafraîchir et des éléments de menu contextuel.

Important

ListView a été déprécié, ainsi que EntryCell, ImageCell, SwitchCell, TextCell, et ViewCell. À la place, utilisez CollectionView.

Cell n’a pas été déprécié, car il est actuellement utilisé pour la génération de code source. Toutefois, il doit être considéré comme déconseillé.

La classe ListView dérive de la classe ItemsView<Cell>, dont elle hérite les propriétés suivantes :

  • ItemsSource, de type IEnumerable, spécifie la collection d’éléments à afficher et a une valeur par défaut de null.
  • ItemTemplate, de type DataTemplate, spécifie le modèle à appliquer à chaque élément de la collection d’éléments à afficher.

ListView définit les propriétés suivantes :

  • Footer, de type object, spécifie la chaîne ou la vue qui sera affichée à la fin de la liste.
  • FooterTemplate, de type DataTemplate, spécifie le DataTemplate à utiliser pour mettre en forme le Footer.
  • GroupHeaderTemplate, de type DataTemplate, définit le DataTemplate utilisé pour définir l’apparence de l’en-tête de chaque groupe. Cette propriété est mutuellement exclusive avec la propriété GroupDisplayBinding. Par conséquent, configurer cette propriété configurera GroupDisplayBinding sur null.
  • HasUnevenRows, de type bool, indique si les éléments de la liste peuvent avoir des lignes de hauteurs différentes. La valeur par défaut de cette propriété est false.
  • Header, de type object, spécifie la chaîne ou la vue qui sera affichée au début de la liste.
  • FooterTemplate, de type DataTemplate, spécifie le DataTemplate à utiliser pour mettre en forme le Footer.
  • HorizontalScrollBarVisibility, de type ScrollBarVisibility, indique le moment où la barre de défilement horizontale est visible.
  • IsGroupingEnabled, de type bool, indique si les données sous-jacentes doivent être affichées dans des groupes. La valeur par défaut de cette propriété est false.
  • IsPullToRefreshEnabled, de type bool, indique si l’utilisateur peut balayer l’écran vers le bas pour que le ListView actualise ses données. La valeur par défaut de cette propriété est false.
  • IsRefreshing, de type bool, indique si le ListView est en cours d'actualisation. La valeur par défaut de cette propriété est false.
  • RefreshCommand, de type ICommand, représente la commande qui sera exécutée lorsqu’une actualisation est provoquée.
  • RefreshControlColor, de type Color, détermine la couleur de la visualisation d’actualisation qui s’affiche lorsqu’une actualisation se produit.
  • RowHeight, de type int, détermine la hauteur de chaque ligne quand HasUnevenRows est false.
  • SelectedItem, de type object, représente l’élément actuellement sélectionné dans le ListView.
  • SelectionMode, de type ListViewSelectionMode, indique si les éléments peuvent être sélectionnés dans le ListView ou non. La valeur par défaut de cette propriété est .
  • SeparatorColor, de type Color, définit la couleur de la barre qui sépare les éléments de la liste.
  • SeparatorVisibility, de type SeparatorVisibility, définit si des séparateurs sont visibles entre les éléments.
  • VerticalScrollBarVisibility, de type ScrollBarVisibility, indique le moment où la barre de défilement verticale est visible.

Toutes ces propriétés sont soutenues par des objets BindableProperty, ce qui signifie qu'elles peuvent être ciblées par des liaisons de données et stylisées.

En outre, ListView définit les propriétés suivantes qui ne sont pas supportées par les objets BindableProperty :

  • GroupDisplayBinding, de type BindingBase, la liaison à utiliser pour afficher l'en-tête de groupe. Cette propriété est mutuellement exclusive avec la propriété GroupHeaderTemplate. Par conséquent, la définition de cette propriété définira GroupHeaderTemplate sur null.
  • GroupShortNameBinding, de type BindingBase, définit la liaison du nom à afficher dans les listes de raccourcis groupées.
  • , de type , définit la stratégie de réutilisation des cellules du . Il s’agit d’une propriété en lecture seule.

ListView définit les événements suivants :

  • ItemAppearing, qui est levé lorsque la représentation visuelle d’un élément est ajoutée à la mise en page visuelle du ListView. L’objet ItemVisibilityEventArgs qui accompagne cet événement définit les propriétés Item et Index.
  • ItemDisappearing, qui se déclenche lorsque la représentation visuelle d’un élément est en cours de suppression de la mise en page visuelle du ListView. L'objet ItemVisibilityEventArgs qui accompagne cet événement définit les propriétés Item et Index.
  • ItemSelected, qui se déclenche lorsque l’utilisateur sélectionne un nouvel élément de la liste. L'objet SelectedItemChangedEventArgs qui accompagne cet événement définit les propriétés SelectedItem et SelectedItemIndex.
  • ItemTapped, qui se déclenche lorsque l’utilisateur appuie sur un élément du ListView. L’objet ItemTappedEventArgs qui accompagne cet événement définit les propriétés Group, Item et ItemIndex.
  • Refreshing, qui se déclenche lorsque l’utilisateur lance une opération de balayage pour actualiser sur le ListView.
  • Scrolled, . L’objet ScrolledEventArgs qui accompagne cet événement définit les propriétés ScrollX et ScrollY.
  • ScrollToRequested . L'objet ScrollToRequestedEventArgs qui accompagne cet événement définit les propriétés Element, Mode, Position, ScrollX, ScrollY, et ShouldAnimate.

Remplir un ListView avec des données

Un ListView est rempli avec des données en définissant sa propriété ItemsSource sur n’importe quelle collection qui implémente IEnumerable.

Important

Si le doit être actualisé à mesure que des éléments sont ajoutés, supprimés ou modifiés dans la collection sous-jacente, cette dernière doit être une collection qui envoie des notifications de modification de propriété, comme .

ListView peut être rempli avec des données en utilisant la liaison de données pour lier sa propriété ItemsSource à une collection IEnumerable. En XAML, cela est réalisé avec l’extension de balisage Binding :

<ListView ItemsSource="{Binding Monkeys}" />

Le code C# équivalent est :

ListView listView = new ListView();
listView.SetBinding(ItemsView.ItemsSourceProperty,  static (MonkeysViewModel vm) => vm.Monkeys);

Dans cet exemple, la propriété ItemsSource est liée à la propriété Monkeys du viewmodel connecté.

Remarque

Vous pouvez activer les liaisons compilées pour améliorer les performances de liaison de données dans les applications .NET MAUI. Pour plus d’informations, consultez Liaisons compilées.

Pour plus d’informations sur la liaison de données, consultez Liaison de données.

Définir l’apparence de l’élément

L'apparence de chaque élément dans la ListView peut être définie en ajustant la propriété ItemTemplate à un DataTemplate :

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="models:Monkey">
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Les éléments spécifiés dans un DataTemplate définissent l’apparence de chaque élément de la liste, et un enfant du DataTemplate doit être un objet Cell. Dans l’exemple, la disposition dans le est gérée par un . Grid contient un objet Image et deux objets Label qui sont tous liés aux propriétés de la classe Monkey :

public class Monkey
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

La capture d’écran suivante montre le résultat de la modélisation de chaque élément de la liste :

Screenshot of ListView where each item is templated.Capture d’écran d’un ListView où chaque élément est basé sur un modèle.

Pour plus d'informations sur les modèles de données, consultez Modèles de données.

Cellules

L’apparence de chaque élément d'un ListView est définie par un DataTemplate, et le DataTemplate doit référencer une classe Cell pour afficher les éléments. Chaque cellule représente une donnée dans le ListView. .NET MAUI inclut les cellules intégrées suivantes :

  • TextCell, qui affiche du texte principal et du texte secondaire sur des lignes distinctes.
  • ImageCell, qui affiche une image avec le texte principal et le texte secondaire sur des lignes distinctes.
  • SwitchCell, qui affiche du texte et un commutateur pouvant être activé ou désactivé.
  • EntryCell, qui affiche une étiquette et un texte modifiable.
  • , qui est une cellule personnalisée dont l’apparence est définie par . Utilisez ce type de cellule si vous souhaitez définir entièrement l'apparence de chaque élément dans ListView.

En général, SwitchCell et EntryCell sont uniquement utilisés dans un TableView et ne sont pas utilisés dans un ListView. Pour en savoir plus sur SwitchCell et EntryCell, consultez TableView.

Cellule de texte

Un TextCell affiche le texte principal et le texte secondaire sur des lignes distinctes. TextCell définit les propriétés suivantes :

  • Text, de type string, définit le texte principal à afficher.
  • TextColor, de type Color, représente la couleur du texte principal.
  • Detail, de type string, définit le texte secondaire à afficher.
  • DetailColor, de type Color, indique la couleur du texte secondaire.
  • Command, de type ICommand, définit la commande exécutée lorsque la cellule est tapée.
  • CommandParameter, de type object, représente le paramètre passé à la commande.

Les propriétés s'appuient sur des objets BindableProperty, ce qui signifie qu'elles peuvent être les cibles de liaisons de données et être stylisées.

L’exemple suivant montre comment utiliser un TextCell pour définir l’apparence des éléments dans un ListView :

<ListView ItemsSource="{Binding Food}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:FoodItem">
            <TextCell Text="{Binding Name}"
                      Detail="{Binding Description}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

La capture d’écran suivante montre l’apparence des cellules obtenue :

Capture d’écran d’un ListView dont chaque élément est une TextCell.Capture d’écran d’un ListView où chaque élément est une TextCell.

Cellule d’image

Un ImageCell affiche une image avec le texte principal et le texte secondaire sur des lignes distinctes. ImageCell hérite des propriétés de TextCell et définit la propriété ImageSource, de type ImageSource, qui spécifie l’image à afficher dans la cellule. Cette propriété s’appuie sur un objet BindableProperty, ce qui signifie qu’elle peut être la cible de liaisons de données et être stylisée.

L’exemple suivant montre comment utiliser un ImageCell pour définir l’apparence des éléments dans un ListView :

<ListView ItemsSource="{Binding Food}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:FoodItem">
            <ImageCell ImageSource="{Binding Image}"
                       Text="{Binding Name}"
                       Detail="{Binding Description}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

La capture d’écran suivante montre l’apparence des cellules obtenue :

Screenshot of ListView where each item is an ImageCell.Capture d’écran de ListView où chaque élément est un ImageCell.

Vue de la cellule

Un ViewCell est une cellule personnalisée dont l'apparence est définie par un View. ViewCell définit une propriété View, de type View, qui indique la vue représentant le contenu de la cellule. Cette propriété s’appuie sur un objet BindableProperty, ce qui signifie qu’elle peut être la cible de liaisons de données et être stylisée.

Remarque

La propriété View est la propriété de contenu de la classe ViewCell, et n'a donc pas besoin d'être définie explicitement dans le XAML.

L’exemple suivant montre comment utiliser un pour définir l’apparence d’éléments dans un :

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="models:Monkey">
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

À l'intérieur du ViewCell, la disposition peut être gérée par tout agencement .NET MAUI. Dans cet exemple, la disposition est gérée par un Grid. Grid contient un objet Image et deux objets Label qui sont tous liés aux propriétés de la classe Monkey.

La capture d’écran suivante montre le résultat de la modélisation de chaque élément de la liste :

Screenshot of ListView where each item is templated with a ViewCell.Capture d’écran d’un ListView dont chaque élément est basé sur une ViewCell.

Choisir l’apparence de l’élément au moment de l’exécution

Vous pouvez choisir l’apparence de chaque élément dans ListView au moment de l’exécution, en fonction de la valeur de l’élément, en définissant la propriété ItemTemplate sur un objet DataTemplateSelector :

<ContentPage ...
             xmlns:templates="clr-namespace:ListViewDemos.Templates"
             xmlns:viewmodels="clr-namespace:ListViewDemos.ViewModels"
             x:DataType="viewmodels:MonkeysViewModel">
    <ContentPage.Resources>
        <DataTemplate x:Key="AmericanMonkeyTemplate"
                      x:DataType="models:Monkey">
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>

        <DataTemplate x:Key="OtherMonkeyTemplate"
                      x:DataType="models:Monkey">
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>

        <templates:MonkeyDataTemplateSelector x:Key="MonkeySelector"
                                             AmericanMonkey="{StaticResource AmericanMonkeyTemplate}"
                                             OtherMonkey="{StaticResource OtherMonkeyTemplate}" />
    </ContentPage.Resources>

    <Grid Margin="20">
        <ListView ItemsSource="{Binding Monkeys}"
                  ItemTemplate="{StaticResource MonkeySelector}" />
    </Grid>
</ContentPage>

La propriété ItemTemplate est définie sur un objet MonkeyDataTemplateSelector. L'exemple suivant présente la classe MonkeyDataTemplateSelector :

public class MonkeyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate AmericanMonkey { get; set; }
    public DataTemplate OtherMonkey { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return ((Monkey)item).Location.Contains("America") ? AmericanMonkey : OtherMonkey;
    }
}

La classe MonkeyDataTemplateSelector définit les propriétés AmericanMonkey et OtherMonkeyDataTemplate qui sont assignées à différents modèles de données. Le remplacement OnSelectTemplate retourne le modèle AmericanMonkey, qui affiche le nom et l’emplacement du singe en sarcelle, lorsque le nom du singe contient « America ». Si le nom du singe ne contient pas « America », le remplacement OnSelectTemplate retourne le modèle OtherMonkey, qui affiche le nom et l’emplacement du singe en gris argenté :

Capture d’écran de la sélection du modèle d’élément à l'exécution de ListView.

Pour plus d’informations sur les sélecteurs de modèles de données, consultez « Créer un DataTemplateSelector ».

Répondre à la sélection d’un élément

Par défaut, la sélection est activée. Cependant, vous pouvez modifier ce comportement en définissant la propriété SelectionMode. L'énumération ListViewSelectionMode définit les membres suivants :

  • None : indique que les éléments ne peuvent pas être sélectionnés.
  • Single : indique qu’un seul élément peut être sélectionné, et que cet élément sera mis en surbrillance. Il s’agit de la valeur par défaut.

ListView définit un événement ItemSelected qui est déclenché lorsque la propriété SelectedItem change, soit parce qu'un utilisateur sélectionne un élément dans la liste, soit parce qu'une application configure la propriété. L'objet SelectedItemChangedEventArgs qui accompagne cet événement a des propriétés SelectedItem et SelectedItemIndex.

Lorsque la propriété SelectionMode est définie sur Single, un seul élément dans ListView peut être sélectionné. Lorsqu’un élément est sélectionné, la propriété SelectedItem est définie sur la valeur de l’élément sélectionné. Lorsque cette propriété change, l'événement ItemSelected se déclenche.

L’exemple suivant montre un ListView qui peut répondre à une sélection d’élément unique :

<ListView ItemsSource="{Binding Monkeys}"
          ItemSelected="OnItemSelected">
    ...
</ListView>

Dans cet exemple, le gestionnaire d’événements OnItemSelected s’exécute lorsque l’événement ItemSelected se déclenche, et il récupère l’élément sélectionné :

void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
{
    Monkey item = args.SelectedItem as Monkey;
}

La capture d’écran suivante montre la sélection d'un seul élément dans un ListView :

Capture d’écran d’un ListView avec une sélection.Capture d’écran d’un ListView avec une sélection.

Effacer la sélection

La propriété SelectedItem peut être effacée en la définissant (ou en définissant l'objet auquel elle est liée) sur null.

Désactiver la sélection

La sélection ListView est activée par défaut. Cependant, il peut être désactivé en définissant la propriété SelectionMode sur None :

<ListView ...
          SelectionMode="None" />

Lorsque la propriété SelectionMode est définie sur None, les éléments dans le ListView ne peuvent pas être sélectionnés, la propriété SelectedItem reste null et l’événement ItemSelected ne se déclenche pas.

Données de cache

ListView est une vue puissante pour l’affichage des données, mais elle présente certaines limitations. Les performances de défilement peuvent souffrir lors de l’utilisation de cellules personnalisées, en particulier lorsqu’elles contiennent des hiérarchies d’affichage profondément imbriquées ou utilisent certaines dispositions qui nécessitent une mesure complexe. Heureusement, certains techniques vous permettent d’éviter les problèmes de performance.

Un(e) ListView est souvent utilisé(e) pour afficher beaucoup plus de données que ce que l'écran peut afficher. Par exemple, une application musicale peut avoir une bibliothèque de chansons avec des milliers d’entrées. La création d’un élément pour chaque entrée gaspille une mémoire précieuse et fonctionne mal. La création et la destruction de lignes nécessitent constamment que l’application instancie et nettoie constamment les objets, ce qui fonctionne également mal.

Pour économiser la mémoire, les équivalents natifs ListView de chaque plateforme ont des fonctionnalités intégrées pour réutiliser les lignes. Seules les cellules visibles à l’écran sont chargées en mémoire. Le contenu est chargé dans les cellules existantes. Ce modèle empêche l’application d’instancier des milliers d’objets, afin d’économiser du temps et de la mémoire.

.NET MAUI autorise la réutilisation des cellules ListView au travers de l'énumération ListViewCachingStrategy, qui définit les membres suivants :

  • RetainElement, précise que le ListView va générer une cellule pour chaque élément de la liste.
  • RecycleElement, spécifie que le ListView va tenter de réduire son empreinte mémoire et son temps d'exécution en recyclant les cellules de liste.
  • RecycleElementAndDataTemplate, de la même manière que RecycleElement, assure que lorsque un ListView utilise un DataTemplateSelector, les objets DataTemplate sont mis en cache selon le type d'élément contenu dans la liste.

Conserver les éléments

La stratégie de mise en cache RetainElement spécifie que le ListView générera une cellule pour chaque élément de la liste, ce qui constitue le comportement par défaut ListView. Il doit être utilisé dans les circonstances suivantes :

  • Chaque cellule a un grand nombre de liaisons (de 20 à + de 30).
  • Le modèle de cellule change fréquemment.
  • Les tests révèlent que la stratégie de mise en cache RecycleElement entraîne une vitesse d'exécution réduite.

Il est important de reconnaître les conséquences de la stratégie de mise en cache RetainElement lors de l’utilisation de cellules personnalisées. Tout code d’initialisation de cellule doit s’exécuter pour chaque création de cellule, qui peut être de plusieurs fois par seconde. Dans ce cas, les techniques de disposition qui étaient correctes sur une page, comme l’utilisation de plusieurs objets imbriqués Grid, deviennent des goulots d’étranglement en matière de performances lorsqu’elles sont configurées et détruites en temps réel pendant que l’utilisateur fait défiler l’écran.

Éléments de recyclage

La stratégie de mise en cache RecycleElement spécifie que le ListView va tenter de minimiser son empreinte mémoire et d'améliorer sa vitesse d'exécution en recyclant les cellules de la liste. Ce mode n’offre pas toujours d’amélioration des performances. Vous devez mener des tests pour déterminer les améliorations. Toutefois, il s’agit du choix privilégié, qui doit être utilisé dans les circonstances suivantes :

  • Chaque cellule a un petit nombre modéré de liaisons.
  • Le BindingContext de chaque cellule définit toutes les données de la cellule.
  • Chaque cellule est très similaire, le modèle de cellule étant le même.

Pendant la virtualisation, le contexte de liaison de la cellule est mis à jour. Par conséquent, si une application utilise ce mode, elle doit s’assurer que les mises à jour du contexte de liaison sont correctement gérées. Toutes les données relatives à la cellule doivent provenir du contexte de liaison, sous peine d’erreurs de cohérence. Ce problème peut être évité en utilisant la liaison de données pour afficher les données de cellule. Les données de cellule doivent être définies dans la dérogation OnBindingContextChanged, plutôt que dans le constructeur de cellule personnalisée, comme le montre l'exemple suivant :

public class CustomCell : ViewCell
{
    Image image = null;

    public CustomCell()
    {
        image = new Image();
        View = image;
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        var item = BindingContext as ImageItem;
        if (item != null)
        {
            image.Source = item.ImageUrl;
        }
    }
}

Recycler des éléments avec un DataTemplateSelector

Lorsqu’un ListView utilise un DataTemplateSelector pour sélectionner un DataTemplate, la stratégie de mise en cache RecycleElement ne met pas en cache les objets DataTemplate. Au lieu de cela, un DataTemplate est sélectionné pour chaque élément de données de la liste.

Remarque

La stratégie de mise en cache RecycleElement requiert que lorsqu’un DataTemplateSelector est invité à sélectionner un DataTemplate, chaque DataTemplate doit retourner le même type ViewCell. Prenons l’exemple d’un ListView avec un DataTemplateSelector pouvant retourner MyDataTemplateA (où MyDataTemplateA retourne un ViewCell de type MyViewCellA) ou MyDataTemplateB (où MyDataTemplateB retourne un ViewCell de type MyViewCellB), lorsque MyDataTemplateA est retourné, il doit retourner MyViewCellA, sous peine de générer une exception.

Recycler des éléments avec un DataTemplates

La stratégie de mise en cache RecycleElementAndDataTemplate s’appuie sur la stratégie de mise en cache RecycleElement en s’assurant que lorsqu’un ListView utilise un DataTemplateSelector pour sélectionner un DataTemplate, les objets DataTemplate sont mis en cache selon le type d’élément dans la liste. Par conséquent, les objets DataTemplate sont sélectionnés une fois par type d’élément, plutôt qu’une fois par instance d’élément.

Remarque

La stratégie de mise en cache RecycleElementAndDataTemplate nécessite que les objets DataTemplate retournés par le DataTemplateSelector utilisent le constructeur DataTemplate qui prend un Type.

Définir la stratégie de mise en cache

La ListView stratégie de mise en cache peut être définie en XAML en configurant l’attribut CachingStrategy :

<ListView CachingStrategy="RecycleElement">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
              ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

En C#, la stratégie de mise en cache est définie au travers d’une surcharge du constructeur :

ListView listView = new ListView(ListViewCachingStrategy.RecycleElement);

Définir la stratégie de mise en cache dans un ListView sous-classé

La définition de l'attribut Attribute à partir de XAML sur un SubclassedObject ne produira pas le comportement désiré, car il n'existe pas de propriété Property sur MainClass. La solution à ce problème consiste à spécifier un constructeur sur le classé en sous-classe ListView qui accepte un paramètre de ListViewCachingStrategy et le transmet à la classe de base.

public class CustomListView : ListView
{
    public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
    {
    }
    ...
}

Ensuite, la valeur d'énumération ListViewCachingStrategy peut être spécifiée à partir du XAML à l'aide de l'attribut x:Arguments :

<local:CustomListView>
    <x:Arguments>
        <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
    </x:Arguments>
</local:CustomListView>

En-têtes et pieds de page

ListView peut présenter un en-tête et un pied de page qui défilent avec les éléments de la liste. L’en-tête et le pied de page peuvent être des chaînes, des vues ou des objets DataTemplate.

ListView définit les propriétés suivantes pour spécifier l’en-tête et le pied de page :

  • Header, de type object, indique la chaîne, la liaison ou la vue qui sera affichée au début de la liste.
  • FooterTemplate, de type DataTemplate, spécifie le DataTemplate à utiliser pour formater le Footer.
  • Footer, de type object, spécifie la chaîne, la liaison ou la vue qui sera affichée à la fin de la liste.
  • FooterTemplate, de type DataTemplate, spécifie le DataTemplate à utiliser pour mettre en forme le Footer.

Les propriétés s'appuient sur des objets BindableProperty, ce qui signifie qu'elles peuvent être les cibles de liaisons de données.

Les propriétés Header et Footer peuvent être définies sur des valeurs string, comme illustré dans l’exemple suivant :

<ListView ItemsSource="{Binding Monkeys}"
          Header="Monkeys"
          Footer="2022">
    ...
</ListView>

La capture d’écran suivante montre l’en-tête obtenu :

Screenshot of a ListView string header.Capture d’écran d’un en-tête de chaîne ListView.

Les propriétés Header et Footer peuvent chacune être définies sur une vue. Il peut s’agir d’une vue unique ou d’une vue contenant plusieurs vues enfants. L'exemple suivant montre les propriétés Header et Footer attribuées à un objet Grid qui contient un objet Label :

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.Header>
        <Grid BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Monkeys"
                   FontSize="12"
                   FontAttributes="Bold" />
        </Grid>
    </ListView.Header>
    <ListView.Footer>
        <Grid BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Friends of Monkey"
                   FontSize="12"
                   FontAttributes="Bold" />
        </Grid>
    </ListView.Footer>
    ...
</ListView>

La capture d’écran suivante montre l’en-tête obtenu :

Capture d’écran de l’en-tête et du pied de page de CollectionView avec des vues.Capture d’écran de l’en-tête et du pied de page de CollectionView avec des vues.

Les propriétés HeaderTemplate et FooterTemplate peuvent être définies sur des objets DataTemplate utilisés pour formater l'en-tête et le pied de page. Dans ce scénario, les propriétés Header et Footer doivent être liées à la source actuelle pour que les modèles soient appliqués, comme illustré dans l’exemple suivant :

<ListView ItemsSource="{Binding Monkeys}"
          Header="{Binding .}"
          Footer="{Binding .}">
    <ListView.HeaderTemplate>
        <DataTemplate>
            <Grid BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Monkeys"
                       FontSize="12"
                       FontAttributes="Bold" />
            </Grid>
        </DataTemplate>
    </ListView.HeaderTemplate>
    <ListView.FooterTemplate>
        <DataTemplate>
            <Grid BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Friends of Monkey"
                       FontSize="12"
                       FontAttributes="Bold" />
            </Grid>
        </DataTemplate>
    </ListView.FooterTemplate>
    ...
</ListView>

Séparateurs d’éléments de contrôle

Par défaut, des séparateurs s’affichent entre les éléments sur iOS et Android. Ce comportement peut être modifié en définissant la propriété SeparatorVisibility, de type SeparatorVisibility, à None :

<ListView ...
          SeparatorVisibility="None" />

En outre, lorsque le séparateur est activé, sa couleur peut être définie avec la propriété SeparatorColor.

<ListView ...
          SeparatorColor="Blue" />

Dimensionner les éléments

Par défaut, tous les éléments d’un ListView ont la même hauteur, qui est dérivée du contenu du DataTemplate qui définit l’apparence de chaque élément. Toutefois, vous pouvez modifier ce comportement avec les propriétés et . Par défaut, la HasUnevenRows propriété est false.

Vous pouvez définir la propriété RowHeight sur un int qui représente la hauteur de chaque élément dans le ListView, à condition que HasUnevenRows soit false. Quand HasUnevenRows est défini sur true, chaque élément de ListView peut avoir une hauteur différente. La hauteur de chaque élément sera dérivée du contenu de l'élément DataTemplate, et ainsi chaque élément sera dimensionné selon son contenu.

Vous pouvez redimensionner par programmation des éléments ListView individuels au moment de l’exécution en modifiant les propriétés liées à la disposition des éléments dans le DataTemplate, à condition que la propriété HasUnevenRows soit true. L'exemple suivant modifie la hauteur d'un objet Image lorsqu'il est tapé :

void OnImageTapped(object sender, EventArgs args)
{
    Image image = sender as Image;
    ViewCell viewCell = image.Parent.Parent as ViewCell;

    if (image.HeightRequest < 250)
    {
      image.HeightRequest = image.Height + 100;
      viewCell.ForceUpdateSize();
    }
}

Dans cet exemple, le gestionnaire d'événements OnImageTapped est exécuté en réponse à un objet Image sur lequel l'utilisateur a appuyé. Le gestionnaire d’événements met à jour la hauteur du Image et la méthode Cell.ForceUpdateSize met à jour la taille de la cellule, même lorsque la cellule n'est pas visible.

Avertissement

L’utilisation excessive du dimensionnement dynamique des éléments peut entraîner une dégradation des performances de ListView.

Mise en page de droite à gauche

ListView peut organiser son contenu dans une direction de flux de droite à gauche en définissant sa propriété FlowDirection sur RightToLeft. Cependant, la propriété FlowDirection doit idéalement être définie sur une page ou une disposition racine, ce qui permet à tous les éléments de la page ou de la disposition racine de s'adapter à la direction du flux.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:viewmodels="clr-namespace:ListViewDemos.ViewModels"
             x:Class="ListViewDemos.RightToLeftListPage"
             Title="Right to left list"
             FlowDirection="RightToLeft"
             x:DataType="viewmodels:MonkeysViewModel">
    <Grid Margin="20">
        <ListView ItemsSource="{Binding Monkeys}">
            ...
        </ListView>
    </Grid>
</ContentPage>

La valeur par défaut FlowDirection pour un élément avec un parent est MatchParent. Par conséquent, le ListView hérite de la valeur de la propriété FlowDirection de Grid, qui hérite à son tour de la valeur de la propriété FlowDirection de ContentPage.

Afficher les données groupées

Les jeux de données volumineux sont souvent difficiles à gérer lorsqu’ils sont présentés dans une liste de défilement continue. Dans ce scénario, l’organisation des données en groupes peut améliorer l’expérience utilisateur en facilitant la navigation dans les données.

Les données doivent être regroupées avant de pouvoir être affichées. Pour ce faire, créez une liste de groupes, où chaque groupe est une liste d’éléments. La liste des groupes doit être une IEnumerable<T> collection, où T définit deux éléments de données :

  • Un nom de groupe.
  • Une IEnumerable collection qui définit les éléments appartenant au groupe.

Le processus de regroupement des données consiste donc à :

  • Créer un type qui modélise un élément unique.
  • Créez un type qui modélise un groupe d’éléments unique.
  • Créez une collection IEnumerable<T>, où T est le type qui modélise un groupe d’éléments unique. Cette collection est une collection de groupes qui stocke les données groupées.
  • Ajouter des données à la collection IEnumerable<T>.

Exemple

Lors du regroupement de données, la première étape consiste à créer un type qui modélise un élément unique. L’exemple suivant montre la classe Animal.

public class Animal
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

La classe Animal modélise un élément unique. Un type qui modélise un groupe d’éléments peut ensuite être créé. L’exemple suivant présente la classe AnimalGroup:

public class AnimalGroup : List<Animal>
{
    public string Name { get; private set; }

    public AnimalGroup(string name, List<Animal> animals) : base(animals)
    {
        Name = name;
    }
}

La classe AnimalGroup hérite de la classe List<T> et ajoute une propriété Name qui représente le nom du groupe.

Une IEnumerable<T> collection de groupes peut ensuite être créée :

public List<AnimalGroup> Animals { get; private set; } = new List<AnimalGroup>();

Ce code définit une collection nommée Animals, où chaque élément de la collection est un objet AnimalGroup. Chaque objet comprend un nom et une collection qui définit les objets du groupe.

Les données groupées peuvent ensuite être ajoutées à la collection Animals :

Animals.Add(new AnimalGroup("Bears", new List<Animal>
{
    new Animal
    {
        Name = "American Black Bear",
        Location = "North America",
        Details = "Details about the bear go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/08/01_Schwarzbär.jpg"
    },
    new Animal
    {
        Name = "Asian Black Bear",
        Location = "Asia",
        Details = "Details about the bear go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG/180px-Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG"
    },
    // ...
}));

Animals.Add(new AnimalGroup("Monkeys", new List<Animal>
{
    new Animal
    {
        Name = "Baboon",
        Location = "Africa & Asia",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
    },
    new Animal
    {
        Name = "Capuchin Monkey",
        Location = "Central & South America",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
    },
    new Animal
    {
        Name = "Blue Monkey",
        Location = "Central and East Africa",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
    },
    // ...
}));

Ce code crée deux groupes dans la collection Animals. Le premier AnimalGroup est nommé Bears et contient une collection List<Animal> de détails « Bear ». Le second AnimalGroup est nommé Monkeys, et contient un ensemble de détails des singes.

ListView affichera les données regroupées, à condition que celles-ci aient été correctement groupées, en définissant la propriété IsGroupingEnabled à true :

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="True">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="models:Animal">
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Le code C# équivalent est :

ListView listView = new ListView
{
    IsGroupingEnabled = true
};
listView.SetBinding(ItemsView.ItemsSourceProperty, static (AnimalsViewModel vm) => vm.Animals);
// ...

L’apparence de chaque élément dans ListView est définie en réglant sa propriété ItemTemplate sur un DataTemplate. Pour plus d'informations, consultez Définir l'apparence des éléments.

La capture d’écran suivante montre le ListView affichant les données groupées :

Capture d’écran des données groupées dans un ListView.

Remarque

Par défaut, ListView affiche le nom du groupe dans l’en-tête du groupe. Vous pouvez modifier ce comportement en personnalisant l’en-tête de groupe.

Personnaliser l’en-tête de groupe

Vous pouvez personnaliser l’apparence de chaque en-tête de groupe en définissant la propriété ListView.GroupHeaderTemplate sur un DataTemplate :

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="True">
    <ListView.GroupHeaderTemplate>
        <DataTemplate x:DataType="models:AnimalGroup">
            <ViewCell>
                <Label Text="{Binding Name}"
                       BackgroundColor="LightGray"
                       FontSize="18"
                       FontAttributes="Bold" />
            </ViewCell>
        </DataTemplate>
    </ListView.GroupHeaderTemplate>
    ...
</ListView>

Dans cet exemple, chaque en-tête de groupe est défini sur un Label qui affiche le nom de groupe et qui a d’autres propriétés d’apparence définies. La capture d’écran suivante montre l’en-tête de groupe personnalisée :

Capture d’écran d’un en-tête de groupe personnalisé dans un ListView.Capture d’écran d’un en-tête de groupe personnalisé dans un ListView.

Important

La propriété GroupHeaderTemplate s'exclut mutuellement avec la propriété GroupDisplayBinding. Par conséquent, les deux propriétés ne doivent pas être définies.

Grouper sans modèles

ListView peut afficher correctement les données regroupées sans définir la propriété ItemTemplate sur un DataTemplate :

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="true" />

Dans ce scénario, des données significatives peuvent être affichées en remplaçant la méthode ToString dans le type qui modélise un élément unique, ainsi que dans le type qui modélise un groupe d'éléments.

Contrôler le défilement

ListView définit deux méthodes ScrollTo qui permettent de faire défiler les éléments dans la vue. L'une des surcharges fait défiler l'élément spécifié à l'écran, tandis que l'autre fait défiler l'élément spécifié dans le groupe spécifié vers le champ de vision. Les deux surcharges ont des arguments supplémentaires qui permettent de spécifier la position exacte de l'élément après que le défilement est terminé et de déterminer s'il faut animer le défilement.

ListView définit un événement ScrollToRequested déclenché lorsqu’une des méthodes ScrollTo est appelée. L'objet ScrollToRequestedEventArgs qui accompagne l'événement ScrollToRequested a de nombreuses propriétés, notamment ShouldAnimate, Element, Mode, et Position. Certaines de ces propriétés sont définies à partir des arguments spécifiés dans les appels de méthode ScrollTo.

En outre, ListView définit un événement Scrolled qui est déclenché pour indiquer que le défilement s’est produit. L'objet ScrolledEventArgs qui accompagne l'événement Scrolled a les propriétés ScrollX et ScrollY.

Détecter le défilement

ListView définit un événement Scrolled qui est déclenché pour indiquer qu'un défilement s'est produit. La classe ItemsViewScrolledEventArgs, qui représente l'objet qui accompagne l'événement Scrolled, définit les propriétés suivantes :

  • ScrollX, de type double, indique la position X du défilement.
  • , de type , représente la position Y du défilement.

L’exemple de XAML suivant montre un ListView qui définit un gestionnaire d’événements pour l’événement Scrolled :

<ListView Scrolled="OnListViewScrolled">
    ...
</ListView>

Le code C# équivalent est :

ListView listView = new ListView();
listView.Scrolled += OnListViewScrolled;

Dans cet exemple, le gestionnaire d’événements OnListViewScrolled s’exécute lorsque l’événement Scrolled se déclenche :

void OnListViewScrolled(object sender, ScrolledEventArgs e)
{
    // Custom logic
}

Important

L’événement Scrolled est déclenché pour les défilements initiés par l’utilisateur et les défilements programmatiques.

Faire défiler un élément dans la vue

La méthode ScrollTo fait défiler l’élément spécifié pour le rendre visible. Pour un objet ListView nommé listView, l'exemple suivant montre comment faire défiler l'élément "Proboscis Monkey" dans la vue.

MonkeysViewModel viewModel = BindingContext as MonkeysViewModel;
Monkey monkey = viewModel.Monkeys.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, ScrollToPosition.MakeVisible, true);

Vous pouvez également faire défiler un élément dans les données groupées dans la vue en spécifiant l’élément et le groupe. L’exemple suivant montre comment faire défiler l’élément Proboscis Monkey du groupe Monkeys pour le rendre visible :

GroupedAnimalsViewModel viewModel = BindingContext as GroupedAnimalsViewModel;
AnimalGroup group = viewModel.Animals.FirstOrDefault(a => a.Name == "Monkeys");
Animal monkey = group.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, group, ScrollToPosition.MakeVisible, true);

Remarque

L’événement ScrollToRequested se déclenche lorsque la méthode ScrollTo est appelée.

Désactiver l’animation de défilement

Une animation de défilement s’affiche lors du défilement d’un élément dans la vue. Toutefois, cette animation peut être désactivée en définissant l'argument animated de la méthode ScrollTo sur false :

listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: false);

Contrôler la position de défilement

Lors du défilement d’un élément dans la vue, la position exacte de l’élément une fois le défilement terminé peut être spécifiée avec l’argument position des méthodes ScrollTo. Cet argument accepte un membre d'énumération ScrollToPosition.

RendreVisible

Le membre ScrollToPosition.MakeVisible indique que l'élément doit être défilé jusqu'à ce qu'il soit visible dans la vue :

listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: true);

Démarrer

Le membre ScrollToPosition.Start indique que l'élément doit faire l'objet d'un défilement jusqu'au début de la vue :

listView.ScrollTo(monkey, position: ScrollToPosition.Start, animate: true);

Centrer

Le membre ScrollToPosition.Center indique que l’élément doit être faire l’objet d’un défilement jusqu’au centre de la vue :

listView.ScrollTo(monkey, position: ScrollToPosition.Center, animate: true);

Fin

Le membre ScrollToPosition.End indique que l’élément doit être défilé jusqu’à la fin de la vue.

listView.ScrollTo(monkey, position: ScrollToPosition.End, animate: true);

Visibilité de la barre de défilement

ListView définit les propriétés HorizontalScrollBarVisibility et VerticalScrollBarVisibility qui s’appuient sur des propriétés pouvant être liées. Ces propriétés obtiennent ou définissent une valeur d'énumération ScrollBarVisibility qui détermine le moment où la barre de défilement horizontale ou verticale est visible. L’énumération ListViewSelectionMode définit les membres suivants :

  • indique le comportement de la barre de défilement par défaut pour la plateforme, et constitue la valeur par défaut des propriétés et .
  • Always indique que la barre de défilement est visible même si le contenu correspond à l’affichage.
  • Never indique que les barres de défilement ne seront pas visibles, même si le contenu ne tient pas dans la vue.

Ajouter des menus contextuels

ListView prend en charge les éléments de menu contextuel, qui sont définis comme des objets MenuItem ajoutés à la collection ViewCell.ContextActions dans le DataTemplate pour chaque élément :

<ListView x:Name="listView"
          ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="models:Monkey">
            <ViewCell>
                <ViewCell.ContextActions>
                    <MenuItem Text="Favorite"
                              Command="{Binding x:DataType='viewmodels:MonkeysViewModel', Source={RelativeSource AncestorType={x:Type viewmodels:MonkeysViewModel}}, Path=FavoriteCommand}"
                              CommandParameter="{Binding}" />
                    <MenuItem Text="Delete"
                              Command="{Binding x:DataType='viewmodels:MonkeysViewModel', Source={RelativeSource AncestorType={x:Type viewmodels:MonkeysViewModel}}, Path=DeleteCommand}"
                              CommandParameter="{Binding}" />
                </ViewCell.ContextActions>

                ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Les objets MenuItem sont révélés lorsque l’utilisateur clique avec le bouton droit sur un élément du ListView :

Capture d’écran des éléments du menu contextuel de CollectionView.Capture d’écran des éléments du menu contextuel de CollectionView.

Pour plus d’informations sur les éléments de menu, consultez Afficher les éléments de menu.

Tirer pour actualiser

ListView prend en charge la fonctionnalité de tirer pour actualiser, ce qui permet d’actualiser les données affichées en tirant la liste d’éléments vers le bas.

Pour activer la fonctionnalité de glisser pour rafraîchir, définissez la propriété IsPullToRefreshEnabled sur true. Lorsqu'une actualisation est déclenchée, ListView génère l'événement Refreshing, et la propriété IsRefreshing est définie sur true. Le code requis pour actualiser le contenu du ListView doit être exécuté par le gestionnaire de l’événement Refreshing, ou par l’implémentation ICommand que RefreshCommand exécute. Une fois ListView actualisé, la propriété IsRefreshing doit être définie sur false, ou la méthode EndRefresh doit être appelée sur le ListView pour indiquer que l’actualisation est terminée.

L’exemple suivant montre un ListView qui utilise le glisser pour rafraîchir :

<ListView ItemsSource="{Binding Animals}"
          IsPullToRefreshEnabled="true"
          RefreshCommand="{Binding RefreshCommand}"
          IsRefreshing="{Binding IsRefreshing}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="models:Animal">
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Dans cet exemple, lorsque l'utilisateur initie une actualisation, le ICommand défini par la propriété RefreshCommand est exécuté, ce qui devrait rafraîchir les éléments affichés. Une visualisation d’actualisation, qui se compose d’un cercle de progression animé, s’affiche pendant l’actualisation. La valeur de la propriété IsRefreshing indique l'état actuel de l'opération de rafraîchissement. Quand une actualisation est déclenchée, cette propriété passe automatiquement à true. Une fois l'actualisation terminée, vous devez rétablir la propriété à false.