Отменяйте и повторяйте слово за словом в поле расширенного текста в Winforms

#c# #winforms

Вопрос:

Я пытаюсь отменить и повторить работу в своем текстовом редакторе уже около 3 дней. Это сводит меня с ума.

У меня есть текстовое поле (с именем richTextBoxPrintCtrl1), которое я хотел бы иметь возможность отменить и *повторить *(слово за словом).

Поэтому, если я нажму кнопку отменить, это отменит последнее слово. И если я затем нажму кнопку повторить, она повторит последнее слово.

Может кто-нибудь помочь мне с этим разобраться?

richTextBoxPrintCtrl1.Отменить(); работает не очень хорошо. Он удаляет все, что было введено в текстовое поле. и если вы наберете слишком много, появится эта ошибка

Заранее спасибо за вашу помощь.

Я знаю, что этот вопрос задавался много раз раньше, но я не могу заставить его работать, используя информацию из вопросов, которые я здесь просматривал. если это поможет здесь, мой код

 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;
}
 

Комментарии:

1. Если вы хотите слово за словом отменить. Вы можете реализовать вход в систему самостоятельно, используя stack функцию, в которой вводите все символы stack и отменяете ввод этого слова/символа для этой функции.

2. Я думаю, что самая большая проблема здесь заключается в том, что операции пользовательского интерфейса для расширенного текстового поля не структурированы в словесных единицах. Пользователь может вставлять, удалять и перезаписывать символы , вставлять их из буфера обмена, удалять или перезаписывать выбранные тексты. Это самые маленькие «единицы», которые имеют смысл для отмены/повтора — слова, похоже, не подходят идеально.

Ответ №1:

Добавив комментарий @piedpiper, вы можете посмотреть на шаблон дизайна сувениров (https://refactoring.guru/design-patterns/memento), который является поведенческим паттерном и имеет дело с этим типом функциональности.

Но один из способов подойти к этому-поместить каждое слово в массив/список. Затем у вас есть счетчик позиций, который вы уменьшаете при отмене, а затем объединяете всю строку в массиве до счетчика позиций и заменяете весь текст в текстовом поле объединенной строкой. Та же логика применима и для повтора, когда вы только увеличиваете счетчик позиций.

Вот пример того, как это может сработать. Я использовал форму Windows, RichEditBox, и я отключил свойство ShortcutsEnabled в RichEditBox на значение 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;
            }
        }
    }
}

 

Ответ №2:

Я нашел способ. Я надеюсь, что на этом закончатся все остальные вопросы. код, который у меня сейчас есть, работает :

     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];
    }


}
 

Мероприятия:

 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;
    }
 

изменение текстового поля

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