找出 WPF 中 4 级树视图项的绑定

Figuring Out Bindings for 4 level Tree View item in WPF

我有一个看起来像这样的产品的平面文件:

 public List<Product> Products = new List<Product>{
 new Product{Name = "OIS Swap", AssetType="Rates",ProductType="Swap",Currency="USD"},
 new Product{Name = "Libor Swap", AssetType ="Rates",ProductType="Swap",Currency="USD"},};

我想通过如下分类在 WPF 中填充 TreeView:

USD
--Rates
----Swap
------OIS Swap

首先,我使用 Linq 生成了一个 4 级层次结构,如下所示:

class HierarchyViewModel{
    public static IEnumerable<CurrencyViewModel> Currency {get;set;}
       public  HierarchyViewModel()
        {
            Currency = Products
                .OrderBy(prod => prod.Currency)
                .GroupBy(prod => prod.Currency)
                .OrderBy(group=> group.Key)
                .Select(group =>
                    new CurrencyViewModel(group.Key, group.Select(prod => prod).ToArray()
                        )
                        ).ToArray();

        }
    }

    class CurrencyViewModel
    {
        public string currency;
        public IEnumerable<AssetTypeViewModel> AssetTypes { get; set; } 

        public CurrencyViewModel(string currency, IEnumerable<Product> CurrencySorted)
        {
            this.currency = currency;
            AssetTypes = CurrencySorted
                         .OrderBy(prod => prod.AssetType)
                         .GroupBy(prod => prod.AssetType)
                         .OrderBy(group => group.Key)
                         .Select(group => new AssetTypeViewModel(group.Key, group.Select(prod => prod).ToArray()
                             )
                             ).ToArray();
        }
    }


    class AssetTypeViewModel
    {
       public string assettype;

       public IEnumerable<ProductTypeViewModel> ProductType { get; set; }

      public  AssetTypeViewModel(string assettype, IEnumerable<Product> AssetSorted)
       {
           this.assettype = assettype;
           ProductType = AssetSorted
               .OrderBy(prod => prod.ProductType)
               .GroupBy(prod => prod.ProductType)
               .OrderBy(group => group.Key)
               .Select(group => new ProductTypeViewModel(group.Key, group.Select(prod => prod).ToArray()
                   )
                   ).ToArray();
       }

    }

    class ProductTypeViewModel
    {
        string producttype;
        public IEnumerable<Product> Products;
        public ProductTypeViewModel(string producttype,IEnumerable<Product> ProductSorted)
        {
            this.producttype = producttype;
            Products = ProductSorted
                .OrderBy(prod => prod.ProductType)
                .Select(prod => prod).ToArray();
        }
    }

在我的 XAML 中,我进行如下绑定:

        <TreeView.Resources>
            <HierarchicalDataTemplate  DataType="{x:Type xy:CurrencyViewModel}" ItemsSource="{Binding currency}">
            <TextBlock Text="{Binding currency}"/>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate  DataType="{x:Type xy:AssetTypeViewModel}" ItemsSource="{Binding assettype}">
                <TextBlock Text="{Binding assettype}"/>
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate  DataType="{x:Type xy:ProductTypeViewModel}" ItemsSource="{Binding producttype}">
                <TextBlock Text="{Binding producttype}"/>
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type xy:Product}" >
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>

        </TreeView.Resources>

    </TreeView>

我的用户控件的代码隐藏是

public GraphTreeView()
        {
            InitializeComponent();


            MyTree.DataContext = new HierarchyViewModel();
         }

但由于某种原因,树视图未填充。我测试了 Hierachy 生成,它似乎按预期工作。我确定我的绑定中存在一些错误,非常感谢您帮助我解决问题。 提前致谢!

Update :使用 Xavier 的回答,我能够深入了解: 美元 ---费率 - - 交换 还缺最后一关

更新 2 经过一番争论,并使用 Snoop 检查其绑定方式,我 'hacked' 进入了答案。事实证明,绑定 (如预期的那样)吐出一个没有 ToString() 方法定义的 'Product' classes 列表。我覆盖了我的 class 定义中的那些,并使用 ItemContainerStyle 作为资源来定义最后一条腿绑定。如果有人感兴趣,这里是完整的 XAML。非常感谢 Xavier 让我走上了正确的道路。

<UserControl.Resources>
        <xy:ProducttoNameConverter x:Key="ProductToNameConverter"/>
        <ItemContainerTemplate x:Key="LastLegConverter">          

            <TextBlock Text="{Binding}"/>

        </ItemContainerTemplate>

    </UserControl.Resources>
 <TreeView  x:Name="MyTree"  ItemsSource="{Binding Currency}"> 

            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type xy:CurrencyViewModel}" ItemsSource="{Binding AssetTypes }" >

                   <TextBlock Text="{Binding MyCurrency}"/>
                </HierarchicalDataTemplate>

                <HierarchicalDataTemplate DataType="{x:Type xy:AssetTypeViewModel}" ItemsSource="{Binding ProductType}">

                    <TextBlock Text="{Binding MyAssetType}"/>

                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type xy:ProductTypeViewModel}" ItemTemplate="{StaticResource LastLegConverter}" ItemsSource="{Binding Products}">
                    <TextBlock Text="{Binding MyProductType}"/>


                </HierarchicalDataTemplate>

                </TreeView.Resources>

确保将 TreeView 本身上的 ItemsSource 设置为最外层集合。此外,您需要将每个数据模板上的 ItemsSource 属性 设置为关联视图模型中子项的集合。

例如:

<TreeView ItemsSource="{Binding Currency}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type xy:CurrencyViewModel}" ItemsSource="{Binding AssetTypes}">
            <TextBlock Text="{Binding currency}"/>
        </HierarchicalDataTemplate>
        ...
    </TreeView.Resources>
</TreeView>

TreeView 上设置 ItemsSource 启动填充控件的过程,然后为集合中的项目定义的数据模板控制每个项目的呈现方式。

HiearchicalDataTemplate 的目的是通知每个子视图在哪里可以找到该类型每个项目的子项目。因此,每个 TreeViewItem 将使用关联模板的内容来构建其视图,并使用 ItemsSource 属性 来查找要为其创建自己的子视图的项目集合。该过程一直持续到生成整棵树。