Programmatic Silverlight Tree View Control Node Expansion using View Model (MVVM)






4.98/5 (18 votes)
Programmatically selecting a Silverlight Tree View Control node using View Model (MVVM)

The Silverlight Tree View Control and View Model (MVVM)
Live example: http://silverlight.adefwebserver.com/ViewModelTreeControl
Also see: Silverlight DataTrigger is the Answer to View Model / MVVM issues
When using the Silverlight Tree View Control, you will discover that it is not easy to expand a Tree Node programmatically without using code behind. This article shows how to do that using a Behavior.
Using The Silverlight Tree View Control
Let's look at the normal operation of the Silverlight Tree View Control using View Model (MVVM):

We start off with a simple Category class...

We bind a collection of Categories to the Tree View Control.
We create an ICommand that will set the IsSelected property of one of the nodes:
public ICommand SetCategoryCommand { get; set; }
public void SetCategory(object param)
{
foreach (var Cat in colCategory)
{
// Find the Node
var result = (from objCategory in Cat.AllChildren()
where objCategory.CategoryName == "Category Sub1-1"
select objCategory).FirstOrDefault();
if (result != null)
{
// Set the IsSelected property so the checkbox
// will be checked
result.IsSelected = true;
}
}
}
private bool CanSetCategory(object param)
{
return true;
}
We can then invoke the ICommand with a Button, and the check box on the node is selected.

The problem is, if the Silverlight Tree View Control is collapsed, the Node will be checked but you will not know it unless you expand the Tree Node.
Programmatically Selecting The Tree Node
The first step to programmatically selecting the Tree Node is to create a property in the View Model to hold the value of the selected node:
private Category _SelectedCategory;
public Category SelectedCategory
{
get { return _SelectedCategory; }
set
{
if (SelectedCategory == value)
{
return;
}
_SelectedCategory = value;
this.NotifyPropertyChanged("SelectedCategory");
}
}
And setting the value:
// Set the SelectedCategory property
// so the Behavior will know what node to open
SelectedCategory = objCategorySub0;
Next, we create a Behavior and drop it on the Tree View Control.

We set the Button to trigger the Behavior, and we bind the SelectedCategory to the Behavior.
Notice, there is also a ExpandOnLoad check box, to allow us to indicate if the node should expand when the page is loaded, or when triggered by an event such as a Button click.

When we run the project and click the Button...

The Silverlight Tree View Control Node is automatically expanded.
The Behavior
The Behavior does not consist of a lot of code. This is the method that does most of the work:
private void SelectNode()
{
// Only try to expand Node if the SelectedCategory is set
if (SelectedCategory != null)
{
// Refresh Tree Control
objTreeView.UpdateLayout();
// Get the DataContext of the Tree Control
MainPageViewModel objMainPageViewModel =
(MainPageViewModel)objTreeView.DataContext;
// Get collection of items bound to Tree Control
ObservableCollection<category> colCategories =
(ObservableCollection<category>)objMainPageViewModel.colCategory;
// Loop through the top levels items
foreach (var Cat in colCategories)
{
// Find the Node - Is it a child of this parent?
var result = (from objCategory in Cat.AllChildren()
where objCategory == SelectedCategory
select objCategory).FirstOrDefault();
// If the selected item is a child of the Parent
if (result != null)
{
// Get the Tree Control node container for the item
TreeViewItem objTreeViewItem =
(TreeViewItem)objTreeView.ItemContainerGenerator.ContainerFromItem(Cat);
// Expand the Node
objTreeViewItem.IsExpanded = true;
// Refresh Tree Control
objTreeView.UpdateLayout();
ExpandChildNode(objTreeViewItem, Cat);
}
}
}
}
// This method expands child nodes
private void ExpandChildNode(TreeViewItem objTreeViewItem, Category Cat)
{
// Loop through all the sub Categories
foreach (var item in Cat.Categories)
{
// Find the Node - Is it a child of this parent?
var result = (from objCategory in item.AllChildren()
where objCategory == SelectedCategory
select objCategory).FirstOrDefault();
// If the selected item is a child of the Parent
if (result != null)
{
// Get the Tree Control node container for the item
TreeViewItem SubTreeViewItem = (TreeViewItem)
objTreeViewItem.ItemContainerGenerator.ContainerFromItem(item);
// Expand the Node
SubTreeViewItem.IsExpanded = true;
// Refresh Tree Control
objTreeView.UpdateLayout();
// Recursively call the function
ExpandChildNode(SubTreeViewItem, item);
}
}
}
What's Wrong With Code Behind?
There are a number of projects that I am working on where we allow a Designer, with no programming ability, to use Microsoft Expression Blend, to create a UI for a Silverlight Application. For this reason, we do not want to use any code behind, because the Designer would need to know how to program to avoid breaking something.
When we are able to implement Silverlight project with no code behind, we do not have this problem.