Undo Methods and Properties


The editing area in WordPad is a Windows RichEdit control, and WordPad has an Undo command. The ActiveX RichTextBox control is also based on the RichEdit control, but it doesn’t have an Undo method. If WordPad can have one, why can’t we?


Well, we can. We just have to roll our own by sending the appropriate messages. Windows maintains an undo buffer for Edit and RichEdit controls and provides three edit messages to control the buffer: EM_UNDO, EM_CANUNDO, and EM_EMPTYUNDOBUFFER. It’s easy enough to wrap these up as features of the XEditor control:

Sub EditUndo()
Call SendMessage(txt.hWnd, EM_UNDO, ByVal 0&, ByVal 0&)
End Sub

Sub ClearUndo()
Call SendMessage(txt.hWnd, EM_EMPTYUNDOBUFFER, ByVal 0&, ByVal 0&)
End Sub

Property Get CanUndo() As Boolean
CanUndo = SendMessage(txt.hWnd, EM_CANUNDO, ByVal 0&, ByVal 0&)
End Property

This is about as simple as SendMessage gets. You pass the handle, the message constant, and zeros for the wParam and lParam parameters.


Edwina has an Edit menu with an Undo item. Here’s the menu event:

Private Sub mnuEditUndo_Click()
edit.EditUndo
End Sub

Edwina doesn’t use the ClearUndo method, but she does use the CanUndo property to disable the Undo menu item when there’s nothing to undo. The main Edit menu event procedure handles the update:

Private Sub mnuEdit_Click()
mnuEditUndo.Enabled = edit.CanUndo
End Sub

Usually, you don’t attach code to the event procedure for the top menu items, but it’s handy for updating either the disabled or checked state of items that might be changed by events outside the menu. This wouldn’t work for the Undo toolbar button, but few programs disable toolbar buttons. I could disable it nevertheless in the PositionChange event, which I’ll get to soon.


Edwina’s undo feature isn’t as sophisticated as the undo feature in more powerful editors. It has only one level of undo, and it might not undo some commands the way you think it should. But it’s easy to implement and better than nothing.


Notice the naming convention in the menu code. Where appropriate, I create method names from the name of the menu (Edit) and the item (Undo) where you would normally put the method names. Of course, nothing prevents you from tying this method to a button or a keystroke or even from putting it on some other menu with some other name. I copy the Notepad interface here because most developers are familiar with Notepad even if they (like me) prefer something (anything) different.