5

我想实现一个具有以下结构的树视图.....

[RootNode] <---- 树的根
--[ParentNode P1] <---- ModelClass P1 的对象
----[ChildNode C1] <----- ModelClass C1 的对象(有不同类型的孩子以及)
----[ChildNode C2] <----- ModelClass C2 的对象(也有不同类型的孩子)
----[ChildNode C3] <----- ModelClass C3 的对象(有不同类型的孩子)
--[ParentNode Q1] <---- ModelClass Q1 的对象
----[ChildNode B1] <----- ModelClass B1 的对象(也有不同类型的孩子)
- ---[ChildNode B2] <----- ModelClass B2 的对象(也有不同类型的孩子)
----[ChildNode B3] <----- ModelClass B3 的对象(也有不同类型的孩子)
--[ParentNode R1] <---- ModelClass R1 的对象
----[ChildNode A1] <----- ModelClass A1 的对象(也有不同类型的子节点)
----[ChildNode A2] <----- ModelClass A2 的对象(也有不同类型的孩子)
----[ChildNode A3] <----- ModelClass A3 的对象(也有不同类型的孩子)

我已经查看了本网站以及网络上提出的许多解决方案......但只是无法弄清楚如何去做......

这是我对 Wpf 的第一次尝试,这是一个至关重要的要求......

也很难为上述不同的类制作对象模型.....

上面显示的所有类还有其他属性,包括它们的子节点......我不想只显示子节点的所有属性

完全被...看到不同的解决方案感到困惑

如果我能在这方面得到一些帮助,那就太好了……

谢谢

4

3 回答 3

9

如果您使用自定义集合,分层数据模板就可以工作......我的课程是这样的:

public class EntityBase :ObservableCollection<object>
{

}

public class Parent : EntityBase
{

}  

public class ChildA : EntityBase // Dont make it a collection if it has noe childern to be displayed so dont inherit for EntityBase
{
   //Child Properties
}


public class ChildB : EntityBase
{
//Child Properties
}  

ChildA现在,当您最终将数据绑定到 TreeView 时,您会将ChildB项目作为Parent对象的子项,即

    public ObservableCollection<object> GetData()
    {
         var temp = new ObservableCollection<object>();
         Parent parent = new Parent(); // Root Node
         temp.Add(parent);
         parent.Add(new ChildA()); // ChildA as Child1 of Parent

         parent.Add(new ChildA()); // ChildA as Child2 of Parent

         parent.Add(new ChildB()); // ChildB as Child3 of Parent

         parent.Add(new ChildB()); // ChildB as Child4 of Parent

         return temp;

    }  

最后层次数据模板看起来像..

<TreeView Name="test" Grid.Row="0" ItemsSource="{Binding Path=TreeData,Source={StaticResource ResourceKey=DataSource}}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type EntityLayer:Parent}" ItemsSource="{Binding}">
                <StackPanel>
                    <TextBlock>Parent</TextBlock>
                </StackPanel>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type EntityLayer:ChildA}" ItemsSource="{Binding}">
                <StackPanel>
                    <TextBlock Text="{Binding Path = Name}"></TextBlock>
                </StackPanel>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type EntityLayer:ChildB}" ItemsSource="{Binding}">
                <StackPanel>
                    <TextBlock Text="{Binding Path = Name}"></TextBlock>
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>
于 2011-06-10T11:43:20.730 回答
2

如果这些类中的任何一个具有共同的基类,那么您会更容易,例如,您可以将一个DataTemplate用于多个类。

但是,如果这些模型中的每一个确实不同并且没有足够的共同点,那么您将需要使用 a 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而不是 an x:Key,即使集合是模糊的 ( List<object>),WPF 仍然会检查底层类型以确定它是否是P1// Q1etc。并找到正确HierarchicalDataTemplate的使用方法。我TreeView只需要看起来像这样:

<TreeView ItemsSource"{Binding}" />

但是,假设为了向您展示 aDataTemplateSelector您不能依赖它隐式匹配 by Type。您将x:Keys 放在您的数据模板上,例如:

<HierarchicalDataTemplate DataType="{x:Type loc:P1}" x:Key="myKeyforP1"
                          ItemsSource="{Binding}">
    <TextBlock>a P1 object</TextBlock>
</HierarchicalDataTemplate>

然后您的选择器可能会在内部使用 aDictionary来确定用于给定的资源键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>
于 2011-05-18T16:00:46.907 回答
0

您是否可以发布解决方案的更多详细信息。我正在尝试实现相同的目标,我添加了多个分层数据模板,但有兴趣查看对象模型。

就我而言,我有一个具有以下属性的父级

Public string Name { get; set; }
Public ObservableCollection<ChildA> ChildrenA { get; set; }
Public ObservableCollection<ChildB> ChildrenB { get; set; }

我想在我的树视图中显示这些。有兴趣知道我如何构建对象模型,因为我需要在树中显示在单个 ChildA 和 ChildB 集合之上的级别。

于 2011-06-08T12:59:28.787 回答