Partager via


ListView

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. Alors que ListView gère l’apparence de la liste, DataTemplate définit l’apparence de chaque élément de la liste en utilisant un Cell pour les afficher. .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 d’éléments d’en-tête et de pied de page, de données groupées, de balayage pour actualiser et de menu contextuel.

La classe ListView est issue de la classe ItemsView<Cell>, dont elle hérite des 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é s’exclue mutuellement avec la propriété GroupDisplayBinding. Par conséquent, la définition de cette propriété configure 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.
  • HeaderTemplate, de type DataTemplate, spécifie le DataTemplate à utiliser pour mettre en forme le Header.
  • HorizontalScrollBarVisibility, de type ScrollBarVisibility, indique le moment où la barre de défilement horizontale est visible.
  • IsGroupedEnabled, 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 s’exécute lorsqu’une actualisation est déclenché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 vous pouvez sélectionner des éléments dans le ListView. La valeur par défaut de cette propriété est Single.
  • 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 s’appuient sur des objets BindableProperty, ce qui signifie qu’elles peuvent être les cibles de liaisons de données et mises en forme avec un style.

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

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

ListView définit les événements suivants :

  • ItemAppearing, qui se déclenche lorsque l’utilisateur ajoute la représentation visuelle d’un élément à la disposition 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 l’utilisateur supprime la représentation visuelle d’un élément de la disposition 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

Vous pouvez remplir un ListView avec des données en définissant sa propriété ItemsSource sur n’importe quelle collection qui implémente IEnumerable.

Important

Si ListView 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 IEnumerable qui envoie des notifications de modification de propriété, par exemple ObservableCollection.

Vous pouvez remplir ListView avec des données en utilisant une liaison de données pour lier sa propriété ItemsSource à une collection IEnumerable. En XAML, utilisez pour ce faire l’extension de balisage Binding :

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

Le code C# équivalent est :

ListView listView = new ListView();
listView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

Dans cet exemple, les données de la propriété ItemsSource sont liées à 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

Vous pouvez définir l’apparence de chaque élément dans ListView en définissant la propriété ItemTemplate sur un DataTemplate :

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <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. Un enfant du DataTemplate doivent être un objet Cell. Dans l’exemple, la disposition dans DataTemplate est gérée par Grid. 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 :

Capture d’écran d’un ListView dont 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 un élément de données dans le ListView. .NET MAUI inclut les cellules intégrées suivantes :

  • TextCell, qui affiche le texte principal et le 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.
  • ViewCell, qui est une cellule personnalisée dont l’apparence est définie par View. Vous devez utiliser 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

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 quand l’utilisateur appuie sur la cellule.
  • 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 mises en forme avec un style.

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

<ListView ItemsSource="{Binding Food}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <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.

Cellule d’image

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 mise en forme avec un style.

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

<ListView ItemsSource="{Binding Food}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <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 :

Capture d’écran de ListView dont chaque élément est une ImageCell.

Cellule de vue

ViewCell est une cellule personnalisée dont l’apparence est définie par View. ViewCell définit une propriété View, de type View, qui définit 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 mise en forme avec un style.

Remarque

La propriété View est la propriété de contenu de la classe ViewCell et n’a donc pas besoin d’être explicitement définie à partir du code XAML.

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

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <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 de ViewCell, la disposition peut être gérée par n’importe quelle disposition .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 :

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">
    <ContentPage.Resources>
        <DataTemplate x:Key="AmericanMonkeyTemplate">
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>

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

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

    <StackLayout Margin="20">
        <ListView ItemsSource="{Binding Monkeys}"
                  ItemTemplate="{StaticResource MonkeySelector}" />
    </StackLayout>
</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 OtherMonkey DataTemplate, qui sont configurées sur 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 bleu-vert 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 de runtime 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 ListView est désactivée. Vous pouvez modifier ce comportement en définissant la propriété SelectionMode. L’énumération ListViewSelectionMode définit les membres suivants :

  • None : indique que l’utilisateur ne peut pas sélectionner d’éléments.
  • Single : indique que l’utilisateur peut sélectionner un élément unique, l’élément sélectionné étant mis en surbrillance. Il s’agit de la valeur par défaut.

ListView définit un événement ItemSelected qui se déclenche lorsque la propriété SelectedItem change, parce qu’un utilisateur sélectionne un élément dans la liste ou parce qu’une application configure la propriété. L’objet SelectedItemChangedEventArgs qui accompagne cet événement définit les propriétés SelectedItem et SelectedItemIndex.

