ちょいとCollectionViewSourceを使ったパターンを試してみました。CollectionViewSourceに適当なデータを突っ込みます。
<!-- MainPage.xaml --><CollectionViewSourcex:Name="source" />
// MainPage.xaml.csprivate ObservableCollection<Person> people = new ObservableCollection<Person>(); privatevoid navigationHelper_LoadState(object sender, LoadStateEventArgs e) { this.source.Source = people; }
DataTemplateSelectorを使いたいので以下のような感じで適当なのを作りました。
using MasterDetailApp.DataModel; using System; using System.Collections.Generic; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace MasterDetailApp.Common { publicclass PersonDataTemplateSelector : DataTemplateSelector { public IList<DataTemplate> Templates { get; private set; } public PersonDataTemplateSelector() { this.Templates = new List<DataTemplate>(); } protectedoverride DataTemplate SelectTemplateCore(object item, DependencyObject container) { if(item == null) { returnnull; } var p = (Person)item; returnthis.Templates[Math.Abs(p.Age) % this.Templates.Count]; } } }
MainPage.xamlのリソースにNull用のPersonオブジェクトとともに定義をしておきます。
<dataModel:Person x:Key="NullPerson"Name="NullPerson"Age="-1" /><common:PersonDataTemplateSelector x:Key="personTemplateSelector"><common:PersonDataTemplateSelector.Templates><DataTemplate><Border Padding="10"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><TextBlock Style="{StaticResource BaseTextBlockStyle}"TextWrapping="Wrap"Text="名前:"/><TextBlock Style="{StaticResource BaseTextBlockStyle}"Grid.Row="1"TextWrapping="Wrap"Text="年齢:"/><TextBlock Style="{StaticResource BaseTextBlockStyle}"Grid.Column="1"TextWrapping="Wrap"Text="{Binding Name}"/><TextBlock Style="{StaticResource BaseTextBlockStyle}"Grid.Column="1"Grid.Row="1"TextWrapping="Wrap"Text="{Binding Age}"/></Grid></Border></DataTemplate><DataTemplate><Border Background="Red"Padding="10"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><TextBlock Style="{StaticResource BaseTextBlockStyle}"TextWrapping="Wrap"Text="名前:"/><TextBlock Style="{StaticResource BaseTextBlockStyle}"Grid.Row="1"TextWrapping="Wrap"Text="年齢:"/><TextBlock Style="{StaticResource BaseTextBlockStyle}"Grid.Column="1"TextWrapping="Wrap"Text="{Binding Name}"/><TextBlock Style="{StaticResource BaseTextBlockStyle}"Grid.Column="1"Grid.Row="1"TextWrapping="Wrap"Text="{Binding Age}"/></Grid></Border></DataTemplate></common:PersonDataTemplateSelector.Templates></common:PersonDataTemplateSelector>
背景色なしと、背景色赤の2パターンのDataTemplateから年齢をもとに選択して返します。
んで、MasterとなるListBoxとDetailとなるContentControlをさくっと定義します。ContentControlのほうのBindingはPathにCurrentItemを指定するようにしておきました。こうすることで、現在選択中のアイテムを強制的にわたせるかな。
<ListBox Grid.Row="1"Margin="15"ItemsSource="{Binding Source={StaticResource source}}"ItemTemplateSelector="{StaticResource personTemplateSelector}"><ListBox.ItemContainerStyle><Style TargetType="ListBoxItem"><Setter Property="HorizontalContentAlignment"Value="Stretch" /><Setter Property="VerticalContentAlignment"Value="Stretch" /></Style></ListBox.ItemContainerStyle></ListBox><ContentControl Grid.Column="1"Grid.Row="1"Margin="15"Content="{Binding CurrentItem, Source={StaticResource source}, TargetNullValue={StaticResource NullPerson}}"ContentTemplateSelector="{StaticResource personTemplateSelector}"HorizontalContentAlignment="Stretch"VerticalContentAlignment="Stretch" />
あとは、AppBarに適当にボタンをおいて要素の追加や削除や選択解除などの処理を書いてみました。
privatevoid CreateData() { // 適当にデータをつくる var items = Enumerable.Range(1, 20) .Select(i => new Person { Name = "田中" + i, Age = i }); foreach (var item in items) { this.people.Add(item); } } privatevoid ClearData() { // データクリアthis.people.Clear(); } privatevoid AddData() { // 適当にデータを追加this.people.Add(new Person { Name = "tanaka" + this.people.Count, Age = 100 }); } privatevoid AppBarButton_Click(object sender, RoutedEventArgs e) { this.ClearData(); } privatevoid AppBarButton_Click_1(object sender, RoutedEventArgs e) { this.AddData(); } privatevoid AppBarButton_Click_2(object sender, RoutedEventArgs e) { this.ClearData(); this.CreateData(); } privatevoid AppBarButton_Click_3(object sender, RoutedEventArgs e) { // 選択解除 ICollectionView v = this.source.View; v.MoveCurrentTo(null); } privatevoid AppBarButton_Click_4(object sender, RoutedEventArgs e) { // 選択中の要素を削除if (source.View.CurrentItem == null) { return; } source.View.Remove(source.View.CurrentItem); }
実行して動かしてみると。 起動直後。
データ作ってみたところ
選択してみたところ
選択したものを削除したところ
データを選択してからクリアしたところ
ここまでの一連の操作をしたときのVSのデバッグ出力
'MasterDetailApp.exe' (CLR v4.0.30319: DefaultDomain): 'C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: DefaultDomain): 'c:\users\kazuki\documents\visual studio 2013\Projects\MasterDetailApp\MasterDetailApp\bin\Debug\AppX\MasterDetailApp.exe' が読み込まれました。シンボルが読み込まれました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\system32\WinMetadata\Windows.UI.Xaml.winmd' が読み込まれました。モジュールがシンボルなしでビルドされました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.InteropServices.WindowsRuntime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.WindowsRuntime.dll' が読み込まれました。モジュールがシンボルなしでビルドされました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\system32\WinMetadata\Windows.ApplicationModel.winmd' が読み込まれました。モジュールがシンボルなしでビルドされました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Threading.Tasks\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Threading.Tasks.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\system32\WinMetadata\Windows.UI.winmd' が読み込まれました。モジュールがシンボルなしでビルドされました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\system32\WinMetadata\Windows.Foundation.winmd' が読み込まれました。モジュールがシンボルなしでビルドされました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.WindowsRuntime\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.WindowsRuntime.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Diagnostics.Debug\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Diagnostics.Debug.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.WindowsRuntime.UI.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.WindowsRuntime.UI.Xaml.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\system32\WinMetadata\Windows.Globalization.winmd' が読み込まれました。モジュールがシンボルなしでビルドされました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Collections\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Collections.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'c:\users\kazuki\documents\visual studio 2013\Projects\MasterDetailApp\MasterDetailApp\bin\Debug\AppX\GalaSoft.MvvmLight.DLL' が読み込まれました。PDB ファイルを開けないか、ファイルが見つかりません。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ObjectModel\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.ObjectModel.dll' が読み込まれました。モジュールがシンボルなしでビルドされました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Extensions\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.Extensions.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Threading\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Threading.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\system32\WinMetadata\Windows.System.winmd' が読み込まれました。モジュールがシンボルなしでビルドされました。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Linq\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Linq.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。 'MasterDetailApp.exe' (CLR v4.0.30319: Immersive Application Domain): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll' が読み込まれました。シンボルの読み込みをスキップしました。モジュールは最適化されていて、デバッグ オプションの [マイ コードのみ] 設定が有効になっています。
あやしげなバインド系のエラーは出てなさそう。ということで、ストアアプリでマスター詳細シナリオで出てたエラーはContentControlのBindingにCurrentItem渡してやればエラーでなくなりそう・・・?