Amirmohammad Ramezani
Amirmohammad Ramezani

Reputation: 25

Undo and Redo word by word in Rich Text Box in Winforms

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. and if you type too much this error will appear

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. if it helps here my code

private string[] temp = new string[100];
private int index;
private int currentpostion;

public Undo()
{
    index = 0;
    currentpostion = 0;
}

public void Set_Text(string s)
{
    temp[index] = s;
    currentpostion = index;
    ++index;
}

public string UndoCons()
{
    if (currentpostion > 0)
    {
        return temp[--currentpostion];
    }
    return null;
}

public string RedoCosns()
{
    if (currentpostion < index)
    {
        return temp[++currentpostion];
    }
    return null;
}

Upvotes: 1

Views: 409

Answers (2)

Amirmohammad Ramezani
Amirmohammad Ramezani

Reputation: 25

I have found a way. I hope this end all the other questions. the code that I have now is working :

    public class Operation
{
    private static List<string> _txt_list = new List<string>() { "" };
    private static int Position { get; set; }
    public void ChangeText(string txt)
    {
        if (_txt_list.Count < 100)
        {
            _txt_list.Add(txt);
            //a     0
            //al    1
            //ali   2
        }
        else 
        {
            for (int i = 0; i < 100; i++) 
            {
                if (i == 99)
                {
                    _txt_list[i] = txt;
                }
                else 
                {
                    _txt_list[i] = _txt_list[i + 1];
                }
            }
        }

        if (Position < 99) 
        {
            Position = _txt_list.Count -1;
        }
    }

    public string Undo() 
    {
        if (Position > 0) 
        {
            Position--;
        }
        return _txt_list[Position];
    }

    public string Redo()
    {
        if (Position < 99)
        {
            Position++;
        }
        
        return _txt_list[Position];
    }


}

events:

private void Menu_Edit_Undo_Click(object sender, EventArgs e)
    {
        txt_Notepad.Text = _operationObj.Undo();
        txt_Notepad.SelectionStart = txt_Notepad.Text.Length;
        txt_Notepad.SelectionLength = 0;
    }


 private void Menu_Edit_Redo_Click(object sender, EventArgs e)
    {
        txt_Notepad.Text = _operationObj.Redo();
        txt_Notepad.SelectionStart = txt_Notepad.Text.Length;
        txt_Notepad.SelectionLength = 0;
    }

textbox change

private void txt_keyUp(object sender, KeyEventArgs e)
    {
        _operationObj.ChangeText(txt_Notepad.Text);
    }

Upvotes: 0

mnemonic
mnemonic

Reputation: 1032

Adding to @piedpiper's comment, you can look at the Memento design pattern (https://refactoring.guru/design-patterns/memento) which is a behavioral pattern and deals with this type of functionality.

But one way to approach this is to push every word to an array/List. You then have a with a position counter which you decrement on the undo, and then concatenate all the string in your array up to your position counter and replace all the text in your textbox with the concatenated string. The same logic applies for the redo, where you only increment the position counter.

Here is an example of how this can work. I've used a Windows Form, RichEditBox and I disabled the 'ShortcutsEnabled' property on the RichEditBox to False.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private IList<Keys> ignoreKeys = new List<Keys> { Keys.Control, Keys.Tab, Keys.Shift, Keys.ControlKey, Keys.ShiftKey, Keys.LShiftKey, Keys.RShiftKey };
        private IList<string> Words { get; set; }
        private int counter = 0;

        public Form1()
        {
            InitializeComponent();
            Words = new List<string>();
        }

        private void richTextBox1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Control)
            {
                if (e.KeyCode == Keys.Z)
                {
                    counter--;
                }

                if (e.KeyCode == Keys.Y)
                {
                    counter++;
                }

                richTextBox1.Text = String.Join(" ", Words.Take(counter));
            }
            else if (!ignoreKeys.Any(ignoreKey => ignoreKey == e.KeyCode))
            {
                Words = richTextBox1.Text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                counter = Words.Count;
            }
        }
    }
}

Upvotes: 1

Related Questions