Lorsque la propriété SelectionMode a la valeur Single, un seul élément dans le fichier 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 le gestionnaire d’événements 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 élément unique dans un ListView :

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, vous pouvez désactiver le défilement 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 ListView est souvent utilisé pour afficher beaucoup plus de données qu’à l’écran. 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 conserver la mémoire, les équivalents ListView natifs 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, spécifie que le ListView génère 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 sa vitesse d’exécution en recyclant les cellules de la liste de recyclage.
  • RecycleElementAndDataTemplate, comme RecycleElement, garantit que lorsqu’un ListView utilise un DataTemplateSelector, les objets DataTemplate sont mis en cache par le type d’élément de la liste.

Conserver les éléments

La stratégie de mise en cache RetainElement spécifie que la cellule ListView génère une cellule pour chaque élément de la liste. Il s’agit du 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 StackLayout, deviennent des goulots d’étranglement des performances lorsqu’elles sont configurées et détruites en temps réel lorsque 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 réduire son empreinte mémoire et sa vitesse d’exécution en recyclant les cellules de la liste de recyclage. 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 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. Vous pouvez également définir les données de cellule dans le remplacement OnBindingContextChanged (plutôt que dans le constructeur de la cellule personnalisée), comme illustré dans 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 (en plus) que lorsqu’un ListView utilise un DataTemplateSelector pour sélectionner un DataTemplate, les objets DataTemplate sont mis en cache par le type d’élément de la liste. Par conséquent, les objets DataTemplate sont sélectionnés une fois par type d’élément, au lieu d’une seule 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 stratégie de mise en cache ListView 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 CachingStrategy à partir de XAML sur un ListView sous-classé ne produit pas le comportement souhaité, car il n’y a pas de propriété CachingStrategy sur ListView. La solution à ce problème consiste à spécifier un constructeur sur le ListView sous-classé qui accepte un paramètre 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 code XAML avec 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, spécifie la chaîne, la liaison ou la vue qui sera affichée au début de la liste.
  • HeaderTemplate, de type DataTemplate, spécifie le DataTemplate à utiliser pour mettre en forme le Header.
  • 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 :

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 définies sur un objet StackLayout qui contient un objet Label :

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.Header>
        <StackLayout BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Monkeys"
                   FontSize="12"
                   FontAttributes="Bold" />
        </StackLayout>
    </ListView.Header>
    <ListView.Footer>
        <StackLayout BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Friends of Monkey"
                   FontSize="12"
                   FontAttributes="Bold" />
        </StackLayout>
    </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 utilisant des vues.

Les propriétés HeaderTemplate et FooterTemplate peuvent être définies sur des objets DataTemplate utilisés pour mettre en forme 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>
            <StackLayout BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Monkeys"
                       FontSize="12"
                       FontAttributes="Bold" />
            </StackLayout>
        </DataTemplate>
    </ListView.HeaderTemplate>
    <ListView.FooterTemplate>
        <DataTemplate>
            <StackLayout BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Friends of Monkey"
                       FontSize="12"
                       FontAttributes="Bold" />
            </StackLayout>
        </DataTemplate>
    </ListView.FooterTemplate>
    ...
</ListView>

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

Par défaut, des séparateurs s’affichent entre les éléments ListView sur iOS et Android. Ce comportement peut être modifié en définissant la propriété SeparatorVisibility, de type SeparatorVisibility, sur 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 HasUnevenRows et RowHeight. Par défaut, la propriété HasUnevenRows est false.

Vous pouvez définir la propriété RowHeight sur un int qui représente la hauteur de chaque élément de 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 étant dérivée du contenu de l’élément DataTemplate, chaque élément est dimensionné en fonction de 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 de DataTemplate, à condition que la propriété HasUnevenRows soit true. L’exemple suivant modifie la hauteur d’un objet Image quand l’utilisateur appuie dessus :

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é quand l’utilisateur appuie sur un objet Image. 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 lorsqu’elle n’est pas visible.

Avertissement

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

Disposition de droite à gauche

Pour que ListView applique à son contenu une direction de flux de droite à gauche, définissez sa propriété FlowDirection sur RightToLeft. Cependant, la propriété FlowDirection doit idéalement être définie sur une page ou une disposition racine. Ainsi, tous les éléments de la page ou de la disposition racine répondent à la direction de flux :

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

