WindowsPhoneGeek

WPAppInfo

Login | Join (Why?)

rss rss rss
logo

Windows Phone Toolkit ExpanderView in depth| Part2: Data Binding

published on: 9/8/2011 | Views: N/A | Tags: WP7Toolkit Mango

by WindowsPhoneGeek

This is the second article about the new ExpanderView control from the latest release of Windows Phone Toolkit - August 2011 (7.1 SDK). This time I am going to talk about data binding and using ExpanderView in more complex scenarios.

NOTE:  In Part1 we talked about key properties, methods, events and the main features of the Windows Phone ExpanderView in details. You can take a look at it for reference.

Here is how the final data binding example should look like:

imageimage

To begin with lets first create a new Windows Phone 7.1 application project and add a reference to the Microsoft.Phone.Controls.Toolkit.dll assembly in your Windows Phone application project. (for more information about the assembly visit: Where to find Microsoft.Phone.Controls.Toolkit.dll in WP Toolkit Aug 2011).

Databinding ExpanderView Step by Step

This example demonstrates how to populate the ExpanderView with data using data binding. We will implement a sample expandable menu for a pizza company which shows different kinds of pizzas in collapsed state and detailed descriptions of the ingredients in expanded state.

  • Defining the Data Source

Here are the steps we will follow in order to create a data source:

Step1. Define the business/data class.

The first step is to define the data class. Lets create a "CustomPizza " class which exposes the following properties:

public class CustomPizza : INotifyPropertyChanged
{
    private bool isExpanded;

    public string Image
    {
        get;
        set;
    }

    public string Name
    {
        get;
        set;
    }

    public DateTime DateAdded
    {
        get;
        set;
    }

    public IList<PizzaOption> Options
    {
        get;
        set;
    }

    public bool HasNoOptions
    {
        get
        {
            return this.Options == null || this.Options.Count == 0;
        }
    }

