Windows 8 – Appliquer un template en fonction des items d’une liste

J’ai commencé à travailler sur Windows 8 autour d’une application utilisant des List/Grid/Gridview, en C#/XAML, et pour lesquelles je souhaitais personnaliser l’affichage de certains éléments identifiable. Par exemple, appliquer un style différent au dernier élément de la liste…

Pour l’exemple, nous allons créer une nouvelle application Windows Metro style de type Grid App (XAML) que j’ai nommé ici TemplateSelector :

clip_image001

Si on exécute l’application, voilà ce que l’on obtient :

clip_image002

Nous avons donc ici une liste d’éléments basés sur la Datasource exemple fournit par le template de projet. On voit ici que chaque élément utilise le même template : Standard250x250ItemTemplate.

<DataTemplate x:Key="Standard250x250ItemTemplate">
        <Grid HorizontalAlignment="Left" Width="250" Height="250">
            <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
                <Image Source="{Binding Image}" Stretch="UniformToFill"/>
            </Border>
            <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
                <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>
                <TextBlock Text="{Binding Subtitle}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
            </StackPanel>
        </Grid>
    </DataTemplate>

Imaginons que l’on souhaite que l’élément 3 de notre premier groupe possède un cadre bleu, c’est à dire, appliquer un style différent que Standard250x250ItemTemplate utilisé.

Pour cela il existe une classe DataTemplateSelector : http://msdn.microsoft.com/fr-fr/library/system.windows.controls.datatemplateselector.aspx

Pour l’implémenter c’est simple, il suffit de créer une classe qui hérite de DataTemplateSelector et de surcharger la méthode SelectTemplateCore.

Ajoutons une classe à notre projet, que j’ai nommé ici MyTemplateSelector :

clip_image003

Voici le code de ma classe MyTemplateSelector :

public class MyTemplateSelector : DataTemplateSelector
    {
        protected override Windows.UI.Xaml.DataTemplate SelectTemplateCore
            (object item, Windows.UI.Xaml.DependencyObject container)
        {
            if (item is SampleDataItem)
            {
                SampleDataItem sample = item as SampleDataItem;
                if (sample.UniqueId == "Group-1-Item-3")
                    return Application.Current.Resources["Special250x250ItemTemplate"] as DataTemplate;
                else
                    return Application.Current.Resources["Standard250x250ItemTemplate"] as DataTemplate;
            }
            return base.SelectTemplateCore(item, container);
        }
    }

Ici, en fonction de l’Identifiant de l’item en cours, j’applique soit le template Standard250x250ItemTemplate, soit le template Special250x250ItemTemplate dans le cas ou l’Identifiant est "Group-1-Item-3" dans mon exemple et en me basant sur la Datasource du template de projet.

Il faut penser à créer le template Special250x250ItemTemplate, dans le fichier StandardStyles.xaml par exemple :

<DataTemplate x:Key="Special250x250ItemTemplate">
        <Grid HorizontalAlignment="Left" Width="250" Height="250">
            <Border BorderBrush="Blue" BorderThickness="12" Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
                <Image Source="{Binding Image}" Stretch="UniformToFill"/>
            </Border>
            <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
                <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>
                <TextBlock Text="{Binding Subtitle}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
            </StackPanel>
        </Grid>
    </DataTemplate>

Il ne reste plus qu’à dire à notre GridView d’utiliser notre classe MyTemplateSelector. Pour cela, il suffit d’ajouter, dans le code XAML de la page, la ressource :

<common:MyTemplateSelector x:Key="TemplateSelector" />

Puis au niveau du GridView de spécifier la propriété ItemTemplateSelector :

<GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemGridView"
            AutomationProperties.Name="Grouped Items"
            Grid.Row="1"
            Margin="0,-3,0,0"
            Padding="116,0,40,46"
            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
            ItemTemplateSelector="{StaticResource ResourceKey=TemplateSelector}"
            SelectionMode="None"
            IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick"> 

Attention, il faut également supprimer la propriété ItemTemplate du GridView sinon, il ne passera pas par notre classe MyTemplateSelector.

Remarque, on peut aussi appliquer ces valeurs au niveau du code behind C# :

this.itemGridView.ItemTemplate = null; 
this.itemGridView.ItemTemplateSelector = new MyTemplateSelector(); 

Si on exécute désormais notre application, voici ce que l’on obtient :

clip_image004

Nous savons désormais comment personnaliser nos éléments dans une liste. Les possibilités sont assez nombreuses. Dans mon cas, j’ai utilisé ce principe pour ajouter un élément en fin de ma liste qui me permet de faire de la pagination.

Par défaut ma liste charge 40 éléments, le dernier élément est un + qui lorsque l’on clique dessus, charge les 40 éléments suivants :

clip_image005

Rock’n'Roll.