首页 > 解决方案 > WPF Treeview绑定多个不同的列表

问题描述

我想将多个不同的列表绑定到 WPF 中的 TreeView。我查找了其他一些解决方案,但找不到任何解决我的问题的方法。这个答案非常接近,但不是我想要的。

我尝试了上面的链接解决方案,但它只在 TreeView 中显示两个级别。我不知道如何在 TreeView 中将每个列表的名称显示为父级。

我要显示的对象如下所示:

public class LightDistributor
{
  public string Description { get; set; }
  // ...

  public List<Field> Hardware { get; set; }
  public List<Type> Inputs { get; set; }
  public List<Type> Outputs { get; set; }
}

public class Field
{
  public string Fieldname { get; set; }
  // ...
}

public class Type
{
  public string TypeDescription { get; set; }
  // ...
}

和 XAML:

<TreeView ItemsSource="{Binding LightDistributors}">
  <TreeView.ItemTemplate>
    <HierarchicalDataTemplate DataType="{x:Type data:LightDistributor}" ItemsSource="{Binding Hardware}">
       <TextBlock Text="{Binding Description}" />
       <HierarchicalDataTemplate.ItemTemplate>
          <DataTemplate DataType="{x:Type data:Field}">
               <TextBlock Text="{Binding Description}" />
          </DataTemplate>
       </HierarchicalDataTemplate.ItemTemplate>
    </HierarchicalDataTemplate>
  </TreeView.ItemTemplate>   
</TreeView>

我希望我的 Treeview 看起来:

LightDistributor - LongFloor
    | Hardware
        - Field1
        - Field2
        - Field3
    | Inputs
        - InputTypeA
        - InputTypeB
    | Outputs
        - OutputTypeY
        - OutputTypeZ

它目前的样子:

LightDistributor - LongFloor
        - Field1
        - Field2
        - Field3

根据 SelectedItem,将显示带有更多参数的 UserControl。

标签: c#wpftreeviewhierarchicaldatatemplate

解决方案


添加一个NamedSection,它将名称与项目列表分组:

public class NamedSection
{
    public string Name { get; set; }
    public IReadOnlyList<object> Items { get; set; }
}

然后更新你的LightDistributor. 请注意我是如何将List<T>属性设置为仅获取器的,以便NamedSection可以正确捕获构造时的引用。

public class LightDistributor
{
    public string Description { get; set; }
    // ...

    public List<Field> Hardware { get; } = new List<Field>();
    public List<Type> Inputs { get; } = new List<Type>();
    public List<Type> Outputs { get; } = new List<Type>();

    public List<NamedSection> Sections { get; }

    public LightDistributor()
    {
        this.Sections = new List<NamedSection>()
        {
            new NamedSection() { Name = "Hardware", Items = this.Hardware },
            new NamedSection() { Name = "Inputs", Items = this.Inputs },
            new NamedSection() { Name = "Outputs", Items = this.Outputs },
        };
    }
}

然后你的 XAML:

<TreeView ItemsSource="{Binding LightDistributors}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:LightDistributor}" ItemsSource="{Binding Sections}">
            <TextBlock Text="{Binding Description}" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:NamedSection}" ItemsSource="{Binding Items}">
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>
        <DataTemplate DataType="{x:Type local:Field}">
            <TextBlock Text="{Binding Fieldname}"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:Type}">
            <TextBlock Text="{Binding TypeDescription}"/>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

我最初认为您也可以通过将 of 声明x:ArrayTreeViewItem资源(硬件、输入、输出各有一个项目)然后将其设置为 LightDistributor 的 HierarchicalTemplate 的 ItemsSource 来实现这一点。但是这不起作用,因为似乎没有办法为x:Array我们要显示的每个 LightDistributor 克隆它。


推荐阅读