views:

467

answers:

1

I'm pretty new to Xaml and need some advise.

A TreeView should be bound to a hierarchical object structure. The TreeView should have a context menu, which is specific for each object type.

I've tried the following:

<TreeView>
  <TreeView.Resources>
    <DataTemplate x:Key="RoomTemplate">
      <TreeViewItem Header="{Binding Name}">
        <TreeViewItem.ContextMenu>
          <ContextMenu>
            <MenuItem Header="Open" />
            <MenuItem Header="Remove" />
          </ContextMenu>
        </TreeViewItem.ContextMenu>
      </TreeViewItem>
    </DataTemplate>
  </TreeView.Resources>

  <TreeViewItem Header="{Binding Name}" Name="tviRoot" IsExpanded="True" >

  <TreeViewItem Header="Rooms"  
                ItemsSource="{Binding Rooms}"
                ItemTemplate="{StaticResource RoomTemplate}">
    <TreeViewItem.ContextMenu>
      <ContextMenu>
        <MenuItem Header="Add room"></MenuItem>
      </ContextMenu>
    </TreeViewItem.ContextMenu>
  </TreeViewItem>
</TreeViewItem>

But with this markup the behavior is as intended, but the child items (the rooms) are indented too much.

Anyway all the bining samples I could find use TextBlock instead of TreeViewItem in the DataTemplate, but wonder how to integrate the ContextMenu there.

+3  A: 

You would not normally create a DataTemplate containing a TreeViewItem, because the binding infrastructure will be creating the TreeViewItem for you -- all your DataTemplate needs to do is specify what should be displayed as the content of the TreeViewItem. That's why the samples you've found use TextBlocks instead of TreeViewItems in the DataTemplate.

I suspect the use of TreeViewItem rather than TextBlock causes the excessive indenting because you have a (manually created) TreeViewItem in your DataTemplate (which incurs one level of indent) inside another (automatic) TreeViewItem (which incurs another level of indent). Therefore, using a TextBlock instead of a TreeViewItem should cure this. Integrating the ContextMenu shouldn't be an issue because TextBlock has a ContextMenu property too.

So you should be able to just change your DataTemplate as follows:

<DataTemplate x:Key="RoomTemplate">
  <TextBlock Text="{Binding Name}">
    <TextBlock.ContextMenu>
      <ContextMenu>
        <MenuItem Header="Open" />
        <MenuItem Header="Remove" />
      </ContextMenu>
    </TextBlock.ContextMenu>
  </TextBlock>
</DataTemplate>

Incidentally for TreeViews it is common to use a HierarchicalDataTemplate rather than a plain DataTemplate because this allows for multiple levels of items via the HierarchicalDataTemplate.ItemsSource property. This may not be required in your scenario though.

itowlson
Great, that did it! I'm using the HierarchicalDataTemplate too. But how do I add some fixed (non-bound) child items to the data bound item template? Like>Rooms>>Room1>>>Windows>>>>Window1>>>Doorswhere only Room1 and Window1 are data bound?
Michael Stoll
So you want to interpose additional fixed nodes? I *think* you could do that by going back to the TreeViewItem approach: your data template would be a TreeViewItem with the fixed header, whose ItemsSource was bound to the HDT's context e.g. `<HDT><TreeViewItem Header="Rooms" ItemsSource="{Binding}" /></HDT>`. Not tested though! If this doesn't work, you might want to post it as a new question as this will probably get more attention and therefore better answers than further discussion in a comment chain -- just a suggestion!
itowlson
Nope, that doesn't do it. I'll post a new question.
Michael Stoll