TreeViews

Topics: Getting Started, UI Architecture
Jul 6, 2011 at 4:45 PM

Okay,

I'm looking for general design question for the following situation:

- I want to have a hierarchical list - like a treeview - to present which windows can be activated.  ie: I wish to have a list of Home Screens and each Home screen can open children screens.

In all the examples I've seen which implement Conductor<IScreen>.Collection.OneActive use a simple listbox bound to the Items - this takes care of setting ActiveItem of course.

I've been following the pattern from the MediaOwl application for getting the children screen into the main Items list, but am a little stumped on getting these items to display as children of the parent item.

I've explored using HierarchicalDataTemplate's but since all of the items available to the conductor are essentially in flat list, this doesn't seem to make sense.

Any advice as to a 'proper' solution?

Jul 6, 2011 at 8:13 PM

My hacked solution was to create a base class for all of my "home screens" which maintains a list of it's children that were created.  The problem that was occurring is that any new windows were being displayed in the root nodes... this was 'fixed' by creating an empty template for these items.

        <HierarchicalDataTemplate DataType="{x:Type cal:Screen}">
        </HierarchicalDataTemplate>
       
        <HierarchicalDataTemplate DataType="{x:Type fw:HomeScreen}"
                                  ItemsSource="{Binding Path=ChildViewModels}">
                    <Button cal:Message.Attach="ActivateItem($dataContext)" Style="{x:Null}">
                        <DockPanel>
                            <TextBlock TextWrapping="Wrap"
                               Text="{Binding DisplayName}"
                               Margin="5"
                               />
                        </DockPanel>
                    </Button>
            <HierarchicalDataTemplate.ItemTemplate>
                <DataTemplate>
                    <Button cal:Message.Attach="ActivateItem($dataContext)" Style="{x:Null}"
                            Content="{Binding Path=DisplayName}"/>                   
                </DataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>           
        </HierarchicalDataTemplate>

...

<TreeView x:Name="Items"
                             Margin="5"
                             Width="210"
                             MinHeight="300"
                             >
                    </TreeView>

Jul 6, 2011 at 8:20 PM

I hope to have well understood your scenario.

I would try creating an interface (implemented by all involved Screens) abstracting the hierarchical relationships between the different screen.
It could be, for example:

 

interface IHierarchicalStructureMember {
	IEnumerable<IHierarchicalStructureMember> StructureChildren{ get; }
}
or
interface IHierarchicalStructureMember {
	IHierarchicalStructureMember StructureParent { get; }
}
depending of which of the two best fits the information about mutual relationships you have.

Once you have that, you can bind it to a treeview in the UI.
In particular, the first version could be used as is in a hierarchical template, while the second version should be "transformed" in model shaped with nested collection.

You also have to make sure that the treeview gets updated.

The simplest way is to raise a change notification on the property holding the root of the structure whenever the Conductor's Items collection changes: you have to subscribe to Items' CollectionChanged and call NotifyOfPropertyChange("Root") in the handler (if using the second version, you also have to regenerate the nested collection model).
I should point out, however, that this update approach could lead to poor performance when the number of nodes grows.

A better (yet significantly more complex) would be to "merge" the modifications detected in Items property in a separated structure, in order to just synchronize changed nodes.

Does it make sense?
Please let me know if I explained the idea clearly enough.

Jul 6, 2011 at 8:24 PM
Edited Jul 6, 2011 at 8:26 PM

It looks fine to me. It is very similar to my first version. 

If you want to avoid the empty template, try exposing a collection containing just the root screen. 

Jul 6, 2011 at 9:03 PM
marcoamendola wrote:

It looks fine to me. It is very similar to my first version. 

If you want to avoid the empty template, try exposing a collection containing just the root screen. 

Ahh, good call.  I'll give that a shot.