Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Different Templates in One Listbox

DZone's Guide to

Different Templates in One Listbox

· Mobile Zone
Free Resource

In this post I will explain how I selected different templates based on the type of data I wanted to show in the same listbox.

Now why might you want 2 different templates in the same list box? Well what if you wanted to display different tasks and appointments for a single day. But you want to see at a quick glance what a task is and what an appointment is. So lets say you have a square for all tasks and a circle for all appointments.

To do this you will use a ContentControl which as the data gets bound to the listbox, we will override the method to check if the item getting bound is a task or appointment. And then set the template depending on what it is.

In my code example the tasks and appointments both inherit from a class called CalendarItem. This is an object orientated programing principle, and if you don’t understand it let me know and I will create a blog about the basics of it.

First think I did was to create the templates I would be using for tasks and appointments. I created a seperate file called “DataTemplates.xaml” and put it into a folder called “Resources”.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DataTemplate x:Key="TaskTemplate">
      <StackPanel Orientation="Horizontal" Margin="0, 6">
        <Grid Margin="12, 0, 12, 0">
          <Rectangle Fill="{Binding categoryColor}" Width="20" Height="20"/>
        </Grid>
        <StackPanel Orientation="Horizontal">
          <TextBlock Text="{Binding title}" HorizontalAlignment="Left" TextWrapping="Wrap" FontSize="24" Width="300"/>
          <TextBlock Text="{Binding time}" HorizontalAlignment="Right" FontSize="24" Width="112"/>
        </StackPanel>
      </StackPanel>
    </DataTemplate>
 
    <DataTemplate x:Key="ApptTemplate">
        <StackPanel Orientation="Horizontal" Margin="0, 6">
            <Grid Margin="12, 0, 12, 0">
                <Ellipse Fill="{Binding categoryColor}" Width="20" Height="20"/>
            </Grid>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding title}" HorizontalAlignment="Left" TextWrapping="Wrap" FontSize="24" Width="300"/>
                <TextBlock Text="{Binding time}" HorizontalAlignment="Right" FontSize="24" Width="300"/>
            </StackPanel>
        </StackPanel>
    </DataTemplate>
 
</ResourceDictionary>

As you look at this code you will see the template structures look alike, but one uses a rectangle and the other usues an ellipse. Now in the CalendarItem class everything has a category and a categoryColor, a title and a time. So we us all that data to display.

Next thing is you will have to create the override using the ContentControl. Create a class file in your solution, I called mine “TemplateSelector.cs.”

using System.Windows.Controls;
using System.Windows;
using System.Windows.Markup;
using System.Xml.Linq;
 
namespace DuelTemplateSample.Helpers
{
    public class DataTemplateHelper
    {
        public static DataTemplate LoadFromDictionary(string dictionary, string template)
        {
            var doc = XDocument.Load(dictionary);
            var dict = (ResourceDictionary)XamlReader.Load(doc.ToString(SaveOptions.None));
            return dict[template] as DataTemplate;
        }
    }
 
    public class templateSelector : ContentControl
    {
        protected override void OnContentChanged(object oldContent, object newContent)
        {
            base.OnContentChanged(oldContent, newContent);
 
            var calItem = (CalendarItem)newContent;
 
            if (calItem.type == "APPT")
            {
                ContentTemplate = DataTemplateHelper.LoadFromDictionary(
                                "DuelTemplateSample;component/Resources/DataTemplates.xaml",
                                "ApptTemplate");
            }
            else
            {
                ContentTemplate = DataTemplateHelper.LoadFromDictionary(
                                "DuelTemplateSample;component/Resources/DataTemplates.xaml",
                                "TaskTemplate");
            }
        }
    }
}

As you can see in the ContentControl code we are overriding the OnContentChanged method, which takes in 2 objects. oldContent and newContent. If you don’t understand what an override is, it is another principle of object orientated programming. We then typecase (that is setting the object as another type), in this case we are saying the the newContent is a CalendarItem. Then we check the the type is, this is a property of calendar item, it will be either ‘APPT’ for appointment or ‘TASK’ for task. Then depending on what the type is we load the ContentTemplate from the DateTemplate file and the template name. In the code I am calling a method called LoadFromDictionary which is defined in the code above the OnContentChanged. All this does is loads in the xaml file that you created before, and gets the template matching the template name. As you can see I am sending a string that is giving the location of the xaml file, this format is used to tell the location of the file in the application the “DuelTemplateSample;” tells what namespace the file is located in, and the “component/Resources/DataTemplates.xaml” tells that the file is located in the Resources folder. The component means it is in the ‘root’ of the project.

Now is the time to get to set up to work in the ListBox. In your xaml page that will contain the ListBox, add in

xmlns:templateSelector="clr-namespace:DuelTemplateSample.Helpers"

to the PhoneApplicationPage with all the other namespaces. As you can see “DuelTemplateSample.Helpers” is the namespace of where the templateSelector / OnContentChanged is located. Now for the ListBox mine looks like this

<ListBox x:Name="DuelListBox" SelectionChanged="DuelListBox_SelectionChanged" Height="133" Margin="0,475,0,0" VerticalAlignment="Top" >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <templateSelector:templateSelector Content="{Binding}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

As you see I set the DataTemplate to

<templateSelector:templateSelector Content="{Binding}"/>

This is what calls the OnContentChange override method and sets the template to the template depending on the type that we coded before.

Now all you need to do is bind a set of data to the ListBox and check out the results. In this case I have a list of CalendarItems a mix of tasks and appointments and load it into the ListBox in the code behind.

I hope this helps and if you are confused, have any questions or comments please comment or email me at andy (at) underbridgecity.net.

 

Topics:

Published at DZone with permission of Andrew Conlisk, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}