これらのクラスのいずれかに共通の基本クラスがあると、たとえば、DataTemplate
複数のクラスに1つを使用できるようになります。
ただし、これらの各モデルが実際に異なり、共通点が十分でない場合は、を使用する必要がありますがDataTemplateSelector
、組み込みのメカニズムで十分な場合があります。
設定
同様の状況を再現するために私が作成した基盤の一部を次に示します。異なるクラスはそれぞれから継承するList<object>
ため、任意のタイプの子を含む組み込みの方法がありますが、データテンプレートを選択する際にその共通性に依存していません。
public class P1 : List<object> {
public P1() {}
public P1( IEnumerable<object> collection ) : base( collection ) {}
}
さらに、私のルートデータソースはタイプでList<object>
あるため、任意のタイプのオブジェクトを含めることができます。
のWindow
コンストラクタ:
public MainWindow() {
InitializeComponent();
this.DataContext = MyDataSource.GetData(); // in which I construct the tree of parents and children
}
解決
HierarchicalDataTemplate
タイプごとにsを作成することから始めます。いずれかのタイプに子が含まれていない場合は、もちろん、DataTemplate
代わりにsを作成します。
<HierarchicalDataTemplate DataType="{x:Type loc:P1}"
ItemsSource="{Binding}">
<TextBlock>a P1 object</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type loc:C1}"
ItemsSource="{Binding}">
<TextBlock>a C1 object</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type loc:C2}"
ItemsSource="{Binding}">
<TextBlock>a C2 object</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type loc:Q1}"
ItemsSource="{Binding}">
<TextBlock>a Q1 object</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type loc:B1}"
ItemsSource="{Binding}">
<TextBlock>a B1 object</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type loc:B2}"
ItemsSource="{Binding}">
<TextBlock>a B2 object</TextBlock>
</HierarchicalDataTemplate>
各クラスList<object>
はの子孫であるため、オブジェクト自体がプロパティのコレクションではなく子アイテムのソースであるため、を使用しますItemsSource="{Binding}"
。もちろん、子アイテムがというプロパティの下のコレクションにある場合は、Children
代わりになりますItemsSource="{Binding Children}"
。これにより、各オブジェクトの子を異なる場所に配置できます。
この例でを実装する最も簡単な方法DataTemplateSelector
は、何もしないことです。を指定しただけで、データテンプレートにはを指定しDataType
なかったためx:Key
、コレクションがあいまいなList<object>
場合でも()WPFは、基になる型を調べて、それが// P1
etcQ1
であるかどうかを判断します。使用する正しいものを見つけてHierarchicalDataTemplate
ください。私のTreeView
唯一のように見える必要があります:
<TreeView ItemsSource"{Binding}" />
ただし、を示すために、がDataTemplateSelector
暗黙的に一致することを信頼できないとしましょうType
。x:Key
次のように、データテンプレートにsを配置します。
<HierarchicalDataTemplate DataType="{x:Type loc:P1}" x:Key="myKeyforP1"
ItemsSource="{Binding}">
<TextBlock>a P1 object</TextBlock>
</HierarchicalDataTemplate>
次に、セレクターは内部でを使用しDictionary
て、特定のリソースキーに使用するリソースキーを決定する場合がありますType
(これは単純な実装であることに注意してください)。
public class CustomDataTemplateSelector : DataTemplateSelector {
static Dictionary<Type, object> typeToKey = new Dictionary<Type, object>();
static CustomDataTemplateSelector() {
typeToKey[ typeof( P1 ) ] = "myKeyforP1";
}
public override DataTemplate SelectTemplate( object item, DependencyObject container ) {
var element = container as FrameworkElement;
if ( element != null && item != null ) {
var itemtype = item.GetType();
object keyObject;
if ( typeToKey.TryGetValue( itemtype, out keyObject ) ) {
var template = element.TryFindResource( keyObject ) as DataTemplate;
if ( template != null ) {
return template;
}
}
}
return base.SelectTemplate( item, container );
}
}
次に、セレクターをリソースディクショナリに追加すると、TreeView
別のプロパティを割り当てる必要があります。
<Grid.Resources>
<loc:CustomDataTemplateSelector x:Key="mySelector" />
</Grid.Resources>
<TreeView ItemsSource="{Binding}"
ItemTemplateSelector="{StaticResource mySelector}"></TreeView>
また、アイテムをリソースキーとしてbase.SelectTemplate()
使用しようとするため、モデルの標準と、カスタムを使用している場合にのみ使用されるカスタマイズされたバージョンを使用できます。Type
HierarchicalDataTemplate
TreeView
DataTemplateSelector
<HierarchicalDataTemplate DataType="{x:Type loc:P1}"
ItemsSource="{Binding}">
<TextBlock>a P1 object</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type loc:P1}" x:Key="myKeyforP1"
ItemsSource="{Binding}">
<TextBlock>a P1 that looks much different</TextBlock>
</HierarchicalDataTemplate>