5

次のような構造のツリービューを実装したい.....

[RootNode]<----ツリーのルート
-[ParentNodeP1]<----ModelClassP1のオブジェクト
----[ChildNodeC1] <----- ModelClass C1のオブジェクト(異なるタイプの子を持つ同様に)
---- [ChildNode C2] <----- ModelClass C2のオブジェクト(異なるタイプの子も持つ)
---- [ChildNode C3] <----- ModelClass C3のオブジェクト(持つ異なるタイプの子も)
-[ParentNode Q1] <----ModelClassQ1のオブジェクト
----[ChildNodeB1] <----- ModelClass B1のオブジェクト(異なるタイプの子もあります)
- --- [ChildNode B2] <----- ModelClass B2のオブジェクト(異なるタイプの子もあります)
---- [ChildNode B3] <----- ModelClass B3のオブジェクト(異なるタイプの子もあります)
--[ParentNode R1] <----ModelClassR1のオブジェクト
----[ChildNodeA1] <----- 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
}  

これで、最終的にデータをTreeViewにバインドすると、オブジェクトの子アイテムとしてアイテムが作成さChildAれますChildBParent

    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複数のクラスに1つを使用できるようになります。

ただし、これらの各モデルが実際に異なり、共通点が十分でない場合は、を使用する必要がありますが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なかったためx:Key、コレクションがあいまいなList<object>場合でも()WPFは、基になる型を調べて、それが// P1etcQ1であるかどうかを判断します。使用する正しいものを見つけてHierarchicalDataTemplateください。私のTreeView唯一のように見える必要があります:

<TreeView ItemsSource"{Binding}" />

ただし、を示すために、がDataTemplateSelector暗黙的に一致することを信頼できないとしましょうTypex:Key次のように、データテンプレートにsを配置します。

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

次に、セレクターは内部でを使用しDictionaryて、特定のリソースキーに使用するリソースキーを決定する場合があります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()使用しようとするため、モデルの標準と、カスタムを使用している場合にのみ使用されるカスタマイズされたバージョンを使用できます。TypeHierarchicalDataTemplateTreeViewDataTemplateSelector

<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 に答える