Search code examples
c#winformsvisual-studiorichtextboxundo-redo

How can I implement effective Undo/Redo into my WinForms application?


I have a WinForm text editor.

I would like to be able to allow the user to undo and redo changes in the Rich Text Box, like they can in Microsoft Word.

I have spent the past week or so researching how to do this, and most results seem to be regarding graphics applications.

The standard richTextBox1.Undo(); gives disappointing results, as it undoes everything that the user has written.

Does anybody have any idea how I could implement effective undo/redo? Preferably one which undoes/redoes the action word-by-word as opposed to character-by-character.


Solution

  • This is a very basic idea, and I'm sure that many improvements could be made.

    I would create a String Array and incrementally store the value of the RichTextBox (In the TextChanged event, under your own conditions) in the array. As you store the value, increment the value of a counter, say stackcount. When the user undoes, decrement the stackcount and set the RichTextBox.Text = array(stackcount). If they redo, then increment the value of the counter and set the value again. If they undo and then change the text, then clear all values onwards.

    I am sure that many other people may have better suggestions/changes for this, so please post in comments and I will update, or edit it yourself!

    Example in C#

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace RedoUndoApp
    {
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    
        public string[] RTBRedoUndo;
        public int StackCount = 0;
        public int OldLength = 0;
        public int ChangeToSave = 5;
        public bool IsRedoUndo = false;
    
        private void Form1_Load(object sender, EventArgs e)
        {
            RTBRedoUndo = new string[10000];
            RTBRedoUndo[0] = "";
        }
    
        private void undo_Click(object sender, EventArgs e)
        {
            IsRedoUndo = true;
            if (StackCount > 0 && RTBRedoUndo[StackCount - 1] != null)
            {
                StackCount = StackCount - 1;
                richTextBox1.Text = RTBRedoUndo[StackCount];
            }
        }
    
        private void redo_Click(object sender, EventArgs e)
        {
            IsRedoUndo = true;
            if (StackCount > 0 && RTBRedoUndo[StackCount + 1] != null)
            {
                StackCount = StackCount + 1;
                richTextBox1.Text = RTBRedoUndo[StackCount];
            }
    
        }
    
        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            if (IsRedoUndo == false && richTextBox1.Text.Substring(richTextBox1.Text.Length - 1, 1) == " ")//(Math.Abs(richTextBox1.Text.Length - OldLength) >= ChangeToSave && IsRedoUndo == false)
            {
                StackCount = StackCount + 1;
                RTBRedoUndo[StackCount] = richTextBox1.Text;
                OldLength = richTextBox1.Text.Length;
            }
        }
    
        private void undo_MouseUp(object sender, MouseEventArgs e)
        {
            IsRedoUndo = false;
        }
    
        private void redo_MouseUp(object sender, MouseEventArgs e)
        {
            IsRedoUndo = false;
        }
    }
    }