Handling Label Editing in Dialog Boxes

The tree-view and list-view controls support label editing. For a tree-view, the TVS_EDITLABELS style must be specified; for a list-view, LVS_EDITLABELS is required. When label editing is enabled, clicking on an item’s label results in an edit control being displayed to allow the user to enter a new name for the item.

When editing begins, the control sends a notification - TVN_BEGINLABELEDIT for a tree-view, LVN_BEGINLABELEDIT for a list-view. Label editing can be prevented for any particular item by returning a nonzero value from the message handler. Similarly, a notification is sent when editing ends - TVN_ENDLABELEDIT for a tree-view, LVN_ENDLABELEDIT for a list-view, unsurprisingly.

So far this seems very simple, and indeed it is, if the control is being used as a regular child window, for example as a view pane. However, if the control is in a dialog then strange things may happen. Clicking on an item’s label causes the edit control to appear as expected, but any attempt to enter text causes the edit control to disappear along with the entire dialog! This is rather undesirable, to say the least.

The problem here, as is explained in Knowledge Base Q130692, is that the edit control is created with an ID of 1, which happens also to be the value of IDOK, the ID typically used for the ‘OK’ button. When the text in the edit control changes, it sends notifications such as EN_CHANGE to the tree or list-view, which for some reason forwards these notifications on to the dialog window. The upshot is that the dialog thinks the ‘OK’ has been pressed, and dismisses itself.

The solution is to have the ‘OK’ command handler check the window handle in lParam against that of the edit control. Commands coming from the edit control should be discarded. The edit control is retreived by sending a TVM_GETEDITCONTROL or LVM_GETEDITCONTROL message. These messages can be sent each time the window handle is needed, but it is more efficient to store the handle in a member variable when label editing begins, and set the variable to NULL when the edit finishes.

There is an additional twist when using a tree-view. Now we can enter text into the label edit control, but when the enter or escape key is pressed, once again the dialog dismisses itself. The problem is that the dialog manager is trapping these keys, mapping the enter key to the default ID and the escape key to IDCANCEL. This is basically due to a bug in the tree-view and is documented in Knowledge Base article Q130691. The article suggests subclassing the edit control so that it returns DLGC_WANTALLKEYS in response to the WM_GETDLGCODE message. It then says to send TVM_ENDEDITLABELNOW to the tree-view in response to WM_CHAR messages for VK_RETURN and VK_CANCEL. In fact, the subclass procedure never receives these keystrokes (at least on Windows 2000), but fortunately the label editing ends without further intervention.

As ever, there is yet another twist. Q130691 says to unsubclass the edit control in response to TVN_ENDLABELEDIT. However, by that time, the edit control’s window procedure has for some reason changed from what it was set to by subclassing in TVN_BEGINLABELEDIT. This causes ‘polite’ unsubclassing (such as ATL’s UnsubclassWindow) to fail. There is a choice between ‘forcing’ the unsubclassing, or just leaving the edit control subclassed until it is destroyed at the very end of the label edit operation.

It is not strictly necessary to subclass the edit control. The command handlers for the default ID and IDCANCEL could detect whether a label edit is in progress and, if so, end it by sending a TVM_ENDEDITLABELNOW message. However, the subclassing approach is more generic, and does not depend on knowing the default ID. ATL’s CContainedWindow class makes it rather easy to subclass the edit control using an alternate message map, with no need to derive a new class.

Addendum

Knowledge Base article Q130691 was updated on June 28 2002, taking my comments into account.

 
Home

Last updated on 16 July 2002.

 

Yahoo! GeoCities Member Banner Exchange Info 

1