メモ また、マスター/詳細サンプルもご覧ください。
階層データの複数レベルのマスター/詳細ビュー(リスト詳細とも呼ばれます)を作成するには、項目コントロールをチェーン方式で連結された CollectionViewSource インスタンスにバインドします。 このトピックでは、可能な限り {x:Bind} マークアップ拡張 を使用し、必要な場合にはより柔軟性のある(ただしパフォーマンスは低下する){Binding} マークアップ拡張 を使用します。
ユニバーサル Windows プラットフォーム (UWP) アプリの一般的な構造の 1 つは、ユーザーがマスター リストで選択を行うときに、さまざまな詳細ページに移動することです。 これは、階層内のすべてのレベルで各項目の豊富な視覚的表現を提供する場合に便利です。 もう 1 つのオプションは、1 つのページに複数のレベルのデータを表示することです。 これは、ユーザーが関心のある項目にすばやくドリルダウンできる簡単なリストをいくつか表示する場合に便利です。 このトピックでは、この相互作用を実装する方法について説明します。 CollectionViewSource インスタンスは、階層レベルごとに現在の選択を追跡します。
スポーツチームの階層構造をリーグ、部門、チームごとのリストに整理し、チームの詳細ビューを含むビューを作成します。 任意のリストから項目を選択すると、後続のビューが自動的に更新されます。
[前提条件]
このトピックでは、基本的な UWP アプリを作成する方法を知っていることを前提としています。 最初の UWP アプリを作成する手順については、「 C# または Visual Basic を使用して最初の UWP アプリを作成する」を参照してください。
プロジェクトを作成する
新しい ブランクアプリケーション (Windows ユニバーサル) プロジェクトを作成します。 "MasterDetailsBinding" という名前を付けます。
データ モデルを作成する
新しいクラスをプロジェクトに追加し、ViewModel.cs名前を付けて、このコードをプロジェクトに追加します。 これがバインディング ソース クラスになります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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
};
}
}
}
ビューを作成する
次に、マークアップのページを表すクラスからバインディング ソース クラスを公開します。 これを行うには、タイプ LeagueList のプロパティを MainPageに追加します。
namespace MasterDetailsBinding
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.ViewModel = new LeagueList();
}
public LeagueList ViewModel { get; set; }
}
}
最後に、MainPage.xaml ファイルの内容を次のマークアップに置き換えます。このマークアップは、3 つの CollectionViewSource インスタンスを宣言し、それらをチェーン内でバインドします。 その後、後続のコントロールは、階層内のレベルに応じて、適切な CollectionViewSource にバインドできます。
<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>
<CollectionViewSource x:Name="Leagues"
Source="{x:Bind ViewModel}"/>
<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="{ThemeResource 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>
CollectionViewSource に直接バインドすることで、コレクション自体にパスが見つからないバインド内の現在の項目にバインドすることを意味することに注意してください。 バインディングのパスとして CurrentItem プロパティを指定する必要はありませんが、あいまいさがある場合は指定できます。 たとえば、チーム ビューを表す ContentControl には、その Content プロパティが Teams
CollectionViewSource にバインドされています。 ただし、必要に応じて CollectionViewSource によって現在選択されているチームがチーム リストから自動的に提供されるため、Team
のコントロールは クラスのプロパティにバインドされます。