    public bool IsExpanded
    {
        get
        {
            return this.isExpanded;
        }
        set
        {
            if (this.isExpanded != value)
            {
                this.isExpanded = value;
                this.OnPropertyChanged("IsExpanded");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Where PizzaOption is the following class:

public class PizzaOption
{
    public string Name
    {
        get;
        set;
    }
}

Step2. Create a new Images folder and add some images which will be shown in the expanders:

NOTE: You will also have to add an Image folder with some images inside. For example :

clip_image004clip_image002

Step3. Create a sample collection with items of type CustomPizza:

public MainPage()
{
  List<CustomPizza> customPizzas = new List<CustomPizza>()
   {
    new CustomPizza() { Name = "Custom Pizza 1",
       DateAdded = new DateTime(2010, 7, 8), Image="Images/pizza1.png", 
       Options = new List<PizzaOption>
    {
        new PizzaOption() { Name = "Ham" },
        new PizzaOption() { Name = "Mushrooms" },
        new PizzaOption() { Name = "Tomatoes" }
    }},

    new CustomPizza() { Name = "Custom Pizza 2", 
DateAdded = new DateTime(2011, 2, 10), 
Image="Images/pizza2.png", 
Options = new List<PizzaOption>
    {
        new PizzaOption() { Name = "Ham" },
        new PizzaOption() { Name = "Olives" },
        new PizzaOption() { Name = "Mozzarella" }
    }},

    new CustomPizza() { Name = "Surprise Pizza",
Image= null, 
DateAdded = new DateTime(2011, 4, 1),
Options = null },

    new CustomPizza() { Name = "Custom Pizza 3",
Image="Images/pizza3.png",
DateAdded = new DateTime(2011, 5, 15), 
Options = new List<PizzaOption>
    {
        new PizzaOption() { Name = "Salami" },
        new PizzaOption() { Name = "Mushrooms" },
        new PizzaOption() { Name = "Onions" }
    }},

    new CustomPizza() { Name = "Custom Pizza 4",
Image="Images/pizza4.png", 
DateAdded = new DateTime(2011, 7, 20),
Options = new List<PizzaOption>
    {
        new PizzaOption() { Name = "Pepperoni" },
        new PizzaOption() { Name = "Olives" },
        new PizzaOption() { Name = "Mozzarella" }
    }},
   };
     //...
}
  • Databind ExpanderView

At first we will add the necessary DataTemplates in the page Resources section.

Step1. Define a RelativeTimeConverter in the page Resources. We will use it later to transform the "AddedDate" value into suitable string (ex: 08/08/2011 can be transformed into "one month ago").

<phone:PhoneApplicationPage.Resources>
    <toolkit:RelativeTimeConverter x:Key="RelativeTimeConverter"/>
</phone:PhoneApplicationPage.Resources>

Step2. Define a custom HeaderTemplate in the page Resources.

<phone:PhoneApplicationPage.Resources>
    <DataTemplate x:Key="CustomHeaderTemplate">
            <TextBlock Text="{Binding Name}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" FontFamily="{StaticResource PhoneFontFamilySemiLight}"/>
    </DataTemplate>
</phone:PhoneApplicationPage.Resources>

Step3.Define a custom ExpanderTemplate in the page Resources.

<phone:PhoneApplicationPage.Resources>
   <DataTemplate x:Key="CustomExpanderTemplate">
    <StackPanel Orientation="Horizontal">
       <Image Source="{Binding Image}" Stretch="None"/>
       <TextBlock Foreground="{StaticResource PhoneSubtleBrush}"   FontSize="{StaticResource PhoneFontSizeNormal}" VerticalAlignment="Center">
        <TextBlock.Text>
            <Binding Path="DateAdded" Converter="{StaticResource RelativeTimeConverter}" StringFormat="Date added: {0}" />
        </TextBlock.Text>
      </TextBlock>
    </StackPanel>
   </DataTemplate>
</phone:PhoneApplicationPage.Resources>

Step4. Define a custom ItemTemplate in the page Resources.

<phone:PhoneApplicationPage.Resources>
       <DataTemplate x:Key="CustomItemTemplate">
            <TextBlock Text="{Binding Name}" />
    </DataTemplate>
</phone:PhoneApplicationPage.Resources>

Step5. Define a custom NonExpandableHeaderTemplate in the page Resources.

<phone:PhoneApplicationPage.Resources>
   <DataTemplate x:Key="CustomNonExpandableHeaderTemplate">
    <StackPanel Orientation="Vertical">
       <TextBlock Text="{Binding Name}" 
    FontSize="{StaticResource PhoneFontSizeExtraLarge}" 
       FontFamily="{StaticResource PhoneFontFamilySemiLight}"/>
       <TextBlock Foreground="{StaticResource PhoneSubtleBrush}"
                   FontSize="{StaticResource PhoneFontSizeNormal}">
                <TextBlock.Text>
                     <Binding Path="DateAdded" Converter="{StaticResource RelativeTimeConverter}" StringFormat="Date added: {0}" />
          </TextBlock.Text>
       </TextBlock>
          <TextBlock Text="The ingredients will be a surpise!"  Foreground="{StaticResource PhoneSubtleBrush}"
FontSize="{StaticResource PhoneFontSizeNormal}" />
    </StackPanel>
   </DataTemplate>
</phone:PhoneApplicationPage.Resources>

Step6. Add a ListBox in XAML which will be used to display the collection of CustomPizza objects using ExpanderView controls. The ExpanderView and its binding to "CustomPizza" properties is defined in the ItemTemplate. Here is how the ExpanderView should look like:

<ListBox Grid.Row="0" x:Name="listBox">
   <ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <toolkit:ExpanderView Header="{Binding}"   Expander="{Binding}" 
ItemsSource="{Binding Options}" 
NonExpandableHeader="{Binding}"
IsNonExpandable="{Binding HasNoOptions}"  
IsExpanded="{Binding IsExpanded, Mode=TwoWay}"
HeaderTemplate="{StaticResource CustomHeaderTemplate}" ExpanderTemplate="{StaticResource CustomExpanderTemplate}"
ItemTemplate="{StaticResource CustomItemTemplate}"
NonExpandableHeaderTemplate="{StaticResource CustomNonExpandableHeaderTemplate}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
    

Step7. Set the ListBox ItemsSource.

public MainPage()
{
    //...
    this.listBox.ItemsSource = customPizzas;
}

Here is how the final result should look like:

imageclip_image002[10]Normal State:

clip_image004[7]

clip_image006

Expanded State:

clip_image008

That was all about data binding ExpanderView from the Windows Phone Toolkit - August 2011 (7.1 SDK)  in depth. 

The source code is available here:

I hope that the article was helpful.

You may also find interesting the following articles:

You can also follow us on Twitter @winphonegeek

Comments

Event for picking subitems

posted by: jj on 11/7/2011 1:28:05 PM

Does the expanderView expose an event which fires when a subitem (PizzOption) is selected in the sample above? I'm using the ExpanderView in a similar case as in the example but basically have one more level of info to be displayed. I want to tap/click each topping e.g. 'Ham' or 'Tomatoes' and then display a dialog with all properties of the selected topping.

Mr.

posted by: Supreet Tare on 1/29/2012 1:11:23 PM

Awesome Article, saved me a lot of time. I was banging my head for this for long & then read this 2nd part of your article :)

Thank You

Add comment to 'Windows Phone Toolkit ExpanderView in depth| Part2: Data Binding'

Comment

Our Top Articles & Free books

Our Top Tips & Samples