Click here to Skip to main content
Click here to Skip to main content
Go to top

WPF TreeView Selection

, 27 Sep 2007
Rate this:
Please Sign up or sign in to vote.
Implementing TreeViewItem selection in the WPF TreeView control
Screenshot - WPFTreeViewSelection.gif

Introduction

In the process of using the WPF TreeView control, I'm sure many new WPF programmers have tried something like this:

treeView1.SelectedItem = myItem;

...only to discover that the SelectedItem property is read-only. Coming from Windows Forms, it would seem natural to programmatically set the SelectedItem in this manner. In WPF, however, the TreeView control is much more powerful and there are a variety of reasons why the designers chose not to make the SelectedItem property settable. Regardless of design decisions, though, we still need to be able to programmatically set the selected TreeViewItem in a TreeView (and hopefully in an easy manner).

A Solution

The solution I came up with is to have code that "walks" the tree for me, following a list (or chain) of items and selecting the last item in the chain. In the example image above, the selected path is Item 7\Item 8\Item 9\Item 10 and Item 10 is selected in the TreeView. The chain of items, then, is Item 7 -> Item 8 -> Item 9 -> Item 10.

It doesn't matter what type the items in the chain are, just that they're unique for each parent TreeViewItem. Behind the scenes, the code will walk the chain of items from left to right. Each item in the chain is searched for in the Items property of the current ItemsControl (starting with the TreeView and descending into each TreeViewItem). If there are more items in the chain, the current TreeViewItem is expanded and the search continues. The last TreeViewItem has its IsSelected property set to true.

Using the Code

Selecting a TreeViewItem using a path like in the example above is easy:

  1. Include the TreeViewExtensions.cs and UIUtility.cs files in your project.
  2. Reference the namespace to include the extension methods:
    using SynesthesiaM;
  3. Select your item:
    yourTreeView.SetSelectedItem(@"Path\To\Your\Item");

Even for this simple scenario, there is a lot going on in the background and many assumptions are made about the objects in your TreeView. When calling SetSelectedItem(string path), each component of the path (separated by System.IO.Path.DirectorySeparatorChar ) is compared with the ToString representation of the objects in your TreeView. If your TreeView contained objects like this:

public class MyObject
{    
    public string Name { get; set; }
    public int Id { get; set; }
    
    public override ToString()
    {
        return (this.Name);
    }
}

...then the components in your path will effectively be the Name property of each MyObject because that's what ToString returns. What if you wanted to use the Id property instead? Using one of the overloads of SetSelectedItem, you can do it as follows:

// Extract a string representation of the Id property
var myConvertFunction = item =>
    ((MyObject)item).Id.ToString();

// Now you can use the Id numbers in the path
yourTreeView.SetSelectedItem(@"1\2\3\4", myConvertFunction);

If you need more complex item chains that don't have a unique string representation for each item, you can customize the behavior of SetSelectedItem further by specifying a conversion method. Another way of doing the previous example would be:

// Extract the Id property
var myConvertFunction = item =>
    item.Id;

// Use a custom comparison function for matching Id numbers
var myCompareFunction = (id1, id2) =>
    id1 == id2;

// Select the object with Id # 3 in this chain:
// Id # 1
// |-> Id # 2
//     |-> Id # 3 *
yourTreeView.SetSelectedItem(new int[] { 1, 2, 3 }, 
    myCompareFunction, myConvertFunction);

Different aspects of the path searching can be customized. Here's a brief description of each overload:

  • SetSelectedItem(string path, char separatorChar)
    • Lets you specify your own separator character for path components (for example, use "/" for Unix-style paths).
  • SetSelectedItem(string path, Func<object, string> convertMethod)
    • Lets you extract a path component by some other means besides calling ToString on the object.
  • SetSelectedItem<T>(IEnumerable<T> items)
    • Lets you manually provide the item chain and type of items in the TreeView.
    • Items are compared with the "==" operator.
  • SetSelectedItem<T>(IEnumerable<T> items, Func<T, T, bool> compareMethod)
    • Lets you manually provide the item chain and type of items in the TreeView.
    • Items are compared with your custom method.
  • SetSelectedItem<T>(IEnumerable<T> items, Func<T, T, bool> compareMethod, Func<object, T> convertMethod)
    • Lets you manually provide the item chain and type of items in the TreeView.
    • Items are compared with your custom method.
    • Items in the TreeView are converted with your custom method before being compared.

