You may find this post helpful if:
- You are using MVVM
- You are using a TreeView control
- You want the SelectedItem of the TreeView control to be passed to another object
There are a lot of improvements in Expression Blend 4 that makes wiring this up easy. I poked around for a bit until I found the easiest method to do this that I could find.
Create a new Expression Blend 4 (or higher) project.
Add the following folders to the project:
- Classes
- Models
- ViewModels
MVVM Support Class
We need to add one simple class to support Commanding to allow all this to work.
Right-click on the Classes folder and select Add New Item…
Add a class called DelegateCommand.cs and click OK.
Replace all the code with the following code:
using System.Windows.Input;
using System;
// From http://johnpapa.net/silverlight/5-simple-steps-to-commanding-in-silverlight/
public class DelegateCommand : ICommand
{
Func<object, bool> canExecute;
Action<object> executeAction;
bool canExecuteCache;
public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)
{
this.executeAction = executeAction;
this.canExecute = canExecute;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
bool temp = canExecute(parameter);
if (canExecuteCache != temp)
{
canExecuteCache = temp;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, new EventArgs());
}
}
return canExecuteCache;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
executeAction(parameter);
}
#endregion
}
This class allows us to easily use Commanding, that will allow us to call a method in our ViewModel.
The Model
In the Models folder, add a class called SilverlightFolders.cs and replace the code with the following code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
public class SilverlightFolder
{
private ObservableCollection<SilverlightFolder> _SubFolders;
public ObservableCollection<SilverlightFolder> SubFolders
{
get
{
if (_SubFolders == null)
{
_SubFolders = new ObservableCollection<SilverlightFolder>();
}
return _SubFolders;
}
set
{
_SubFolders = value;
}
}
public string FolderName { get; set; }
public string FolderPath { get; set; }
}
This is a simple class that allows us to create a collection of nested folders. Note that it implements ObservableCollection so that changes to values stored in the class, will cause a notification to any UI element that is bound to it so it can automatically update.
In the Models folder, add a class called DataGenerator.cs and replace the code with the following code:
using System;
using System.Net;
using System.Windows;
using System.Collections.ObjectModel;
public static class DataGenerator
{
public static ObservableCollection<SilverlightFolder> SilverlightFolders()
{
return new ObservableCollection<SilverlightFolder>()
{
new SilverlightFolder()
{
FolderName = "Folder1", FolderPath ="Path1",
SubFolders = new ObservableCollection<SilverlightFolder>()
{
new SilverlightFolder()
{
FolderName = "Folder1-1", FolderPath ="Path2",
SubFolders = null
},
new SilverlightFolder()
{
FolderName = "Folder1-2", FolderPath ="Path3",
SubFolders = null
}
}
}
};
}
}
This class creates some sample data. This class could be altered to retrieve an actual folder structure using web services, for example.
The ViewModel
In the ViewModels folder, add a class called MainViewModel.cs and replace the code with the following code:
using System;
using System.ComponentModel;
using System.Windows.Input;
using System.Collections.ObjectModel;
namespace MVVMTreeViewSelectedItemChanged
{
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
// Set the command property
SetProductsCommand = new DelegateCommand(SetProducts, CanSetProducts);
// Set Sample Tree Data
SilverlightFolders = DataGenerator.SilverlightFolders();
}
public ICommand SetProductsCommand { get; set; }
public void SetProducts(object param)
{
SilverlightFolder objSilverlightFolder = (SilverlightFolder)param;
this.ViewModelProperty = objSilverlightFolder.FolderName;
}
private bool CanSetProducts(object param)
{
return true;
}
private ObservableCollection<SilverlightFolder> _SilverlightFolders;
public ObservableCollection<SilverlightFolder> SilverlightFolders
{
get { return _SilverlightFolders; }
private set
{
if (SilverlightFolders == value)
{
return;
}
_SilverlightFolders = value;
this.NotifyPropertyChanged("SilverlightFolders");
}
}
private string viewModelProperty = "";
public string ViewModelProperty
{
get
{
return this.viewModelProperty;
}
set
{
this.viewModelProperty = value;
this.NotifyPropertyChanged("ViewModelProperty");
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
This class exposes the list of Folders as well as a ViewModelProperty that will hold the TreeView selected value. It also contains the SetProducts method that will be triggered in the UI when the TreeView selected value is changed.
Note that this class implements INotifyPropertyChanged to allow the UI to automatically be updated when values change in the ViewModel
At this point you must build the project for the classes to be used in the following steps.
The Fun Part
Imagine that a programmer created the previous files. This project can now be turned over to a designer to actually create the UI.
Double-click on MainPage.xaml in the Projects window to open it. In my example I right-clicked on the LayoutRoot to change it to a Canvas Panel and I re-sized it to make it smaller.
Click on LayoutRoot in the Objects and Timeline window, and in the Properties window, type “DataContext” in the Search box. Next, Click the New button next to DataContext.
Select MainViewModel and click OK.
Click the Data tab and expand MainViewModel (under the Data Context section).

Click on ViewModelProperty and drag it onto the design canvas.
You will need to hover the mouse on the edge of the TextBlock control that is created, and click and drag it to make it wider.
Now, click and drag the SilverlightFolders collection to the canvas.
Position it under the TextBlock control. A TreeView control will be created.
In the Objects and Timeline window, right-click on the TreeView control and select Edit Additional Templates > Edit Generated Items (Item Template) > Edit Current.
This will take you to the Template editing mode. Select the lower TextBlock (that the file Path is bound to) and click the delete button on your keyboard, to delete it.
Click the Return Scope icon, in the Objects and Timeline window, to return to normal design mode.
Hit the F5 key on your keyboard to compile and run the project. The TreeView control will show the Folder structure but when you click on a Folder name nothing will happen.
Setting SelectedItemChanged in the TreeView
Now to the point of this Blog post, how to set the SelectedItemChanged value when you click an element on the TreeView control. Also, how to pass the value selected in the TreeView control to the text box that was placed above the TreeView.
Click on the Assets button on the Tools window.
Type “InvokeCommand” in the search box and the InvokeCommandAction behavior will show. (if you don’t see this, install the Silverlight 4 SDK). Drag and drop it on the TreeView control (either in the Objects and Timeline window or on the design canvas).
The Behavior will show under the TreeView control in the Objects and Timeline window.
Click on the Behavior in the Objects and Timeline window, and in the Properties window, clear out the Search box. You will now see all the properties.
Set the EventName to SelectedItemChanged (so that the Behavior will fire when the selected item is changed in the TreeView).
Click the Data bind icon next to Command (under Common Properties).
- Select the Data Context tab
- Select SetProductsCommand (under MainViewModel)
- Click OK
This instructs the Behavior to call the SetProductsCommand in the ViewModel.
Click the Advanced options box next to CommandParameter (under Common Properties).
Select Data Binding…
- Select the Element Property tab
- Select [TreeView] (in the Scene elements window)
- Select SelectedItme (in the Properties window)
- Click OK
This instructs the Behavior to pass the SilverlightFolder object, that the currently selected TreeView item is bound to, to the SetProductsCommand in the ViewModel.
Hit the F5 key on your keyboard to compile and run the project. The TreeView control will show the Folder structure, and when you click on a Folder name it will show the selected Folder name in the TextBlock.