How to bind to hierarchical data and create a master/details view (XAML)
You can make a multi-level master/details view of hierarchical data by binding list controls to CollectionViewSource instances.
One common structure for Windows Runtime 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:
- Roadmap for Windows Runtime apps using C# or Visual Basic
- Roadmap for Windows Runtime apps using C++
Prerequisites
This topic assumes that you can create a basic Windows Runtime app using C++, C#, or Visual Basic. For instructions on creating your first Windows Runtime app, see Create your first Windows Store app using C# or Visual Basic.
Instructions
Step 1: Create the project
Create a new Windows Runtime 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="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MasterDetailsBinding"
xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="https://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
Roadmaps
Roadmap for Windows Runtime apps using C# or Visual Basic
Roadmap for Windows Runtime apps using C++
Samples
XAML GridView grouping and SemanticZoom sample
StorageDataSource and GetVirtualizedFilesVector sample
Reference
Concepts
Quickstart: Data binding to controls
RelativeSource markup extension
Dependency properties overview
Create your first Windows Store app using C# or Visual Basic