There are a number of public domain Multi-Select
TreeView controls and a number of File Explorers as well, but most seem to be either very complex, older (.NET 2.0 or earlier), too slow for our needs, or are not multi-select.
We wanted something lightweight, flexible and relatively fast that we could populate on demand from any node in the File System.
When I started to build this DLL, the Multi-Select feature seemed the most problematic so I looked at some of the other code online. Anything I found was tracking node selection manually in an
ArrayList (erg) or other data structure.
The code to do that can get a little hairy if one lets the user select/deselect away to their hearts content and I felt that there had to be a better way.
I thought about using the
TreeNode Tag property to hold a custom object that would contain both the node's selected status as well as the appropriate '
Info' object (
DriveInfo) but in a moment of silliness I decided to first see whether the
TreeNode Checked property would work even if the
CheckBox display is turned off.
And what do you know, they do. They are merrily checking away in the background even if the
TreeView isn't showing them. With that little revelation (to me at least) in hand, Multi-Select got much easier.
The rest of this article is focused on how we implemented the Multi-Select feature using the
Note: The project also needed
TreeView populate-on-demand code and not being one to reinvent the wheel, I derived mine from another CodeProject article by Chandana Subasinghe in October 2006 - http://www.codeproject.com/KB/cs/TreeViewFileExplorer.aspx). Yes, I could have used a
DataSource but for this project, the lighter the better.
The guts of the MFT Multi-Select code is comprised mainly of two event handlers:
_AfterSelect fires whenever a node is clicked, after the Tree's
SelectedNode property has been set.
_AfterCheck fires after that, each time we programmatically check a node.
Let's look at
In our code, the event handler decides what nodes to check by looking at the
ModifierKeys the user has pressed (SHIFT, CTRL, or both).
We implemented to duplicate Windows Explorer right-pane functionality. The SHIFT and SHIFT-CTRL handling is the trickiest but not too bad since we are only firing '
Checked' events, not trying to track the selections (sans error trapping for clarity):
protected void MultiSelectFileTreeView_AfterSelect(object sender, TreeViewEventArgs e)
bool bBoth = ModifierKeys == (Keys.Shift | Keys.Control);
bool bControl = (ModifierKeys == Keys.Control);
bool bShift = (ModifierKeys == Keys.Shift);
if (!(bBoth || bControl || bShift))
e.Node.Checked = true;
this.SelectedNode = e.Node;
e.Node.Checked = !e.Node.Checked;
this.SelectedNode = e.Node;
if (bShift || bBoth)
TreeNode TopNode = new TreeNode();
TreeNode BottomNode = new TreeNode();
if (_prevNode.Level != SelectedNode.Level)
TopNode = SelectedNode.Parent.Nodes;
BottomNode = e.Node;
TopNode = (_prevNode.Index < SelectedNode.Index) ? _prevNode : SelectedNode;
BottomNode = (SelectedNode.Index > _prevNode.Index) ?
SelectedNode : _prevNode;
for (int x = TopNode.Index; x <= BottomNode.Index; x++)
TreeNode n = SelectedNode.Parent.Nodes[x];
n.Checked = true;
if (n.Tag.GetType() != typeof(FileInfo))
Now that we are firing "
Check" events, all we have to do is trap them and color the
Node being checked/unchecked to reflect its status.
protected void MultiSelectFileTreeView_AfterCheck(object sender, TreeViewEventArgs e)
e.Node.BackColor = (e.Node.Checked == true) ? SelectedBackColor : this.BackColor;
e.Node.ForeColor = (e.Node.Checked == true) ? SelectedForeColor : this.ForeColor;
Type nodeType = e.Node.Tag.GetType();
if (nodeType == typeof(DirectoryInfo) || nodeType == typeof(DriveInfo))
Using the Code
The MFT class inherits directly from
TreeView and all of the base
TreeView members are accessible to your code.
Use the normal VS methodology of adding a DLL reference to your project and, if you like, of adding it to your VS tool box.
The ReadMe.txt file included in the download describes the MFT properties, which are minimal.
We were after lightweight, remember?
You can set the Node Selection colors and specify the image index numbers to be used but the parent form is responsible for supplying the
ImageList just as you would with a normal
As mentioned, the MFT provides for essentially the same node selection functionality as found in Windows Explorer - SHIFT-select, CTRL-select and SHIFT-CTRL-select functionality are provided.
In addition, a right-click context-menu is provided on expandable nodes. The screen shot shows the Test WinForm app using the context menu to select the files in the root of D:\.
The Test application implements the MFT control in the left pane and subscribes to its
After_Check event to populate a
Listbox with selected files on the right using the event-handler code shown below. As always, the underlying handler (our MFT event) runs before the handler in the parent form.
Note: The MFT also provides a
PopulateAtPath method so that a portion of the file system can be used where appropriate to the application.
Implementing the Control
Here is the code used to implement the control in the Test form. Pardon the lack of error trapping for easier reading.
MultiSelectFileTreeView1.ImageList = imageList1;
MultiSelectFileTreeView1.SelectedBackColor = Color.Violet;
void MultiSelectFileTreeView1_AfterCheck(object sender, TreeViewEventArgs e)
if (e.Node.Tag!=null && e.Node.Tag.GetType() == typeof(FileInfo))
bool has = listBox1.Items.Contains(e.Node.FullPath);
if (e.Node.Checked && !has)
else if (!e.Node.Checked && has)
Points of Interest
One thing to notice is that the
Node.Tag property contains the '
info' object for each node, gathered at the time the node is populated from the file system.
So, while the test app simply shows the
FullPath in the
listbox, the entire
Info object is just as easily available to your code.
- 3rd April, 2010: Initial post