Alan Wayne
Alan Wayne

Reputation: 5384

How to bind to a child branch or leaf of a treeview (in MVVM style)?

I'm a newbie to TreeViews. In WPF style, I have a TreeView organized in three levels:

ReportName1
     NetworkName1
         PrinterName1
         PrinterName2
     NetworkName2
         PrinterName3
         PrinterName4
ReportName2
    ....

in the XAML, I am using Interaction behaviors to bind the TreeView SelectedItem to the ViewModel:

  <TreeView ItemsSource="{Binding ReportTree}"  >
            <i:Interaction.Behaviors>
                <tvb:TreeViewBehavior SelectedItem="{Binding SelectedTreeItem, Mode=TwoWay}" />
            </i:Interaction.Behaviors>

At this point, all works well to send an item from the ReportTree when I select ANY item under the main report name. That is, if I select PrinterName2, then the SelectedTreeItem will be the main viewmodel for ReportName1.

What I need to know is, how can I tell that PrinterName2 is selected as opposed to PrinterName1?

My eventual goal is to allow selection of any leaf or branch in the tree and remove only that selected leaf or branch.

Is there a way to do this?

Thanks for any help on this.

Upvotes: 1

Views: 284

Answers (1)

Marc
Marc

Reputation: 13184

Here is one option to solve this using a simple DataTemplate for the TreeView which contains a MouseBinding to call a select command on the parent ViewModel and pass the clicked item as a CommandParameter.

If your ViewModel looks something like this:

public class MainViewModel
{
    public ObservableCollection<ItemViewModel> Items { get; private set; }

    public ItemViewModel SelectedItem { get; set; }

    public ICommand SelectItem { get; private set; }

    public MainViewModel()
    {
        SelectItem = new LazyCommand<ItemViewModel>(ExecuteSelect);
        Items = new ObservableCollection<ItemViewModel>();            
    }

    private void ExecuteSelect(ItemViewModel item)
    {
        SelectedItem = item;
    }
}

with a straightforward ViewModel for the items:

public class ItemViewModel
{
    public ObservableCollection<ItemViewModel> Items { get; private set; }

    public string Name { get; set; }

    public ItemViewModel()
    {
        Items = new ObservableCollection<ItemViewModel>();
    }
}

Then you can define a TreeView with an HierarchicalDataTemplate as ItemTemplate:

<TreeView ItemsSource="{Binding Items}">
        <TreeView.ItemTemplate>

            <HierarchicalDataTemplate ItemsSource="{Binding Items}" >
                <TextBlock Text="{Binding Name}">
                    <TextBlock.InputBindings>
                        <MouseBinding MouseAction="LeftClick"
                                    Command="{Binding DataContext.SelectItem, RelativeSource={RelativeSource FindAncestor, AncestorType=TreeView}}"
                                    CommandParameter="{Binding}" />
                    </TextBlock.InputBindings>
                </TextBlock>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

The crucial part is the binding to the TreeViews DataContext.SelectItemCommand from the MouseBinding of each item and passing the item in as a parameter. You can then handle the selection itself (setting SelectedItem, etc.) in the ViewModel.

Upvotes: 1

Related Questions