TreeViews

Aug 25, 2010 at 4:23 AM

You knew this question had to come up eventually... :)

I want to create a view that contains a TreeView. That tree view is bound to a BindableCollection<TreeItemViewModels>. The TreeItemViewModels has a property Children that is BindableCollection<TreeItemViewModels>. Out of the box, the top level view models create and display the associated view class (TreeItemView), but none of the children show up. I know how to solve this using HierarchalDataTemplates, but only if I do the 'view' rendering inline instead of creating all the nested view classes. How do I get the child views to render? Or should I even bother? Should I just render inline, catch the events the view-model containing the root collection, and act on the selected node?

Thanks as always

Aug 25, 2010 at 3:52 PM

Solved it. Once again CM is flexible - and predictable - which makes solving these minor issues almost fun. :)

There will definitely be a blog post on this, but until then, here is the simple solution:

    <TreeView ItemsSource="{Binding TreeData}">
      <TreeView.Resources>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type ViewModels:TreeItemViewModel}">
          <Views:TreeItemView Micro:Bind.Model="{Binding}" />
        </HierarchicalDataTemplate>
      </TreeView.Resources>
    </TreeView>

I had to go view first for the tree item, and then bind to the model of the item. I would have preferred for CM to figure out the view for me, but I haven't figured out how to do that yet.

The down side to this approach is that I will need a new HierarchicalDataTemplate for each type of view-model in the tree collection. Where I would like to rely on the framework to create the right view based on the view-model.

Coordinator
Aug 25, 2010 at 7:22 PM

Would this work?

 

<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<ContentControl Micro:View.Model="{Binding}" />
</HierarchicalDataTemplate>

 

Aug 25, 2010 at 7:41 PM

I am pretty sure I tried that, and the tree view was populated with text strings showing the class name of the view model. I will verify.

Aug 25, 2010 at 10:04 PM

 

Rob,

 

that works out pretty well in my context, many thanks. Would really be worth a recipe, maybe together with on-demand loading of nodes in the tree.

 

Lars

Nov 17, 2010 at 9:30 PM

Sorry to "wake" a rather old thread to life, but I have a somewhat related question.

I have a TreeView almost like the above example (but no actual view models, just a simple class in this case). When I click an item in the TreeView, I want to know wich item I clicked and take action from there, but when I'm attaching

cal:Message.Attach="[Event SelectedItemChanged] = [Action Test($dataContext)]"

to my TreeView, the Action "Test" gets called but the parameter is always null.

This is my XAML for the treeview:

<TreeView ItemsSource="{Binding MyItems}" cal:Message.Attach="[Event SelectedItemChanged] = [Action Test($dataContext)]">
    <TreeView.Resources>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}"
                                    DataType="{x:Type CaliburnTest:MyClass}">
            <TextBlock Text="{Binding Name}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

As I said, my "public void Test(MyClass myClass)..." get's called on my view model, but the parameter is null. Any ideas on how to solve this?

Thanks for a great framework btw!

//J

Nov 17, 2010 at 9:52 PM

I worked out a workaround for this, but it doesn't "feel" completly right. All I did was to create a button (styled as a regular textblock) and attached the event on that button instead.

<HierarchicalDataTemplate ItemsSource="{Binding SubTransports}"
                            DataType="{x:Type Model:Transport}">
    <Button Style="{StaticResource textButton}"
            Content="{Binding Name}"
            cal:Message.Attach="[Event Click] = [Action ExploreTransport($dataContext)]"/>
</HierarchicalDataTemplate>

But now the items in the treeview only sometimes "looks" selected (sometimes they got the default blue background and sometimes they don't, but at least the event fires everytime with the correct parameter set).

Still wondering if there isn't a way to bind the Selected or SelectedItemChanged event and also get the dataContext...

//J

 

Nov 19, 2010 at 3:31 PM

Jens,

I don't know if this will help, but I have an app with a Treeview similiar to yours.  To get the currently selected item, I handle the SelectionChanged Event, and then use that to pull out my entity and set it as the current item in the ViewModel.  I know this is a workaround, but the SelectedItem property is not a bindable property so there really is no other way to do it (that I know of).

Greg