2

I am building an application to manage connections, databases, tables, etc. I am needing to bind a collection of items with multiple sub-collections (see below). I am pretty new to WPF and am not sure if an answer to this question already exists. I've searched but haven't found any examples of the scenario I am faced with.

server1
-database1
--functions <- "static" node
---function1
---function2
--users <- "static" node
---user1
---user2
-database2
--functions <- "static" node
---function3
---function4
--users <- "static" node
---user3
---user4

When I try to bind it, I can get the data to display but it isn't in the format needed above. It's displayed like this.

server1
-database1
--function1
--function2
--user1
--user2

object hierarchy:

class DatabaseViewModel
{
    public string Name
    {
         // normal getters and setters for 2way binding
    }
    public IObservableCollection<DbFunctionViewModel> Functions
    {
         // normal getters and setters for 2way binding
    }
    public IObservableCollection<DbUserViewModel> Users
    {
         // normal getters and setters for 2way binding
    }
}

Markup:

<TreeView x:Name="Connections">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type viewModels:DbConnectionViewModel}" ItemsSource="{Binding Databases}">
            <StackPanel Orientation="Horizontal">
                <TextBlock x:Name="Name" Text="{Binding Name}" />
            </StackPanel>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type viewModels:DbDatabaseViewModel}" ItemsSource="{Binding Children}">
            <StackPanel Orientation="Horizontal">
                <TextBlock x:Name="Name" Text="{Binding Name}" />
            </StackPanel>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type viewModels:DbFunctionViewModel}">
            <StackPanel Orientation="Horizontal">
                <TextBlock x:Name="Name" Text="{Binding Name}" />
            </StackPanel>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type viewModels:DbUserViewModel}">
            <StackPanel Orientation="Horizontal">
                <TextBlock x:Name="Name" Text="{Binding UserName}" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

I tried returning a CompositeCollection containing both and it didn't seem to work the way i need it to.

public IList Children
{
    get
    {
        return new CompositeCollection
        {
            new CollectionContainer { Collection = Functions },
            new CollectionContainer { Collection = Users }
        };
    }
}

My question is, how do you bind all the users to a node named users and all the functions to a node named functions? Any advice would be greatly appreciated. Thanks!

sbaker
  • 89
  • 1
  • 7
  • Could you mark your answer as accepted, if it solved the problem you stated? This would help keep the "unanswered questions" list clean :)) – Marcus Mangelsdorf Jan 19 '16 at 13:30

1 Answers1

1

To get your Children property to work, you need to define a data template for CollectionContainer:

<HierarchicalDataTemplate DataType="{x:Type viewModels:CollectionContainer}"
                          ItemsSource="{Binding Collection}">
    <TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>

You should add a string Name property to CollectionContainer:

public IList Children
{
    get
    {
        return new[]
        {
            new CollectionContainer("Functions", Functions),
            new CollectionContainer("Users", Users),
        };
    }
}

A few hints:

  1. Stack panels are redundant.
  2. x:Name is redundant if you're binding using Text={Binding ...}.
Athari
  • 33,702
  • 16
  • 105
  • 146
  • data templates for `CollectionContainer`? seems like it is not necessary to invent a new composite collection by CollectionContainer`s array. – pushpraj Sep 06 '14 at 01:26
  • Well CompositeCollection is a part of the .NET framework. Only reason I have that is a post someone had about binding multiple collection types. – sbaker Sep 06 '14 at 02:13
  • I agree with you @athari, the binding is redundant. I was just trying different things to get it to work. On the other hand, I have other items irrelevant to the problem inside the stackpanel (images, counts) that from what I've seen display properly using the stackpanel. But I agree, in the scope of the post, yes they are redundant. – sbaker Sep 06 '14 at 06:23
  • @StephenBaker The answer you linked to solves a different problem: they want to *concatenate collections* and display them as a *single list*; you want to display *several properties as a list* which expands into *multiple lists*. Obviously, using `CompositeCollection` won't solve your problem. And no matter what type you use instead of `CollectionContainer`, you'll need a template for it, because it's a separate node type. – Athari Sep 06 '14 at 10:37
  • Here is a link to the [post](http://stackoverflow.com/questions/3673173/wpf-treeview-databinding-hierarchal-data-with-mixed-types) I mentioned in my comment above. – sbaker Sep 06 '14 at 22:11
  • @StephenBaker Er... I remember clicking that link before and I'm referring to this QA in my previous comment. I'm confused. Anyway, I still don't see how it's relevant to your problem. – Athari Sep 06 '14 at 22:22
  • The only thing it has to do with my post is you guys were talking about the `CompositeCollection` and `CollectionContainer` classes and they are a part of the `System.Windows.Data` and I tried to add them hoping it would solve the problem I am faced with. – sbaker Sep 08 '14 at 21:30