If you want the maximum level of customization, use the UIUtility.SetSelectedItem method. This method allows you to control almost every aspect of the searching, including the actions taken to select an item and request more items. The example project demonstrates how to use the most important SetSelectedItem overloads.

Points of Interest and Potential Problems

The main reason it's so difficult to select items in a TreeView is because of the generation of item containers. When an object is added to a TreeView or a TreeViewItem is expanded, the child TreeViewItems are generated in a background thread. Calling ItemsControl.ItemContainerGenerator.ContainerFromItem before the background thread is finished will just return a null reference. UIUtility.SetSelectedItem gets around the background thread problem by attaching an event handler to the ItemsControl.ItemContainerGenerator.StatusChanged event and waiting for the generator to finish.

With all of the threading kung-fu, there's the potential for strange problems. One that I've noticed so far is calling any of the SetSelectedItem methods twice, one right after the other, with different paths (or chains). Both calls will expand the appropriate TreeViewItems, but the last one to finish (not necessarily the last one called) will have its final item selected. Other potential problems most likely exist, so I wouldn't recommend using this in critical production code.

Contributions and Comments

Any contributions to the code or comments are welcome! I'm fairly new to WPF myself, so there might be many things that I'm missing or mistaken about. Also, this is my first Code Project article, so any formatting or styling recommendations are welcome too.

History

  • 9/25/2007 - Initial version (1.0)

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

Share

About the Author

DaWanderer
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
QuestionNice solution PinmemberMember 1028419619-Sep-13 1:11 
GeneralMy vote of 4 PinmemberHOSSEIN.AB30-Oct-12 19:08 
GeneralMy vote of 4 PinmemberDean Oliver2-Feb-12 19:08 
GeneralVery Good Solution with the wonderful usage of LINQ PinmemberBharat Mane19-Sep-11 22:55 
GeneralExcellent Solution! PinmemberJohn Livingston8-Feb-11 17:25 
GeneralThis is the wrong way PinmemberAhmad Siddiqi9-Mar-10 12:58 
GeneralLook for children PinmemberKyo_Kusanagi999-Oct-09 10:38 
GeneralThanks PinmemberGary Wheeler3-Aug-09 4:04 
GeneralMoveToNextItem PinmemberAVEbrahimi25-Feb-09 18:37 
QuestionDoesn't work with Virtualization turned on - WPF 3.5 SP1 Feature PinmemberMartin Gagne21-Aug-08 17:11 
AnswerRe: Doesn't work with Virtualization turned on - WPF 3.5 SP1 Feature PinmemberDaWanderer18-Sep-08 3:56 
GeneralRe: Doesn't work with Virtualization turned on - WPF 3.5 SP1 Feature PinmemberZubair Noman28-Oct-08 11:12 
GeneralRe: Doesn't work with Virtualization turned on - WPF 3.5 SP1 Feature PinmemberKenrae25-Nov-08 0:04 
GeneralRe: Doesn't work with Virtualization turned on - WPF 3.5 SP1 Feature PinmemberKenrae25-Nov-08 0:12 
GeneralRe: Doesn't work with Virtualization turned on - WPF 3.5 SP1 Feature PinmemberLeung Yat Chun24-Jun-09 7:16 
GeneralHave just looked at this PinmemberSacha Barber14-Nov-07 0:33 
GeneralRe: Have just looked at this PinmemberDaWanderer14-Nov-07 6:03 
GeneralRe: Have just looked at this PinmemberSacha Barber14-Nov-07 21:59 
GeneralRe: Have just looked at this PinmemberDaWanderer18-Nov-07 8:11 
GeneralRe: Have just looked at this PinmemberSacha Barber18-Nov-07 20:51 
GeneralNice approach PinmvpJosh Smith30-Sep-07 6:39 
GeneralRe: Nice approach PinmemberDaWanderer30-Sep-07 9:31 
GeneralRe: Nice approach PinmvpJosh Smith30-Sep-07 9:40 
GeneralRe: Nice approach PinmemberDaWanderer30-Sep-07 15:16 
GeneralRe: Nice approach PinmvpJosh Smith7-Oct-07 8:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 27 Sep 2007
Article Copyright 2007 by DaWanderer
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid