RSS Feed

Saturday, July 12, 2008

A little help with the .NET WinForms TreeView

So here's the situation: you're developing a .NET WinForms application that needs a TreeView. Obviously, there are a lot of tree controls out there from Infragistics, DevExpress, etc. but you may find that the .NET 3.5 TreeView is sufficient. As I discovered this week, there are likely two issues you'll face when you use the TreeView.

First, when the tree loses focus, the selected node no longer appears highlighted. Maintaining the highlight can be useful if the TreeView is used in conjunction with other controls to help a user navigate or enter data. In these cases, the highlighting can help provide context to the user about the current state of the application.

Second, there is no ideal event for handling what would seem to be the most basic TreeView event - a user selecting a node. How is this possible? Sure, there's the AfterSelect and NodeMouseClick events, but they're both lacking in their own way. The AfterSelect event is close but it isn't fired a second time when you click on the same node twice. The NodeMouseClick event would seem like a good choice, but it isn't fired when the user navigates to a node using the keyboard (for example using the up and down arrows).

Here's a little code to address both issues:

Issue #1:

In your form constructor, attach a handler to the BeforeSelect and AfterSelect events of the TreeView (trv):

trv.BeforeSelect += trv_OnBeforeSelect;
trv.AfterSelect += trv_OnAfterSelect;

In the BeforeSelect event handler, add the following code:

private void trv_OnBeforeSelect(object sender, TreeViewCancelEventArgs e)
{
if (trv.SelectedNode != null)
{
trv.SelectedNode.BackColor = SystemColors.Control;
trv.SelectedNode.ForeColor = SystemColors.ControlText;
}
}

I've used the Control and ControlText colors because I've set the background color of the TreeView to Control. I think by default the background color is SystemColors.Window.

Next, add the following code to the AfterSelect event handler:

private void trv_OnAfterSelect(object sender, TreeViewEventArgs e)
{
e.Node.BackColor = SystemColors.Highlight;
e.Node.ForeColor = SystemColors.HighlightText;

// Handle the Node Selection Here...
}

That's it! Every time a node becomes selected, it's background and font color is set to the highlight color (typically blue background with white text). Every time a node is deselected (just before another node is selected) its color scheme is returned to the default.

Issue #2

To solve the second issue, hook up the following two event handlers in your form constructor:

trv.AfterSelect += trv_OnAfterSelect;
trv.NodeMouseClick += trv_OnNodeMouseClick;

Now, enter the following code in the corresponding event handlers:

private void trv_OnAfterSelect(object sender, TreeViewEventArgs e)
{
// Handle the node selection
}

private void trv_OnNodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (trv.SelectedNode == e.Node)
{
trv_OnAfterSelect(sender, new TreeViewEventArgs(e.Node));
}
}

Obviously, the "magic" for this one happens in the second handler. Here, we simply check to see if an already selected node has been clicked. If it has, we delegate to the handler for the AfterSelect event passing in the node that was clicked on.

Hope this helps!

2 comments:

dave-ilsw said...

Thanks for posting that and thanks to Ayende Rahien for linking to your blog!

Mark van Dijk said...

Thanks Kevin, I'm gonna use this right away!