如何在C#(富文本框)中撤消和重做

问题描述 投票:4回答:3

我一直在尝试在文本编辑器中使用undoredo大约三天。我正在进来。

我有一个文本框(名称为richTextBoxPrintCtrl1),我希望能够undo和* redo *(逐字)。

因此,如果我单击撤消按钮,则会撤消最后一个单词。然后,如果我单击redo按钮,它redoes最后一个字。

有人可以帮我解决这个问题吗?

richTextBoxPrintCtrl1.Undo();效果不佳。它将删除在文本框中键入的所有内容。

感谢您的帮助。

我知道这个问题已经被问过很多次了,但是使用我在SO上浏览过的问题中的信息,我无法使它起作用。

c# winforms visual-studio-2012
3个回答
6
投票

好,我将发布一些代码来帮助您入门。首先,您需要监听TextChanged事件。

textBox1.TextChanged += new EventHandler(textBox1_TextChanged);

并且您需要在类中声明一个堆栈

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

在文本更改处理程序中,您需要将文本框的内容添加到堆栈中

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

然后您需要处理撤消,因此您可以简单地使用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();
         }
    }

3
投票

您可以通过处理像这样的KeyDown-,KeyPress-或KeyUp事件之一,让RichTextBox逐字为您构建撤消堆栈,并跟踪插入符号的位置:

 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
    }

由于RichTextBox为您完成了工作,因此您只需在需要的地方调用rtb.Undo()rtb.Redo()


0
投票

一种解决方案是使用双堆栈来保存文本框的先前内容和插入符号的位置(可以通过结构和更好的优化来改进。

以及使用条件变量来防止在TextChanged事件中再次进入。

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

namespace WindowsFormsAppTest
{

  public partial class FormTest : Form
  {
    private Stack<string> UndoTextStack = new Stack<string>();
    private Stack<int> UndoSelectionStartStack = new Stack<int>();

    private Stack<string> RedoTextStack = new Stack<string>();
    private Stack<int> RedoSelectionStartStack = new Stack<int>();

    private string PreviousText = "";
    private int PreviousSelectionStart = 0;

    private bool UndoRedoMutex;

    public FormTest()
    {
      InitializeComponent();
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
      if ( UndoRedoMutex ) return;
      UndoTextStack.Push(PreviousText);
      UndoSelectionStartStack.Push(PreviousSelectionStart);
      RedoTextStack.Clear();
      RedoSelectionStartStack.Clear();
    }
    private void textBox1_KeyDown(object sender, KeyEventArgs e)
    {
      if ( e.Control && e.KeyCode == Keys.Z )
      {
        if ( UndoTextStack.Count != 0 )
        {
          UndoRedoMutex = true;
          PreviousText = textBox1.Text;
          PreviousSelectionStart = textBox1.SelectionStart;
          RedoTextStack.Push(textBox1.Text);
          RedoSelectionStartStack.Push(textBox1.SelectionStart);
          textBox1.Text = UndoTextStack.Pop();
          textBox1.SelectionStart = UndoSelectionStartStack.Pop();
          UndoRedoMutex = false;
        }
        e.Handled = true;
        e.SuppressKeyPress = true;
      }
      else
      if ( e.Control && e.KeyCode == Keys.Y )
      {
        if ( RedoTextStack.Count != 0 )
        {
          UndoRedoMutex = true;
          UndoTextStack.Push(textBox1.Text);
          UndoSelectionStartStack.Push(textBox1.SelectionStart);
          textBox1.Text = RedoTextStack.Pop();
          textBox1.SelectionStart = RedoSelectionStartStack.Pop();
          PreviousText = textBox1.Text;
          PreviousSelectionStart = textBox1.SelectionStart;
          UndoRedoMutex = false;
        }
        e.Handled = true;
        e.SuppressKeyPress = true;
      }
      else
      {
        PreviousText = textBox1.Text;
        PreviousSelectionStart = textBox1.SelectionStart;
      }
    }
  }

}
© www.soinside.com 2019 - 2024. All rights reserved.