Xamarin Forms DataTemplateSelector

The DataTemplateSelector is a class that lets you change the data template you want to use, in a ListView or CarouselView, depending upon the type of data for each item, in the list. Rather than making a complex ViewCell or ItemTemplate, you can design each one specifically for the type of data you want.

As an example, if you have a twitter feed, some are retweets, promoted advertisement, or direct tweets. You can design a template for each one of these, then in a single list of models, bind them to a ListView and it will pick the right template depending upon which type of model it is.

Common Model

Because the list of items you are showing are likely to be similar, I normally create a number of models, based off a single model.

public class Tweet {}

public class NormalTweet : Tweet {}

public class PromotedTweet : Tweet {}

public class Retweet : Tweet {}

From here we can have a single list of Tweets.

public IList<Tweet> Tweets { get; set; } = new List<Tweet>() { new NormalTweet(), new Retweet(), new PromotedTweet() };

That can now be bound to a ListView.

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

Now you can see the issue of how to display a slightly different template for different types of tweets.

Data Templates

Now, lets create a DataTemplate for each tweet. In the ResourceDictionary of your Page or App, add a DataTemplate for each model type.

<ContentPage.Resources>
    <ResourceDictionary>
        <DataTemplate x:Key="NormalTweetTemplate">
            <ViewCell>
                <Label Text="I'm a normal tweet" />
            </ViewCell>
        </DataTemplate>
        <DataTemplate x:Key="PromotedTweetTemplate">
            <ViewCell>
                <Label Text="I'm a promoted tweet" />
            </ViewCell>
        </DataTemplate>
        <DataTemplate x:Key="RetweetTemplate">
            <ViewCell>
               <Label Text="I'm a retweet" />
            </ViewCell>
        </DataTemplate>
    </ResourceDictionary>
 </ContentPage.Resources>

DataTemplateSelector

To decide which one to use, now we implement a DataTemplateSelector. In your app, create a new class, that inherits from DataTemplateSelector.

public class TweetTemplateSelector : DataTemplateSelector
{
    public DataTemplate NormalTweetTemplate { get; set; }

    public DataTemplate PromotedTweetTemplate { get; set; }

    public DataTemplate RetweetTemplate { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        if (item is NormalTweet)
            return NormalTweetTemplate;
 
        if (item is PromotedTweet)
            return PromotedTweetTemplate;

        if (item is Retweet)
            return RetweetTemplate;

        return null;
    }
}

Back to the ResourceDictionary of your page, add a resource detailing the TweetTemplateSelector.

// Insert in your ContentPage's attributes
xmlns:local="clr-namespace:Mobile"

// Insert just under the Template's you defined in your ResourceDictionary
<local:TweetTemplateSelector x:Key="TweetTemplateSelector"
                             NormalTweetTemplate="{StaticResource NormalTweetTemplate}"
                             PromotedTweetTemplate="{StaticResource PromotedTweetTemplate}"
                             RetweetTemplate="{StaticResource RetweetTemplate}" />

ListView ItemTemplate

To get a ListView or CarouselView to use the DataTemplateSelector, all we have to do now is assign it to the ItemTemplate property.

<ListView ItemsSource="{Binding Tweets}"
          ItemTemplate="{StaticResource TweetTemplateSelector}" />

datatemplate

Limitations

A few limitations to take note of;

  1. A maximum of 20 different templates are allowed.
  2. Don’t return a different instance of the DataTemplate on each call as it will lead to memory leaks.
  3. Must return the same DataTemplate for a type of model, on each call. It can’t change each time you call it.


XAMARIN.FORMS MONTHLY NEWSLETTER

JOIN 1,000+ SUBSCRIBERS

  1. Don't miss out on updates
  2. The latest info from this site, Xamarin and the community
  3. Unsubscribe at any time*

* We use MailChimp, with double opt-in, and instant unsubscribe

Microsoft MVP | Xamarin MVP | Xamarin Certified Developer | Exrin MVVM Framework | Xamarin Forms Developer | Melbourne, Australia

Related Posts

6 Comments

  1. JohnF

    Thanks for the article.
    Do you know the details why these two happen:

    “Don’t return a different instance of the DataTemplate on each call as it will lead to memory leaks.
    Must return the same DataTemplate for a type of model, on each call. It can’t change each time you call it.”

    1. Adam Pedley

      Those warnings are from Xamarin documentation, however the reason behind it, is due to the caching of templates in the renderer. If you change it up, the previous template will be cached in the renderer and there will be no longer any way to reference or dispose of it, until the ListView is disposed of. Hence as you scroll, it will continue to cache new templates and never free up the old ones.

  2. Frederic MEYER

    Hello,

    This works fine a ListView’s creation time.

    I am looking for a solution that would work when the ListView has already been created and them items displayed.

    Think of the following use case:
    – initial ContextAction with one MenuItem “Select”
    – swipe and Tap on the MenuItem would trigger the specified Command and set the Item’s “is_selected” property to true (which is false by default of course)
    – then the ContextAction menu needs to close (just as intended)
    – I swiped again, it would now show “Unselect” as the items is indeed selected

    My findings are that:
    – OnBindingContextChanged is only called at ListView’s creation time
    – If I do change the MenuItem’s Text in code in the Clicked event or via a bindable property, the texts does change but it won’t close after having been tapped – moreover this is not the wanted behavior as I don’t want to show the “Unselect” text before swiping it back again

    I’m stuck for now. If you have any brillant ideas, I would love to hear them.

    1. Adam Pedley

      This seems slightly off topic for the post and a bit too complex to handle in a blog comment system. Post your question on StackOverflow, and myself and others can have a look.

  3. Frederic

    Hello Adam,

    You are right.

    I stumbled on your article because one of the solutions to my problem was to *dynamically* change the template (i.e not with the TemplateSelector which seems to be for initial creation)

    I’ll try to post a full question on SO.

    Thanks
    Very nice blog by the way, very instructive.
    Bookmarked for sure!

  4. Grady

    Hey Adam! Thanks for the article. Would it be possible to switch the DataTemplate based on the state of a Switch?

Leave A Comment?