I am implementing a TreeView control to closely mimic Windows Explorer behaviour. The user can edit labels and these must be uniquely named. If the user edits the name of the label to a non-unique name an error message is displayed and the label remains in edit mode until the user enters a valid name. I am using the following pattern within OnAfterLabelEdit:
protected override void OnAfterLabelEdit(NodeLabelEditEventArgs e)
{
//Label is valid unless the user has changed it.
if(e.Label==null)
{
return;
}
//Peform validation.
bool IsValid=ValidateLabel(e);
if(!IsValid)
{
//Reset label.
e.CancelEdit = true;
System.Windows.Forms.MessageBox.Show("Error");
//Resume edit mode.
e.Node.BeginEdit();
}
else
{//Valid label.
e.Node.Text = e.Label;
base.OnAfterLabelEdit(e);
}
}
This works, as expected, where the user enters an invalid label and presses enter. The node remains in edit mode, allowing the user to easily retype a valid label. However, when the user enters an invalid label and clicks on another node; the error message is displayed (as before) but the node is not in edit mode, merely highlighted.
Clicking on another node seems to result in OnAfterLabelEdit being called twice. The first time around, the e.Label property contains the changed label value. The second time OnAfterLabelEdit is called the e.Label property is null and the routine exits, since there are no modifications to the label.
Is there a bug in the TreeView control Where a folder is not uniquely named, the Windows Explorer treeview returns the node to edit mode. I have looked at a number of examples, which mimic Windows Explorer, but none of them accurately reproduce this particular feature. What do I need to do to recreate this behaviour in my TreeView

Treeview Mimicking Windows Explorer
Yingshen
Okay, I see what's happening. The message for the AfterLabelEdit associated with clicking another node is still in the queue, calling BeginEdit when processing the current AfterLabelEdit is getting tromped by that unprocessed message (or messages). You can force the BeginEdit to occur after all existing message in the queue by invoking it with BeginInvoke. This can be done with an anonymous function by replacing the call to e.Node.BeginEdit(); with this.BeginInvoke((MethodInvoker)delegate(){e.Node.BeginEdit();});.
The drawback of this is that you lose the text the user has currently typed it. You could do what you did before and set e.Node.Text to e.Label; but then you'll circumvent the validation. For example, if the user edits a node and types in invalid text and clicks another node (if your routine changed e.Node.Text to e.Label) the message box would appear and the edit box would contain the current text; but, if the user clicked another node again the TreeView would think the user hadn't edited the text and raise an AfterLabelEdit event with a null e.Label.
I don't think there's anyway to get around that with the current implementation of TreeView (ListView would have the same problem).
David Prentice
Philippe Dansereau
You're seeing this in the debugger, right
When you break anywhere in this code and BeginEdit is called (before or after), the application no longer has focus and the edit is canceled, resulting in what appears to be another AfterLabelEdit event with a null Label.
If you don't break in the code and simply add Trace or Debug statements to see what is going on you will see only the one event.
ShareCropper
Thanks, I understand there may be legitimate reasons for two events to occur. However, it does seem to be preventing me from effecting the desired Windows Explorer style behaviour.
If you edit a TreeNode in Windows Explorer, rename the folder to one that already exists and click on another node, then an error message appears and, crucially, the TreeNode is returned to edit mode. I want to be able to recreate exactly this behaviour (which is exhibited when I edit a node and press enter instead of clicking another node). Any ideas
Cong Li
MFH Schoonbrood
I added code to write to the Event Viewer and ran the executable. There are still 2 events.
The first occurence of the event, where I edit the TreeNode label, has the e.Node.Text value set to the original label and the e.Label value set to the newly edited label.
The second occurence of the event, produced where I click on another node, has the e.Node.Text value set to the original label and the e.Label value set to null.
Where I do not click on another node, whilst editing the label, instead pressing enter to commit an invalid label name, the second invocation of the event does not occur and the TreeNode remains in edit mode - as expected. It appears that clicking another node interferes with the TreeNode remaining in edit mode.
I am using Visual Studio 2005.
nildorn
Yes, you'll always get the AfterLabelEdit with e.Label == null when the user cancels the edit by pressing another node or pressing Esc. If the user has pressed return after the label edit is begun you'll get the AfterLabelEdit with e.Label == to the new value.
You're not getting two events for the same action, you're getting two events for two different actions; there is no bug.
nfreelan
if (e.Label != null)
{
if (ValidateLabel(e))
{
// Stop editing without canceling the label change.
e.Node.EndEdit(false);
}
else
{
/* Cancel the label edit action, inform the user, and
place the node in edit mode again. */
e.CancelEdit = true;
MessageBox.Show("Error");
e.Node.BeginEdit();
}
}