Written by Irmak Tevfik on 12 - Oct - 2014

How to use DataTemplateSelector with Windows 8.1 Store Apps

This article will cover how to implement DataTemplateSelector to have more versatile control of our XAML and our code behind.  We will be separating our DataTemplates into our App.xaml and every single decision will be handled by our TemplateSelector class. Lets begin by adding our example classes for this project. Go ahead and add our classes as:

public class FirstItem
{
    public string ItemName { get; set; }
}
 
public class SecondItem
{
    public string ItemName { get; set; }
}

Now, next step is to add our Main class which will be holding the main page data.
public class PageItems
{
    public string Title { get; set; }
    public object Items { get; set; }
}

Please make sure that you have ObservableDictionary class added to your project!! Lets add a new page and call it MainPage. Change the code for the project to look like:
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
 
    private ObservableDictionary defaultViewModel = new ObservableDictionary();
    /// <summary>
    /// Gets the DefaultViewModel. This can be changed to a strongly typed view model.
    /// </summary>
    public ObservableDictionary DefaultViewModel
    {
        get { return this.defaultViewModel; }
    }
 
    public MainPage()
    {
        this.InitializeComponent();
 
        List<Models.FirstItem> firstItem = new List<Models.FirstItem>()
        {
            new Models.FirstItem(){ ItemName = "First Item 1"},
            new Models.FirstItem(){ ItemName = "First Item 2"}
        };
 
        List<Models.SecondItem> secondItem = new List<Models.SecondItem>()
        {
            new Models.SecondItem(){ ItemName = "Second Item 1"},
            new Models.SecondItem(){ ItemName = "Second Item 2"}
        };
 
        List<Models.PageItems> pageItems = new List<Models.PageItems>()
        {
            new PageItems(){ Items = firstItem, Title="First"},
            new PageItems(){ Items = secondItem, Title="Second"}
        };
 
        this.DefaultViewModel["Groups"] = pageItems;
    }
}

It can be seen that we have created two lists (firstItem, secondItem) holding the data and added these items to our PageItems list. Reason is that, we will be having a CollectionViewSource on our page which "Groups" will be binded to. Our TemplateSelector will iterate through these objects. Lets move on and add our DataTemplateSelector class under your Common folder (or wherever you would like to hold the data).

public class ItemsTemplateSelector : DataTemplateSelector
{
    public DataTemplate FirstItemTemplate { get; set; }
    public DataTemplate SecondItemTemplate { get; set; }
 
    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        var firstItem = (item as FirstItem);
        if (firstItem != null)
            return FirstItemTemplate;
        else
            return SecondItemTemplate;
    }
 
}

Now, we can see that we have two DataTemplate properties. That means we will be returning either one of them depending on the result for overwritten SelectTemplateCore method. 
OK. Now we need our templates ready. Selector will be making the decision, but we need to bind our DataTemplates to their xaml. Go ahead and append your App.xaml to include:

<Application.Resources>
    <DataTemplate x:Name="FirstItemDataTemplate">
        <Grid HorizontalAlignment="Left" Background="Green" Width="200" Height="200">
            <TextBlock Text="{Binding ItemName}"></TextBlock>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Name="SecondItemDataTemplate">
        <Grid  Background="Coral" Height="500"  Width="200" Opacity="1" RequestedTheme="Light">
            <StackPanel VerticalAlignment="Top">
                <Border BorderThickness="2" CornerRadius="2">
                    <TextBlock Text="{Binding ItemName}"  Foreground="#FF2E2E2E" FontFamily="Segoe UI" Margin="10,0" />
                </Border>
            </StackPanel>
        </Grid>
    </DataTemplate>
</Application.Resources>

So we can say that FirstItemDataTemplate will bind to FirstItemTemplate and SecondItemDataTemplate will bind to SecondItemTemplate. Lets move on and change our MainPage.xaml as
<Page
    DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
    .
    .
    .
    .
    .
    RequestedTheme="Light">
 
    <Page.Resources>
        <common:ItemsTemplateSelector x:Key="ItemsTemplateSelector"
            FirstItemTemplate="{StaticResource FirstItemDataTemplate}"
            SecondItemTemplate ="{StaticResource SecondItemDataTemplate}"
            />
        <CollectionViewSource
            x:Name="groupedItemsViewSource"
            Source="{Binding Groups}"
            IsSourceGrouped="true"
            ItemsPath="Items"/>
    </Page.Resources>
     
    <Grid Background="AliceBlue">
        <GridView
            Name="itemGridView"
            ItemTemplateSelector="{StaticResource ItemsTemplateSelector}"
            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
            SelectionMode="None"
            IsSwipeEnabled="false">
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid  ItemWidth="500" AutomationProperties.LiveSetting="Polite" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
            <GridView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Margin="0,40,0,0">
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{Binding Title}"  Margin="0,-11,10,10" TextWrapping="NoWrap" Foreground="#FF424141" FontFamily="Segoe UI Black" FontSize="25" />
                                    <TextBlock Text="{Binding Items.Title}" Margin="0,-11,10,10" TextWrapping="NoWrap" Foreground="#FF424141" FontFamily="Segoe UI Black" FontSize="25" />
                                </StackPanel>
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </GridView.GroupStyle>
        </GridView>
    </Grid>
</Page>

We have our DataContext referenced on the page as DefaultViewModel so we can bind Groups to our CollectionViewSource. And our ItemsTemplateSelector will decide the DataTemplate for our GridView. Go ahead and run your application. Results should look like:


If you have any questions, feel free to ask me.
Enjoy Coding:)
comments powered by Disqus