La valeur par défaut de 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 StackLayout, 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 collection IEnumerable<T>, où T définit deux éléments de données :

  • Un nom de groupe.
  • Une collection IEnumerable 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 présente 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 collection de groupes IEnumerable<T> 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 AnimalGroup comprend un nom et une collection List<Animal> qui définit les objets Animal 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 une List<Animal> collection de détails « Monkey ».

ListView affiche les données groupées, à condition que les données aient été correctement regroupées, en définissant la propriété IsGroupingEnabled sur true :

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="True">
    <ListView.ItemTemplate>
        <DataTemplate>
            <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, "Animals");
// ...

Vous pouvez définir l’apparence de chaque élément dans ListView en définissant la propriété ItemTemplate sur un DataTemplate. Pour plus d’informations, consultez Définir l’apparence d’un élément.

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 définir l’apparence de chaque élément en définissant la propriété ListView.GroupHeaderTemplate sur un DataTemplate :

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="True">
    <ListView.GroupHeaderTemplate>
        <DataTemplate>
            <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.

Important

La propriété GroupHeaderTemplate s’exclue 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 et le type qui modélise un groupe d’éléments unique.

Contrôler le défilement

ListView définit deux méthodes ScrollTo, qui font défiler les éléments dans l’affichage. L’une des surcharges fait défiler l’élément spécifié dans la vue, tandis que l’autre fait défiler l’élément spécifié dans le groupe spécifié dans la vue. Les deux surcharges ont des arguments supplémentaires qui permettent la position exacte de l’élément une fois le défilement terminé, lorsqu’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. 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 déclenché pour indiquer que le défilement s’est produit. L’objet ScrolledEventArgs qui accompagne l’événement Scrolled définit les propriétés ScrollX et ScrollY.

Détecter le défilement

ListView définit un événement Scrolled qui se déclenche pour indiquer que le 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, représente la position X du défilement
  • ScrollY, de type double, 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 se déclenche 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é dans la vue. 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 dans la vue :

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 définie avec l’argument position de la méthode ScrollTo. Cet argument accepte un membre d’énumération ScrollToPosition.

MakeVisible

Le membre ScrollToPosition.MakeVisible indique que l’élément doit faire l’objet d’un défilement 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 être 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 faire l’objet d’un défilement 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 indique si la barre de défilement horizontale ou verticale est visible. L’énumération ScrollBarVisibility définit les membres suivants :

  • Default 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 HorizontalScrollBarVisibility et VerticalScrollBarVisibility.
  • Always indique que la barre de défilement est visible même si le contenu correspond à l’affichage.
  • Never indique que la barre de défilement n’est pas visible même si le contenu ne correspond pas à l’affichage.

Ajouter des menus contextuels

ListView prend en charge les éléments de menus contextuels, qui sont définis en tant qu’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>
            <ViewCell>
                <ViewCell.ContextActions>
                    <MenuItem Text="Favorite"
                              Command="{Binding Source={x:Reference listView}, Path=BindingContext.FavoriteCommand}"
                              CommandParameter="{Binding}" />
                    <MenuItem Text="Delete"
                              Command="{Binding Source={x:Reference listView}, Path=BindingContext.DeleteCommand}"
                              CommandParameter="{Binding}" />
                </ViewCell.ContextActions>

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

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

Capture d’écran des éléments de menu contextuel 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 balayage pour actualiser, ce qui permet d’actualiser les données affichées en balayant la liste d’éléments vers le bas.

Pour activer le balayage pour actualiser, définissez la propriété IsPullToRefreshEnabled sur true. Lorsqu’une actualisation est déclenchée, ListView déclenche l’événement Refreshing et la propriété IsRefreshing est définie sur true. Le code requis pour actualiser le contenu du ListView doit ensuite être exécuté par le gestionnaire pour 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 utiliser le balayage pour actualiser :

<ListView ItemsSource="{Binding Animals}"
          IsPullToRefreshEnabled="true"
          RefreshCommand="{Binding RefreshCommand}"
          IsRefreshing="{Binding IsRefreshing}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Dans cet exemple, lorsque l’utilisateur lance une actualisation, le ICommand défini par la propriété RefreshCommand est exécuté, ce qui doit actualiser 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 d’opération d’actualisation. Quand une actualisation est déclenchée, cette propriété passe automatiquement à true. Une fois l’actualisation terminée, vous devez rétablir la valeur false de la propriété.