Migration du LongListSelector en Universal Apps

Après les ressources destinées aux traductions, nous continuons le tour d’horizon des éléments nécessaires pour migrer d’un projet Windows Phone 8.0 en Universal apps.

LongListSelector WP81

Le LongListSelector est un élément de liste très souvent utilisé : Il est apparu en 8.0 mais existait déjà dans la version 7.0 sous forme d’un composant tiers du Windows Phone Toolkit.

Avec les Universal Apps, ce composant disparaît au profit d’autres composants déjà présents dans Windows 8.0 : Listbox, ListView, GridView.

Liste Simple

Le cas le plus simple est lorsque LongListSelector est utilisé en mode simple Liste (sans regroupement).

Exemple de code :

<phone:LongListSelector
   ItemsSource="{Binding AllItemsViewModel}"    
   IsGroupingEnabled="False"
   ItemTemplate="{StaticResource ItemTemplate}" />

Le IsgroupingEnabled= »False » indique ici qu’il n’y a pas de regroupement des item.

  • Le templateItem met en forme les données. La migration peut se faire très facilement en remplaçant le LongListSelector par un ListView ou même un Listbox :
<ListView
  ItemsSource="{Binding AllItemsViewModel}"    
  ItemTemplate="{StaticResource ItemTemplate}" />

Le ItemTemplate n’a pas besoin d’être migré et reste identique.

Liste avec regroupement

Le regroupement et le IGrouping

Pour rappel, le regroupement des éléments passe par un objet ViewModel de type IGrouping<KeyGroup, ItemViewModel>.

Ce regroupement est également nécessaire pour un projet WP8.0 et Silverlight 8.1. La partie ci dessous est indispensable quelque soir le contrôle XAML utilisé (WP8; WP8.1 Silverlight et WP8.1 XAML)

Je prends l’exemple très simpliste d’une liste de message que l’on souhaite regrouper par Date.

public class MessageViewModel
{
    public string Title { get; set; }
    public DateTime FullDate { get; set; }
    public DateTime DayDate { get { return FullDate.Date; } }
}

Une liste possède déjà des messages :

private List<MessageViewModel> _messages = new List<MessageViewModel>();

Pour gérer un regroupement, il faut implémenter une classe de type IGrouping<KeyGroup, ItemViewModel>

Ce qui peut être défini en utilisant toujours ce même modèle :

public class Group<Tkey, TElement> : List<TElement>
{
    public Tkey Key { get; set; }
    public Group(IGrouping<Tkey, TElement> group)
        : base(group)
    {
        this.Key = group.Key;
    }

    public override bool Equals(object obj)
    {
        Group<Tkey, TElement> that = obj as Group<Tkey, TElement>;
        return (that != null) && (this.Key.Equals(that.Key));
    }

    public override int GetHashCode()
    {
        return Key.GetHashCode();
    }

}

 

Exemple d’utilisation de la liste dans le ViewModel :

private List<Group<string, MessageViewModel>> _messagesByGroup = new List<Group<string, MessageViewModel>>();
        
public List<Group<string, MessageViewModel>> MessagesByGroup { get {return _messagesByGroup; }}

La propriété en « public » est indispensable pour le Binding.

Une requête Linq permet de générer ce regroupement :

var q = from messagevm in _messages
                    orderby messagevm.DayDate descending, messagevm.Title
                    group messagevm by messagevm.DayDate.ToString() into c
                    select new Group<string, MessageViewModel>(c);
            _messagesByGroup = q.ToList();

(Fin du rappel et de la partie commune)

Utilisation en XAML pour WP8.0 WP8.1 Silverlight

<phone:LongListSelector       
        ItemsSource="{Binding MessagesByGroup}"
        GroupHeaderTemplate="{StaticResource MessageGroupHeader}"       
        ItemTemplate="{StaticResource ItemTemplate}"      
        IsGroupingEnabled="True"       
        HideEmptyGroups ="true"/>
  • GroupHeaderTemplate : Modèle pour la partie regroupement qui sera répétée
  • ItemTemplate : Modèle pour les Items.
  • IsGroupingEnabled = true pour permettre le regroupement

Les 2 DataTemplates sont définis dans des styles :

Voici un exemple simpliste

<DataTemplate x:Key="NotifyItemTemplate" >
    <Grid Margin="0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <TextBlock Margin="8 0 0 0" Text="{Binding Title}" Style="{ThemeResource BodyTextBlockStyle}"/>
        <TextBlock Margin="8 0 0 0" Grid.Column="1" Text="{Binding FullDate}" Style="{ThemeResource BodyTextBlockStyle}"/>
    </Grid>
</DataTemplate>

<DataTemplate x:Key="MessageGroupHeader">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding Key}" Style="{ThemeResource SubheaderTextBlockStyle}"/>
        <Border Grid.Row="1" Height="2" Margin="0,0,0,0" 
                HorizontalAlignment="Stretch" 
                VerticalAlignment="Bottom"
                Background="Red"/>
    </Grid>                
</DataTemplate>

Remarquez que l’affichage du regroupement se fait par un {Binding Key}. Dans le cas ou le regroupement représente un objet plus complexe (une image avec un titre par exemple), il faudrait Binder avec Key.NomDeLaPropriété (Key.Image ou Key.Title par exemple).

Utilisation en WP8.1 XAML (ou Windows 8.x)

La première étape est la définition d’une nouvelle source de données « groupées ».

Pour cela, il faut définir une CollectionViewSource (dans les ressources de la page par exemple). La propriété IsSourceGrouped=True est très importante.

CollectionViewSource 
                x:Name="ViewSourceMessagesByGroup" 
                IsSourceGrouped="True"
                Source="{Binding MessagesByGroup}"/>

Ensuite, il faut « Binder » cette propriété de type staticRessource dans la ListView.

{Binding Source={StaticResource ViewSourceMessagesByGroup} }

Très important, le contrôle XAML utilisé doit être obligatoirement un ListView ou un GridView.
La ListBox ne fonctionne pas pour un regroupement.

La propriété GroupStyle va ensuite permettre le regroupement de cette nouvelle source de données.

<ListView
        ItemsSource="{Binding Source={StaticResource ViewSourceMessagesByGroup} }"    
        ItemTemplate="{StaticResource NotifyItemTemplate}" >
    <ListView.GroupStyle>
        <GroupStyle 
                HidesIfEmpty="True" 
                HeaderTemplate="{StaticResource MessageGroupHeader}">
        </GroupStyle>
    </ListView.GroupStyle>
</ListView>

GroupStyle permet de définir l’affichage du groupe HeaderTemplate. Le style du DataTemplate défini par HeaderTemplate est 100% identique au template déjà utilsé dans votre ancien LongListSelector.

Nous avons maintenant une liste avec une regroupement.

HideIfEmpty correspond à l’ancienne propriété HideEmptyGroups et permet d’afficher ou cacher les groupes qui contiennent aucun élément.

Le code source de l’exemple se trouve ici :

download-10-icon-256

Pour le moment les groupes existent mais lorsque l’on clique sur un groupe, rien ne se passe.

Nous allons voir dans le prochain article comment créer la Jumplist permettant l’affichage condensé de tous les groupes.

Laissez un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

trois × 4 =

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.