DataTemplateSelector

Suppose you have a collection of items and you want to display them in a ListView (Xamarin.Forms). The catch is that you want to change the display of each item depending on its state or some other code-based attributes.

At first glance this would seem very difficult, and you’d have to modify the instances in the collection to do so. This is where the DataTemplateSelector comes in.

In short, you create two or more data templates — one for each way you might want to display one of the items in your collection — and then you tell Xamarin.Forms, by way of the DataTemplateSelector, which data template to use.

This may be easier to grok with a simple example.

Let’s start with the type we’ll be displaying in the collection.

 public class Mood
 {
     public string CurrentMood { get; set; }
 }

As you can see, we are using an incredibly simple type. Now let’s create a collection of Mood objects (in our ViewModel):

public class MyListPageViewModel
{
    public ObservableCollection<Mood> Moods { get; set;  }
    
    public MyListPageViewModel()
    {
        Moods = new ObservableCollection<Mood>();
        PopulateCollection();
    }

    private void PopulateCollection()
    {
        var mood = new Mood { CurrentMood = "Happy" };
        Moods.Add(mood);
        mood = new Mood { CurrentMood = "Happy" };
        Moods.Add(mood);
        mood = new Mood { CurrentMood = "Sad" };
        Moods.Add(mood);
        mood = new Mood { CurrentMood = "Happy" };
        Moods.Add(mood);
        mood = new Mood { CurrentMood = "Sad" };
        Moods.Add(mood);
    }
}

As you can see, we have a collection of Mood objects named Moods, and we populate that collection with five instances, some happy, some sad.

Now we create our DataTemplates, one for Mood objects that have a CurrentMood value of “Happy” and one for those that have a CurrentMood value of “Sad.” (This goes in our xaml file)

 <ContentPage.Resources>
     <ResourceDictionary>
         <DataTemplate x:Key="HappyTemplate">
             <ViewCell>
             <StackLayout>
                 <Label HorizontalOptions="StartAndExpand" 
                         VerticalOptions="CenterAndExpand" 
                         Text="Happy Happy" 
                         FontSize="20"/>
             </StackLayout>
         </ViewCell>
         </DataTemplate>

         <DataTemplate x:Key="SadTemplate">
             <ViewCell>
             <StackLayout>
                 <Label Text="Sad, very sad."
                        FontSize="20"
                        TextColor="Red"
                        HorizontalOptions="StartAndExpand"
                        VerticalOptions="CenterAndExpand"/>
                 </StackLayout>
             </ViewCell>
         </DataTemplate>
         

We have two DataTemplates. One has the key “HappyTemplate’ and one the key “SadTemplate.” The key difference between them is that the SadTemplate sets the Label’s font color to red.

You can of course make the DataTemplates as complex and as different as you want. For example, one might have. agrid with three columns, where the first is an image, and the other might use a StackLayout and no image.

Next comes the declaration of our ListView and the fun begins…

 <ContentPage.Content>
     <StackLayout VerticalOptions="FillAndExpand">
         <ListView   
             HasUnevenRows="True"
             ItemTemplate="{StaticResource DemoTemplateSelector}"
             ItemsSource="{Binding Moods}"
             SeparatorVisibility="None"
             VerticalOptions="StartAndExpand" 
             Margin="5">
         </ListView>
     </StackLayout>
 </ContentPage.Content>

The key thing to note here is that the ItemTemplate is set to the DemoTemplate Selector. This is a bit of XAML that goes after the DataTemplates and before the list:

<templateselector:DemoTemplateSelector x:Key="DemoTemplateSelector"
                 HappyTemplate="{StaticResource HappyTemplate}"
                 SadTemplate="{StaticResource SadTemplate}" />

The DataTemplateSelector works together with code that we’ll see in a moment, to pick one of the two named Templates (HappyTemplate and SadTemplate).

To pick which DataTemplate to use, you need a new file that has the logic. It needs to derive from DataTemplateSelector. Here’s the start of the class:

    public class DemoTemplateSelector : DataTemplateSelector
    {
        public DataTemplate HappyTemplate { get; set; }
        public DataTemplate SadTemplate { get; set; }


        protected override DataTemplate OnSelectTemplate(
            object item, BindableObject container)
        {
            DataTemplate selectedTemplate;

            if (!(item is Mood))
            {
                throw new ArgumentException("Not a mood!");
            }

The first thing we do is to define two DataTemplate objects corresponding to the ones in our XAML. Next, we override the OnSelectedTemplate event handler, and check to make sure we have an object of the right type.

Assuming we do, we want to check the property “CurrentMood” and choose the right DataTemplate for that one entry in the ListView:

var selectedItem = (Mood)item;

if (selectedItem.CurrentMood == "Happy")
{
    selectedTemplate = HappyTemplate;
}
else
{
    selectedTemplate = SadTemplate;
}

return selectedTemplate ?? HappyTemplate;

Each item in the collection is passed to this method and evaluated. The correct DataTemplate is returned and used in the ListView

Complete source code for this program is available here.

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen Pluralsight & LinkedIn Learning courses. He was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Xamarin Certified Mobile Developer and a Xamarin MVP and a Microsoft MVP.
This entry was posted in Essentials, Xamarin.Forms. Bookmark the permalink.