3

I am trying to bind a collection of objects held by a Model to a treeview in WPF. My XML to do this was based on WPF Treeview Databinding Hierarchal Data with mixed types but I am not having any luck.

My current XAML looks like this for the treeview.

    <TreeView Name="ConfigurationFilter">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type models:MyModel}"  ItemsSource="{Binding Path=Filters.FilterType1}">
                <StackPanel Orientation="Horizontal">
                    <CheckBox></CheckBox>
                    <Label Content="{Binding Path=Name}"></Label>
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>

I have a model that looks like this

public class MyModel
{
    public Observable<MyFilter> FilterType1 {get;set;}
    public Observable<MyFilter> FilterType2 {get;set;}
}

public class MyFilter
{
    public string Name {get;set;}
    public bool IsSelected {get;set;}
}

Within my MainWindow.Xaml.cs I have the following:

public partial class MainWindow : Window
{
    public MyModel Filters { get; set; }
}

The FilterType1 property has 331 items in it. Yet when I run the app, the binding never happens. I do not see any items in my Treeview. What am I doing wrong?

Update 1

I have added my main window as the data context for the treeview and the binding as suggested but i still do not have any items in the tree

<TreeView Name="ConfigurationFilter" ItemsSource="{Binding Filters}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type models:MyModel}"  ItemsSource="{Binding Path=Filters.FilterType1}">
                <StackPanel Orientation="Horizontal">
                    <CheckBox></CheckBox>
                    <Label Content="{Binding Path=Name}"></Label>
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>

and my MainWindow.cs

    public MainWindow()
    {
        InitializeComponent();
        ConfigurationFilter.DataContext = this;
    }
Community
  • 1
  • 1
Johnathon Sullinger
  • 7,097
  • 5
  • 37
  • 102

2 Answers2

3

I was able to get this working by modifying my treeview to bind to a composite view model as demonstrated on CodeProject.

    <TreeView Grid.ColumnSpan="2" Grid.RowSpan="2">
        <TreeViewItem Header="Routes" Name="RouteView" ItemsSource="{Binding Routes}">
            <TreeViewItem.ItemTemplate>
                <HierarchicalDataTemplate DataType="{x:Type viewModels:RouteViewModel}"  ItemsSource="{Binding}">
                    <StackPanel Orientation="Horizontal">
                        <Label Content="{Binding Path=Name}" VerticalAlignment="Center"></Label>
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeViewItem.ItemTemplate>
        </TreeViewItem>
    </TreeView>

Since my treeview will have multiple root nodes that are pre-determined, I had to bind the datasource to each root TreeViewItem. Then I placed my objects into a composite viewmodel.

Composite View Model

public class DomainViewModel
{
    public ReadOnlyCollection<RouteViewModel> Routes { get; set; }
    public ReadOnlyCollection<SkyViewModel> SkyLines { get; set; }

    public DomainViewModel(List<Route> routes)
    {
        Routes = new ReadOnlyCollection<RouteViewModel>(
            (from route in routes
             select new RouteViewModel(route))
             .ToList<RouteViewModel>());
    }

        Skylines = new ReadOnlyCollection<SkyViewModel>(
            (from route in routes
             select new SkyViewModel(route))
             .ToList<SkyViewModel>());
    }
}

ViewModel - Only 1 shown to help readability.

public class RouteViewModel : INotifyPropertyChanged
{
    private Route _route; // My actual database model.

    public string Name
    {
        get { return _route.RouteName; }
    }

    public RouteViewModel(Route route)
    {
        _route = route;
    }
}

MainWindow

    public MainWindow()
    {
        InitializeComponent();

        this.DomainFilterTreeView.DataContext = new this.Domains;
    }
Johnathon Sullinger
  • 7,097
  • 5
  • 37
  • 102
0

TreeView doesn't have an ItemsSource bound to. Assuming the DataContext of the TreeView is your MainWindow, then you can add the ItemsSource binding.

<TreeView Name="ConfigurationFilter" ItemsSource={Binding Filters}>
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type models:MyModel}"  ItemsSource="{Binding Path=Filters.FilterType1}">
            <StackPanel Orientation="Horizontal">
                <CheckBox></CheckBox>
                <Label Content="{Binding Path=Name}"></Label>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
     ConfigurationFilter.DataContext = this;
    }

    public MyModel Filters { get; set; }
}
123 456 789 0
  • 10,565
  • 4
  • 43
  • 72
  • I gave this a shot and it still didn't work. I have updated my question to show my XAML and MainWindow.cs code using your example. Nothing is presented to the UI. Do you think this is an issue of me trying to bind to properties within a object such as Filters.FilterType1? – Johnathon Sullinger Feb 05 '14 at 23:15
  • How are you populating the Filters? It doesn't look like theres a code that will populate it. – 123 456 789 0 Feb 06 '14 at 03:30
  • Yeah, the MyObject is fetched from a repository. The repository populates the FilterType collections with data a database prior to returning the object to MainWindow. This happens in the window load method – Johnathon Sullinger Feb 06 '14 at 13:32
  • I should note that when I use the debugger within the Window_Loaded event, I can verify the collections have data. – Johnathon Sullinger Feb 06 '14 at 14:06