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)
{
var result = (from objCategory in Cat.AllChildren()
where objCategory.CategoryName == "Category Sub1-1"
select objCategory).FirstOrDefault();
if (result != null)
{
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:
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()
{
if (SelectedCategory != null)
{
objTreeView.UpdateLayout();
MainPageViewModel objMainPageViewModel =
(MainPageViewModel)objTreeView.DataContext;
ObservableCollection<category> colCategories =
(ObservableCollection<category>)objMainPageViewModel.colCategory;
foreach (var Cat in colCategories)
{
var result = (from objCategory in Cat.AllChildren()
where objCategory == SelectedCategory
select objCategory).FirstOrDefault();
if (result != null)
{
TreeViewItem objTreeViewItem =
(TreeViewItem)objTreeView.ItemContainerGenerator.ContainerFromItem(Cat);
objTreeViewItem.IsExpanded = true;
objTreeView.UpdateLayout();
ExpandChildNode(objTreeViewItem, Cat);
}
}
}
}
private void ExpandChildNode(TreeViewItem objTreeViewItem, Category Cat)
{
foreach (var item in Cat.Categories)
{
var result = (from objCategory in item.AllChildren()
where objCategory == SelectedCategory
select objCategory).FirstOrDefault();
if (result != null)
{
TreeViewItem SubTreeViewItem = (TreeViewItem)
objTreeViewItem.ItemContainerGenerator.ContainerFromItem(item);
SubTreeViewItem.IsExpanded = true;
objTreeView.UpdateLayout();
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.