locked
Undo/Redo Functionality in Application

    Question

  • What is the best way to handle relatively simple undo/redo operations within an application I am developing?

    Most of the GUI contains text boxes and other similar controls that allow the user to interact with data from the database.  I just want to be able to undo/redo edits on the text within those controls until the user commits the changes to the database.  Once committed, the undo/redo history would be reset.

    I have searched MSDN and found a small number of threads.  One mentioned use of the Undo Engine while another mentioned using a Stack.  I have not used either before and don't know which would be the best route to pursue.

    Thanks.

    Saturday, March 03, 2007 2:13 PM

Answers

  • It sounds like your plan should work. You can use the TextBox (and any other controls) Tag property to store the old value in (unless you use it for something else). It would be something like this.

    Sub TextBox1_GotFocus(...) Handles TextBox1.GotFocus
      TextBox1.Tag = TextBox1.Text
    End Sub

    Sub TextBox1_LostFocus(...) Handled TextBox1.LostFocus
      If TextBox1.Tag <> TextBox1.Text Then
        UndoStack.Push(TextBox1.Tag)
      End If
    End Sub

    I suggested to use a Queue and it was incorrect by me but you seem to have caught that and use a stack instead.

     

    Monday, March 12, 2007 10:46 AM

All replies

  • The RichTextBox control has an undo action built in, but I have never tried this with database integration before.
    Saturday, March 03, 2007 4:02 PM
  • I am using a normal text box which has an Undo public sub, but it appears that is only works when that control has focus.

    For example, if I change a text box entry, and give another control focus, the Undo event will not fire for the previous control.  However, if I return to the changed text box and fire the Undo event again, the text returns to it's previous state as intended.

    How do I extend the Undo event across controls?

    Thanks.

    Saturday, March 03, 2007 6:20 PM
  • You should keep track of data has been confirmed and when losing focus revert to the last know confirmed data.

    Check the LostFocus event to do this.

    Saturday, March 03, 2007 10:43 PM
  • Here is the functionality in detail of what I am hoping to accomplish.

    My application has five tab sheets in it.  I already have code that prompts the user to save the data before clicking on the next sheet.  In my mind, when the data is saved to the database, the undo history will be cleared and be reset.

    I am thinking I need some sort of Undo/Redo stack for users as they are working on the tab.  It doesn't have to be big in my opinion, perhaps enough room for ten entries.  When the 11th entry is added, the first entry would drop out of the bottom.  Again, when the save button was clicked, all ten entries would be cleared.

    I just haven't ever done this before, so I am looking for a little help.

    Thanks.

    Saturday, March 10, 2007 8:05 PM
  • Create a new class that embeds a Queue object.

    Push any new data on to it and Pop it when you undo a step.

    If you want to  limit the number of steps just call Pop when a Push call pushes it over the limit.

    Sunday, March 11, 2007 4:11 AM
  • Okay, I think I need to back up a step.  Please be patient.  As I mentioned, I haven't done too much of this before.

    I think I have a decent understanding of how Undo/Redo will need to interact with a stack or queue object.  But I haven't been able to totally comprehend how I will determine which information, or more importantly, when that information gets added to the stack.

    My application uses mostly text boxes, some masked text boxes, combo boxes, and date picker controls.

    It was suggested that I use the Lost Focus event.  But when I did that, the command would be fired when a user just tabbed through the controls on the form.

    I also was thinking that maybe I should use the Text Changed event.  The problem I encountered here was that the command was fired prematurely, before the user was completed with the change.  If the user changes an entry from "John Smith" to "John Doe", I want to enter one entry containing "Smith" into the undo history as opposed to multiples entries of "h", "t", "i", "m", "S", etc.

    It appears that I need some combination of the two events.

    Furthermore, I don't understand exactly what information I will be adding to the stack or queue.  My gut tells me that I would need an array possibly of the control name, old text, new text.  But again, I am not sure about that.

    I hate to take this thread backwards, but I just can't get my mind around this logic.

    Thanks.

    Sunday, March 11, 2007 1:37 PM
  • I have been chipping away at this.

    My latest logic involves two public variables, strOldValue as string and strNewValue as string.

    In the textbox GotFocus event, I set strOldValue to the textbox text.  When the LostFocus event is fired, I set strNewValue to the textbox text.  Then, in this event I do a comparison to see if they are the same.  If they aren't, I plan on adding them to the stack.

    Does this seem like I am headed in the right path?

    Thanks.

    Monday, March 12, 2007 2:39 AM
  • It sounds like your plan should work. You can use the TextBox (and any other controls) Tag property to store the old value in (unless you use it for something else). It would be something like this.

    Sub TextBox1_GotFocus(...) Handles TextBox1.GotFocus
      TextBox1.Tag = TextBox1.Text
    End Sub

    Sub TextBox1_LostFocus(...) Handled TextBox1.LostFocus
      If TextBox1.Tag <> TextBox1.Text Then
        UndoStack.Push(TextBox1.Tag)
      End If
    End Sub

    I suggested to use a Queue and it was incorrect by me but you seem to have caught that and use a stack instead.

     

    Monday, March 12, 2007 10:46 AM
  • Hello,

     

    I am just wondering if there is no better way of tracking the changes in the text box.

    In my application I am using quite big multilined textfields and I also provide undo/redo functionality for them.

    But at this moment I do it in a 'not very smart' way.  I use TextChanged event and on each change I create undo entry in my app. So each character user enters goes to my undo stack.

    However doing it only on got/lost focus is not enough for me.

     

    I am looking for a solution which is in beetween of those mention above.

     

    Thank you for the answer,

    Lukasz Magdziarz

    Friday, August 03, 2007 10:15 AM