Click here to Skip to main content
Click here to Skip to main content

How to Bind to Hierarchical Data and Create a Master/Details View (Windows UI Style Apps Using C#/VB/C++ and XAML)

By , 9 Aug 2012
 

This blog was originally posted here: How to bind to hierarchical data and create a master/details view (Metro style apps using C#/VB/C++ and XAML)

Also, check out our Windows 8 sponsored section.

You can make a multi-level master/details view of hierarchical data by binding list controls to CollectionViewSource instances.

One common structure for Metro style apps is to navigate to different details pages when a user makes a selection in a master list. This is useful when you want to provide a rich visual representation of each item at every level in a hierarchy. The Grid Application and Split Application templates in Visual Studio demonstrate how to use this technique.

Another option is to display multiple levels of data on a single page. This is useful when you want to display a few simple lists that let people quickly drill down to an item of interest. This topic describes how to implement this technique by using multiple CollectionViewSource instances. These instances keep track of the current selection at each level.

The following example creates a view of a sports hierarchy that is organized into lists for leagues, divisions, and teams, and includes a team details view. When you select an item from any list, the subsequent views update automatically.


Roadmap: How does this topic relate to others? See:

Prerequisites

This topic assumes that you can create a basic Metro style app using C++, C#, or Visual Basic. For instructions on creating your first Metro style app, see Building your first Metro style app using C++, C#, or Visual Basic.

Instructions

Step 1: Create the project

Create a new Windows Metro style app named MasterDetailsBinding, by using the Blank Application template.

Step 2: Create the data model

Add a new class file to your project and replace its contents with the following code.

This code shows a simple data model that also generates sample data for display in the designer and at run time.

using System;
using System.Collections.Generic;
using System.Linq;

namespace MasterDetailsBinding
{
    public class Team
    {
        public string Name { get; set; }
        public int Wins { get; set; }
        public int Losses { get; set; }
    }

    public class Division
    {
        public string Name { get; set; }
        public IEnumerable<Team> Teams { get; set; }
    }

    public class League
    {
        public string Name { get; set; }
        public IEnumerable<Division> Divisions { get; set; }
    }

    public class LeagueList : List<League>
    {
        public LeagueList()
        {
            this.AddRange(GetLeague().ToList());
        }

        public IEnumerable<League> GetLeague()
        {
            return from x in Enumerable.Range(1, 2) select new League
            {
                Name = "League " + x,
                Divisions = GetDivisions(x).ToList()
            };
        }

        public IEnumerable<Division> GetDivisions(int x)
        {
            return from y in Enumerable.Range(1, 3) select new Division
            {
                Name = String.Format("Division {0}-{1}", x, y),
                Teams = GetTeams(x, y).ToList()
            };
        }

        public IEnumerable<Team> GetTeams(int x, int y)
        {
            return from z in Enumerable.Range(1, 4) select new Team
            {
                Name = String.Format("Team {0}-{1}-{2}", x, y, z),
                Wins = 25 - (x * y * z),
                Losses = x * y * z
            };
        }
    }
}

Step 3: Create the view

Replace the contents of the MainPage.xaml file with the following code.

This code shows the XAML that defines the view. The XAML first declares the sample data source (the local:LeagueList element) and three CollectionViewSource instances, and binds them together in a chain. The subsequent controls can then bind to the appropriate CollectionViewSource depending on the level in the hierarchy.

<Page
    x:Class="MasterDetailsBinding.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MasterDetailsBinding"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

  <Page.Resources>

    <local:LeagueList x:Key="LeagueData"/>
    <CollectionViewSource x:Name="Leagues" 
      Source="{StaticResource LeagueData}"/>
    <CollectionViewSource x:Name="Divisions"
      Source="{Binding Divisions, Source={StaticResource Leagues}}"/>
    <CollectionViewSource x:Name="Teams"
      Source="{Binding Teams, Source={StaticResource Divisions}}"/>

    <Style TargetType="TextBlock">
      <Setter Property="FontSize" Value="15"/>
      <Setter Property="FontWeight" Value="Bold"/>
    </Style>

    <Style TargetType="ListBox">
      <Setter Property="FontSize" Value="15"/>
    </Style>

    <Style TargetType="ContentControl">
      <Setter Property="FontSize" Value="15"/>
    </Style>

  </Page.Resources>

  <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

    <StackPanel Orientation="Horizontal">

      <!-- All Leagues view -->

      <StackPanel Margin="5">
        <TextBlock Text="All Leagues"/>
        <ListBox ItemsSource="{Binding Source={StaticResource Leagues}}" 
          DisplayMemberPath="Name"/>
      </StackPanel>

      <!-- League/Divisions view -->

      <StackPanel Margin="5">
        <TextBlock Text="{Binding Name, Source={StaticResource Leagues}}"/>
        <ListBox ItemsSource="{Binding Source={StaticResource Divisions}}" 
          DisplayMemberPath="Name"/>
      </StackPanel>

      <!-- Division/Teams view -->

      <StackPanel Margin="5">
        <TextBlock Text="{Binding Name, Source={StaticResource Divisions}}"/>
        <ListBox ItemsSource="{Binding Source={StaticResource Teams}}" 
          DisplayMemberPath="Name"/>
      </StackPanel>

      <!-- Team view -->

      <ContentControl Content="{Binding Source={StaticResource Teams}}">
        <ContentControl.ContentTemplate>
          <DataTemplate>
            <StackPanel Margin="5">
              <TextBlock Text="{Binding Name}" 
                FontSize="15" FontWeight="Bold"/>
              <StackPanel Orientation="Horizontal" Margin="10,10">
                <TextBlock Text="Wins:" Margin="0,0,5,0"/>
                <TextBlock Text="{Binding Wins}"/>
              </StackPanel>
              <StackPanel Orientation="Horizontal" Margin="10,0">
                <TextBlock Text="Losses:" Margin="0,0,5,0"/>
                <TextBlock Text="{Binding Losses}"/>
              </StackPanel>
            </StackPanel>
          </DataTemplate>          
        </ContentControl.ContentTemplate>
      </ContentControl>

    </StackPanel>

  </Grid>
</Page>

Whenever a binding specifies a property, it automatically uses the value from the currently selected item in the bound CollectionViewSource. For example, the ContentControl representing the team view has its Content property bound to the Teams CollectionViewSource. However, the controls in the DataTemplate bind to properties of the Team class because the CollectionViewSource automatically supplies the currently selected team from the teams list.

Related topics

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Windows Dev-Center
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 9 Aug 2012
Article Copyright 2012 by Windows Dev-Center
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid