web-dev-qa-db-ja.com

型が混在するWPF Treeviewデータバインディング階層データ

WPF Treeview Bindingで少し複雑な状況があります。私は過去2日間Googleを試してみましたが、 this は私が思いついた閉鎖ですが、問題は解決しません。

ここに状況があります:

次のようなオブジェクトがあります。

public class Category
{
  public string Name { get; set; }
  public List<Category> Categories { get; set; }
  public List<Product> Products { get; set; }
}

public class Product
{
  public string Name { get; set;
}

各カテゴリには、オブジェクトと子カテゴリのリストを含めることができます。私がこれを完全に理解できる理由があり、私が書いているアプリもあります。

実際のオブジェクト構造は次のようになります。

Category - Pharmacy
  |-Product - Aspirin
  |-Product - Tylenol
  |-Category - Tooth Paste
  |  |-Product - Crest
  |  |-Product - Colgate
  |-Category - Paper Products
   |-Category - Toilet Paper
   |  |-Product - NoName
   |  |-Product - Charmin
   |-Category - Facial Tissue
      |-Product - Kleenex
Category - Household
  |-Product - Pinesol Cleaner
  |-Product - Garbage Bags

今、私はこの関係をツリービューにデータバインドしようとしています。 TreeViewが上記のオブジェクト構造とほとんど同じに見えるようにしたいと思います。

これまでのところ、XAML Treeviewは次のようになっています。

  <TreeView x:Name="CategoryList" Margin="8" Grid.Row="2" Grid.RowSpan="2" ItemsSource="{Binding Path=Categories}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type src:Category}" ItemsSource="{Binding Products}">
                    <StackPanel>
                        <TextBlock Text="{Binding Path=Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type src:Product}">
                    <StackPanel>
                        <TextBlock Text="{Binding Path=Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>

これは、カテゴリのメインリストとそのサブ製品のそれぞれに最適です。しかし、それはさらに深くはならず、各カテゴリーの下にサブカテゴリーを表示します。

テンプレートを使用してこれを直接実行し、各アイテム(カテゴリまたは製品)を選択する方法はありますか?私はMVVMパターンを使用しており、コードビハインドを使用したくありませんが、必要な場合は使用します。

35
thorkia

TreeViewの要素には、Category Productsの両方で構成される子のリストが必要なので、Category ViewModelには、CategoryとProductsの両方で構成されるコレクションが必要です。たとえば、 CompositeCollection を使用して既存のコレクションを組み合わせることができます。

public class Category
{
    public string Name { get; set; }
    public List<Category> Categories { get; set; }
    public List<Product> Products { get; set; }

    public IList Children
    {
        get
        {
            return new CompositeCollection()
            {
                new CollectionContainer() { Collection = Products },
                new CollectionContainer() { Collection = Categories }
            };
        }
    }
}

(実際のコードでは、毎回新しいコレクションオブジェクトを作成するのではなく、同じコレクションオブジェクトへの参照を保持することをお勧めします。)

次に、HierarchicalDataTemplateで、結合したリストをItemsSourceとして使用します。

<HierarchicalDataTemplate DataType="{x:Type src:Category}"
                          ItemsSource="{Binding Children}">

アイテムはProductオブジェクトとCategoryオブジェクトの混合であり、WPFはそれぞれに適切なDataTemplateを使用します。

56
Quartermeister