wpfでツリービューを使用する例がたくさんあることを理解しています。信じがたいことは承知していますが、StackOverflow にすでにあるツリービューに関する無数の質問によってまだ対処されていない正当な質問があると思います。
( TL;DRバージョン: たくさんのことを試しました。たくさんの Web サイトを見ました。複雑なツリー構造を持っています。望ましいツリー結果を達成する簡単な方法を探しています。質問は一番下にあります。)
だからここに行きます...
TreeViewsに関するJoshの有名な投稿を読みました
もちろん、Philipp Sumiは、TreeView の使用に関する非常に役立つ投稿を行っています。
目的の出力の要点は、異なるタイプのアイテムがそれぞれのヘッダーの下に表示され、オブジェクトを異なる場所で 2 回表示できることです。DataTemplateSelector だけでは、目的のTreeView
.
望ましい出力:
Root
|--Header A (People)
|---Person A1 (Jane)
|---Person A2 (Steve)
|--Header B (Cars)
|---Car B1 (Red Car)
|---Car B2 (Blue Car)
|---Person A1 (Jane)
|---Person A3 (Jon)
注: A3 はSO のチャック ノリスであるジョンスキートです。
私のアプローチの最初の部分は、CompositeCollection
実際には使用していませんが、本質的に a を使用することです。それにもかかわらず、この投稿は、私の問題を解決しないことを示唆しているようです。人として、つまり。Steve のデータには、他の人、車、またはその他のオブジェクトが含まれていないため、彼は最終品目です。
モデルを見る:
私が拘束しているのはこれです:
public ObservableCollection<object> Children
{
get
{
ObservableCollection<object> childNodes = new ObservableCollection<object>();
foreach (var person in PeopleCollection)
childNodes.Add(person);
foreach (var car in CarCollection)
childNodes.Add(car);
return childNodes;
}
}
テンプレートセレクター:
TreeView で複数のタイプのオブジェクトを管理する必要があるため、DataTemplateSelector を使用しています。
class MyTemplateSelector : DataTemplateSelector
{
public HierarchicalDataTemplate CarTemplate { get; set; }
public HierarchicalDataTemplate PeopleTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item.GetType() == typeof(Car))
return CarTemplate;
if (item.GetType() == typeof(Person))
return (PeopleTemplate);
return (null);
}
}
XAML:
最後に、これをうまくまとめるための XAML があります。
<UserControl.Resources>
<HierarchicalDataTemplate x:Key="m_CarTemplate"
DataType="{x:Type local:Car}"
ItemsSource="{Binding People}" >
<TextBlock Text="{Binding CarColor}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="m_PeopleTemplate"
DataType="{x:Type local:Person}">
<TextBlock Text="{Binding PersonName}" />
</HierarchicalDataTemplate>
<local:ProjectTemplateSelector
CarTemplate="{StaticResource m_CarTemplate}"
PeopleTemplate ="{StaticResource m_PeopleTemplate}"
x:Key="myTemplateSelector"/>
</UserControl.Resources>
XAML のもう少し下:
<TreeView Width="Auto" Height="Auto" HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="0,0,0,0" Name="m_TreeView"
ItemsSource="{Binding ViewModel.Children}"
ItemTemplateSelector="{StaticResource myTemplateSelector}"
/>
考えられる解決策:
Philipp のアプローチに対する主な後退は、理想的には最初のレベルでカテゴリを設定したいだけです<TreeViewItem Header="Cars" />
が、それは失敗するように思われることです。次に、これらのカテゴリ レベルのアイテムのアイテムがありません。単なる文字列である車と人。これらのプレースホルダーオブジェクトを作成し、viewModel でそれらからプロパティを作成するよりもそれぞれのコレクションを与えることができると思いますが、ヘッダーを取得するだけでは少し過剰に思えます...特に既に存在するためです。
2番目のオプションはCompositeCollection アプローチですが、良い例がありますが、それが私の問題を解決するかどうかは完全にはわかりません。1 つには、これが TreeView で使用されているのを見たことがないので、そこで適切に適用されるかどうかわからないため、TreeView を使用してデータの階層的な性質を維持したいと考えています。
最後に、私は独自のバリエーションHierarchicalDataTemplate
を追加しようとしました<TreeViewItem Header="Cars" />
が、すべての車が独自のヘッダーを取得するため、これは機能しません。
質問
主な質問: TreeView の目的の構造を実現するためのバインディングによる適切な方法は何ですか? したがって、すべての車が Cars ヘッダーの下に表示され、People ヘッダーの下に People が表示される結果が生成されます。ただし、Cars.PeopleCollection にある人は、それぞれの Car オブジェクトの子としても表示されます。
二次的な質問: TreeViewItems 専用の Wrapper クラスを作成するための一般的で適切な方法はありますか? それは私がすべきことですか?Philipp's Potential Solution で説明したように。
ここで説明したソリューションが与えられた場合、コードはコンパイルされることにも言及する必要があります。問題は、ヘッダーがないことです。次の問題は、車に人を追加してから車を拡張しようとすると、次のエラーが表示されることです:Must disconnect specified child from current parent Visual before attaching to new parent Visual.
これは、このコード行の製品だと思います:ObservableCollection<object> childNodes = new ObservableCollection<object>();
しかし、率直に言って、遅くて疲れているので、できるこれを行う適切な方法を考え出さないでください。おそらく CompositeCollection が必要です。