Extending the LabelEdit functionality of a TreeView to include validation
An article which describes how to add validation support to a `TreeView` control that is using custom label edit functionality.
Recently I was updating a support tool that displays documents
in raw form and allows editing of them. This tool is centred
TreeView, and the
Text property of each
is a concatenation of a name and one or more values.
The problem with this approach is if you wish to allow the nodes to be edited using the built in functionality you're in trouble as by default you can't actually influence the text that appears in the in-line editor. In other applications of a similar nature I used owner-drawn trees as I was using different styles for the name and the value. In this case, I just wanted the standard look.
Ideally, you'd expect that by hooking into the
event (or overriding
OnBeforeLabelEdit) then you could
NodeLabelEditEventArgs.Label property. Except
this property is read only.
Scratch that then. What about setting the
property to something else in this event, then resetting it
afterwards? Nope, doesn't work either.
Therefore, using just the managed code of the
not possible to do what we want. Lets get slightly outside the
black box with a little Win32 API. We'll get the handle of the
edit control the
TreeView is using and directly set it's
In order to manipulate the edit control, we first need to get a
handle to it. We can do this succinctly by overriding
OnBeforeLabelEdit (or hooking the
although the former is preferable) and using the
Now that we have a handle, we can painlessly use
change the text of the edit control
If you were hooking into the
BeforeLabelEdit event, then you
can just have your own logic in that event to determine the text
to apply. If however you're overriding
OnBeforeEdit in order
to make a nice reusable component, you need another way of
allowing implementers to specify the value. For this, I added a
new event to the control.
NodeRequestTextEventArgs class is essentially a clone of
NodeLabelEditEventArgs except with a writeable
property. I also decided to allow you to cancel the node edit
from this event, so that implementers don't have to hook both
events unless necessary.
Our final version now looks like this:
And an sample usage scenario from the demo application:
In this example, we are setting the edit text to be the value of
Name property, regardless of whatever its
After the conclusion of the label editing, the node's text will be set to the new label, and therefore we need to tinker that logic to allow the implementer to specify the new value text.
You could just hook the
AfterLabelEdit event and have your
custom logic in there (remembering to cancel the default edit),
as shown here:
However, I didn't want to be having to do this type of code each
time I implemented this sort of behaviour in an application.
Rather than get fancy with subclassed
TreeNode classes, I
choose to add a sister event for
RequestDisplayText and then handle this automatically. This is
the only aspect of this article that feels "smelly" to me -
ideally it would be nice if the control could handle this for
you without having to ask for more information. But, this should
do for the time being.
And an example of use:
The demonstration shows both of these approaches - the
TreeViewEx control favours the
RequestDisplayText event, and
TreeViewExNotify control leaves it entirely to the
implementer to deal with.
And that's it. I've seen some implementations of this sort of
functionality in various places across the internet, and some of
them are pretty awful, having to override all sorts of methods,
store and restore various states. The above solution is pretty
simple and works regardless of if you are calling
TreeNode.BeginEdit or using the "click and hover" approach on
In addition, it's trivially easy to expand this to support validation as well, I'll cover that in the next article.
I originally tried two different approaches to modifying the
value, both of these involved capturing the
notification. The first approach used a
NativeWindow bound to
TreeView control's parent watching for the
message. The second approach did the same thing, but used MFC's
Message Reflection via
WM_REFLECT to intercept the
notification message on the tree view itself. Both of these
solutions worked, and yet were still overkill as overriding
OnBeforeLabelEdit is sufficient.
Although I'm not going to describe that approach here as it'll
just clutter the article, I did include an implementation of the
WM_REFLECT solution in the demonstration project as I think it
is a neat technique and potentially useful for other
Like what you're reading? Perhaps you like to buy us a coffee?