tags:

views:

105

answers:

3

I have a custom class that I would like to bind a WPF TreeView that has three tiers. Each tier needs to be bound like this:

    Monitor 
     --> LCD
          --> Samsung 1445 LCD
     --> CRT
          --> Sony 125 CRT

Here is the example code:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        SystemInventory sysInventory = new SystemInventory();
        //Possibly do something like this.
        _myTreeView.DataContext = sysInventory.DeviceGroupInstances; 
    }

    public class SystemInventory
    {
        public ObservableCollection<DeviceGroup> DeviceGroupInstances { get; set; }

        public SystemInventory()
        {
            DeviceGroupInstances = new ObservableCollection<DeviceGroup>();
            DeviceGroupInstances.Add(new DeviceGroup("Monitor"));
        }
    }

    public class DeviceGroup
    {
        public string DeviceGroupName { get; set; }
        public ObservableCollection<DeviceType> DeviceTypeInstances { get; set; }

        public DeviceGroup(string deviceGroupName)
        {
            DeviceTypeInstances = new ObservableCollection<DeviceType>();
            DeviceGroupName = deviceGroupName;

            if (deviceGroupName == "Monitor")
            {
                DeviceTypeInstances.Add(new DeviceType("LCD"));
                DeviceTypeInstances.Add(new DeviceType("CRT"));
            }               
        }
    }

    public class DeviceType
    {
        public string DeviceTypeName { get; set; }
        public ObservableCollection<DeviceInstance> DeviceInstances { get; set; }

        public DeviceType(string deviceGroupName)
        {
            DeviceInstances = new ObservableCollection<DeviceInstance>();
            DeviceTypeName = deviceGroupName;

            if (deviceGroupName == "Monitor")
            {
                DeviceInstances.Add(new DeviceInstance("Samsung 1445 LCD"));
            }
            else
            {
                DeviceInstances.Add(new DeviceInstance("Sony 125 CRT"));
            }                
        }
    }

    public class DeviceInstance
    {
        public string DeviceInstanceName { get; set; }

        public DeviceInstance(string instanceName)
        {
            DeviceInstanceName = instanceName;
        }
    }
}
A: 

You need to use a HierarchicalDataTemplate. There are many examples of this on Stack Overflow (and elsewhere) and if you search around you'll quickly find one. I would create a mock-up to illustrate it, but based on your very low accept rate, I'm not sure it would be worth it. You should look over your past questions and accept answers for all of them.

Charlie
Ah, I didn't see that I could do that. I went back and accepted the ones that worked.
Robert
I will gladly accept your answer if you provide an example.
Robert
I gave you a working example on a similar question:http://stackoverflow.com/questions/2877717/bind-object-to-wpf-treeview/2877899#2877899
Charlie
The change here is that all the binded properties aren't all named "Name". It's a little confusing in your answer how something like this would be accomplished.
Robert
A: 

Just translate the property names in the answer Charlie already gave you.

<TreeView ItemsSource="{Binding DeviceGroups}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding DeviceTypeInstances}">
            <HierarchicalDataTemplate.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding DeviceInstances}">
                    <TextBlock Text="{Binding DeviceInstanceName}"/>
                </HierarchicalDataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
            <TextBlock Text="{Binding DeviceTypeName}"/>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>
hemp
1. <TreeView ItemsSource="{Binding DeviceGroups}"> should be <TreeView ItemsSource="{Binding DeviceGroupInstances}">2. I get binding errors using your code.Error: 40 : BindingExpression path error: 'DeviceTypeName' property not found on 'object' ''DeviceGroup' (HashCode=5991653)'.Error: 40 : BindingExpression path error: 'DeviceInstanceName' property not found on 'object' ''DeviceType' (HashCode=24500892)'
Robert
A: 

First FIX

Change CTOR:

public MainWindow()
    {
        InitializeComponent();
        SystemInventory sysInventory = new SystemInventory();
        //Possibly do something like this.
        this.Content = sysInventory;
    }

Second FIX

Use XAML below (add to MainWindow), where {x:Type pc:MainWindow+SystemInventory} used for nested classes

<Window.Resources>
    <DataTemplate DataType="{x:Type pc:MainWindow+SystemInventory}">
        <TreeView ItemsSource="{Binding DeviceGroupInstances}"/>
    </DataTemplate>

    <HierarchicalDataTemplate DataType="{x:Type pc:MainWindow+DeviceGroup}" ItemsSource="{Binding DeviceTypeInstances}">
        <Label Content="{Binding DeviceGroupName}"/>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="{x:Type pc:MainWindow+DeviceType}" ItemsSource="{Binding DeviceInstances}">
        <Label Content="{Binding DeviceTypeName}"/>
    </HierarchicalDataTemplate>

    <DataTemplate DataType="{x:Type pc:MainWindow+DeviceInstance}">
        <Label Content="{Binding DeviceInstanceName}"/>
    </DataTemplate>

</Window.Resources>

About namespaces

Namespace is what you need to know to use classes. If your classes have namespace:

namespace MyCompany.MyProject.MyComponent
{
   public class SystemInventory
   {
      ....
   }
}

This namespace should be added to XAML with alias to use:

<Window x:Class="MyCompany.MyProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:myAlias="clr-namespace:MyCompany.MyProject.MyComponent" 

    Title="Window1" Height="300" Width="350">
    <Window.Resources>
    ...

Now you can use this classes in XAML like:

<DataTemplate DataType="{x:Type myAlias:DeviceInstance}">
   <Label Content="{Binding DeviceInstanceName}"/>
</DataTemplate>
SeeSharp
What if the class definition for devicegroup, devicetype, and deviceinstance were located in a folder called components? Where the components folder is located in the same directory as MainWindow?
Robert
See "About namespaces" added in my post.
SeeSharp