6

I've been trying to get undo and redo working in my text editor for about 3 days now. It's doing my head in.

I have a text box (named richTextBoxPrintCtrl1), which I would like to be able to undo and *redo *(word by word).

So if I click the undo button, it undoes the last word. And if I then clicked the redo button, it redoes the last word.

Could somebody help me get this working?

richTextBoxPrintCtrl1.Undo(); doesn't work very well. It deletes everything typed in the text box.

Thanks in advance for your help.

I know this question has been asked many times before, but I can't get it working using the information from the questions I've browsed here on SO.

Ian R. O'Brien
  • 6,682
  • 9
  • 45
  • 73
  • I'm new to programming so forgive me if I'm being stupid. –  Apr 02 '13 at 19:26
  • There are several previous questions regarding this topic. You should do a search on StackOverflow for it. This one, for example http://stackoverflow.com/questions/8025926/any-textbox-control-for-winforms-with-multi-level-undo-feature – jugg1es Apr 02 '13 at 19:46
  • As I said, I have searched various sources (including SO) but cannot find one which I can understand/implement. –  Apr 02 '13 at 19:48
  • Then it would help if you posted code that showed what you've been able to do so far. As the other answers say, you have to implement your own custom undo using a stack each time the TextChanged event is fired and then pop the stack each time undo is called. – jugg1es Apr 02 '13 at 19:59
  • The thing is I haven't been able to get ANY type of undo working (besides richTextBoxPrintCtrl1.Undo();). –  Apr 02 '13 at 20:01
  • Peculiar. Undo and redo with ctrl+z and ctrl+y simply, uh, _work_, in a rich text box. The overall break in what is considered one edit seems to be caret movement. – Nyerguds Dec 15 '15 at 14:33

2 Answers2

7

Ok, I'll post some code to help you get started. first you need to listen for the TextChanged event.

textBox1.TextChanged += new EventHandler(textBox1_TextChanged);

and you need to declare a stack in the class

 Stack<string> undoList = new Stack<string>();

In the text changed handler, you need to add the contents of the textbox to the stack

 void textBox1_TextChanged(object sender, EventArgs e)
    {
        undoList.Push(textBox1.Text);
    }

Then you need to handle the undo, so you could simply use CTRL-Z

 textBox1.KeyDown += new KeyEventHandler(textBox1_KeyDown);

void textBox1_KeyDown(object sender, KeyEventArgs e)
    {
         if(e.KeyCode == Keys.Z && (e.Control)) {
             textBox1.Text = undoList.Pop();
         }
    }
jugg1es
  • 1,560
  • 18
  • 33
  • 1
    you can also check if `undoList.Count > 0` and make the textbox's text an empty string to avoid an empty stack error if you undo all the way to the beginning. – ikathegreat Mar 26 '14 at 17:14
  • I found one problem with this code. maybe I did it wrong but at the event handler I found that I have to pop the textbox list twice because. the texchanged function is being trigger as well – Franco Pettigrosso Aug 04 '17 at 01:52
  • I Found something interesting with the code. If I apply this to a button, such as a redo button. I have to pop it twice because the textchanged is being triggered – Franco Pettigrosso Aug 04 '17 at 02:00
  • This does not work : the Push add the last text so it does not do the undo when pop... and when the text is assigned in KeyDown, the TextChanged event is called. –  Apr 21 '20 at 08:50
  • This does not work : the Push add the last text so it does not do the undo when pop... and when the text is assigned in KeyDown, the TextChanged event is called. [How to implement good and efficient undo/redo functionality for a TextBox](https://stackoverflow.com/questions/597792/how-to-implement-good-and-efficient-undo-redo-functionality-for-a-textbox/61340503) ([My attempt is here](https://stackoverflow.com/questions/597792/how-to-implement-good-and-efficient-undo-redo-functionality-for-a-textbox/61340503#61340503)) –  Apr 21 '20 at 09:46
5

You can have the RichTextBox build the undo stack for you word by word, plus keep track of the caret position, by handling one of the KeyDown-, KeyPress- or KeyUp events like this:

 private void rtb_KeyDown(object sender, KeyEventArgs e)
    {
        // Trick to build undo stack word by word
        RichTextBox rtb = (RichTextBox)sender;
        if (e.KeyCode == Keys.Space)
        {
            this.SuspendLayout();
            rtb.Undo();
            rtb.Redo();
            this.ResumeLayout();
        }
        // eztnap
    }

Since the RichTextBox does the job for you, you just have to call rtb.Undo() or rtb.Redo() from wherever you need to.

Andreas
  • 51
  • 1
  • 1
  • note that there are other white spaces you'd might want to consider (like tab, etc) – evenro Oct 07 '14 at 14:31
  • Any reason you know why I couldn't use this with JSON, to be able to undo/redo through the states (so a LOT more words per instance?) – rainabba Aug 23 '22 at 22:53
  • If you use an Undo menu with ctrl+z as the keyboard shortcut. Put rtb.Undo() inside it's Click event for ctrl+z to work in stack. – Ray Chakrit Dec 27 '22 at 18:03