MVVM – Binding TreeView Item Changed to ICommand

Download Sample Project here: http://www.box.com/s/0e8rokffhp9p0pshb6b6

After browsing the web for more tha an hour there were quite some post which helped me to get a clue on how to bind a Tree View item selected.
All these posts gave me call back, on which I had to fire an event again, and add a subscription to it.

I wanted that call back subscription to be an ICommand, so that it is in sync with MVVM model.
But to bring the Call back into the View model had to go an extra mile.

I had to synchronize two dependency property.

1.  A dependency property to bind to  TreeView Item Selected .
2.  A dependency property to bind an ICommand, to  TreeView Item Selected Changed.

Dependency property to bind the TreeView Item Selected:

You need a dependency property which would hold the Tree View Item Selected value.
This property should be always updated with the New value, so that you would get an call back on SelectedItemChanged when a new item in the tree is selected.

public static readonly DependencyProperty SelectedItemProperty =
                       DependencyProperty.RegisterAttached("SelectedItem",
                                 typeof(object),
                                 typeof(TreeViewHelper),
                                 new UIPropertyMetadata(null, SelectedItemChanged));

Dependency property to bind an ICommand, when an TreeView Item Selected is changed:

You need a second dependency property which you could bind to an ICommand and execute when ever a new item in the treeview is selected.

public static readonly DependencyProperty SelectedItemChangedProperty =
                  DependencyProperty.RegisterAttached("SelectedItemChanged",
                                     typeof(ICommand),
                                     typeof(TreeViewHelper));

Code to fire the ICommand on SelectedItemProperty call back events

private static void SelectedItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    if (!(obj is TreeView) || e.NewValue == null)
        return;

    var view = obj as TreeView;
    view.SelectedItemChanged += (sender, e2) => SetSelectedItem(view, e2.NewValue);

    var command = (ICommand) (view as DependencyObject).GetValue(SelectedItemChangedProperty);
    if (command != null)
    {
        if (command.CanExecute(null))
            command.Execute(new DependencyPropertyEventArgs(e));
    }
}

Here is the xaml code to bind these two dependency properties

<UserControl x:Class="TreeViewItemChangedMvvm.View.MyTreeViewControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:ViewModelUtils="clr-namespace:TreeViewItemChangedMvvm.ViewModelUtils" mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TreeView ItemsSource="{Binding ItemsSource}"  
                  ViewModelUtils:TreeViewHelper.SelectedItem="{Binding CurrSelItem}"  
                  ViewModelUtils:TreeViewHelper.SelectedItemChanged="{Binding MySelItemChgCmd}" />
    </Grid>
</UserControl>

Thanks: http://stackoverflow.com/questions/1000040/selecteditem-in-a-wpf-treeview
Sample Project: http://www.box.com/s/0e8rokffhp9p0pshb6b6

About these ads

About jacob aloysious
I'm a 26 yrs old developer working with Atmel R&D India Pvt. Ltd., Chennai. I'm currently working in C#, have done a bit of Java programming too. And also an Android enthusiast. Like spending my spare time @ SO : http://stackoverflow.com/users/1218809/jacob-aloysious

7 Responses to MVVM – Binding TreeView Item Changed to ICommand

  1. Mike Horton says:

    Great work on this. I’ve got a slight problem that you may be able to help with. I’ve got my treeview in a tabcontrol but I’m finding if I switch tabs that when I go back the treeview is reset visually but it does remember the CurrSelItem. My question is whether there’s a way to get the treeview to expand to show what the selected item is.

  2. @Mike: Happy to know it helped… You could bind the “IsExpanded” property and add a Trigger to it.
    Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"

  3. Roger Lae says:

    Great work. Helped me to save a lot of time. Unfortunally the provided download doesnt work. The property CurrselItem is never set. After a little bit investigation I found the reason: The binding must be declared explicitly as TwoWay.
    ViewModelUtils:TreeViewHelper.SelectedItem=”{Binding CurrSelItem, Mode=TwoWay}”

  4. Roger Lae says:

    There’s another issue with Your solution:

    if (!(obj is TreeView) || e.NewValue == null)
    return;

    var view = obj as TreeView;
    view.SelectedItemChanged += (sender, e2) => SetSelectedItem(view, e2.NewValue);

    This piece of code in SelectedItemChanged in TreeeViewHelper causes adding a new event handler each time a tree view item is clicked.
    This would be a q’nd fix:

    if (!(obj is TreeView) || e.NewValue == null)
    return;

    var view = obj as TreeView;
    if (!_wired)
    {
    view.SelectedItemChanged += (sender, e2) => SetSelectedItem(view, e2.NewValue);
    _wired = true;
    }

    where _wired is a static bool …

  5. Happy to know it helped..

    >> Unfortunally the provided download doesn’t work.
    Apologize! But I just checked, the link works fine.

    https://www.box.com/s/0e8rokffhp9p0pshb6b6

    >> The binding must be declared explicitly as TwoWay.
    Agree! In my demo it was just OneWay to pop up a messageBox on SelectedItemChanged,

  6. >> This piece of code in SelectedItemChanged in TreeeViewHelper causes adding a new event handler each time a tree view item is clicked.
    Agree! But I guess the solution should be object specific and not global (static).
    May be Unsubscribing before Subscription could be an idea..

    view.SelectedItemChanged -= (sender, e2) => SetSelectedItem(view, e2.NewValue);

    view.SelectedItemChanged += (sender, e2) => SetSelectedItem(view, e2.NewValue);

  7. I’d been recommended this website by means of my nephew. I’m not sure whether it organize can be authored by means of your ex since no one recognize like accurate pertaining to the issues. You will be superb! Thanks a lot!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: