Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

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

0.00/5 (No votes)
5 Nov 2010 1  
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...

Click to enlarge image

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here