我该如何在我的WinForms应用程序中实现有效的撤销和重做功能?

3
我有一个WinForm文本编辑器。
我想让用户能够像在Microsoft Word 中一样撤消和恢复更改。
我过去一周左右一直在研究如何做到这一点,大多数结果似乎涉及图形应用程序。
标准的richTextBox1.Undo()效果令人失望,因为它会撤消用户编写的所有内容。
是否有人知道我如何实现有效的撤销/重做?最好是逐个单词而不是逐个字符地撤销/重做操作。

请查看此链接:https://dev59.com/w3VD5IYBdhLWcg3wNY1Z - outcoldman
2个回答

3
这是一个很基础的想法,我相信有许多改进的地方。
我会创建一个`String Array`并逐步将`RichTextBox`的值(在您自己的条件下,在`TextChanged`事件中)存储在数组中。当您存储值时,增加计数器的值,比如说`stackcount`。当用户撤消操作时,减少`stackcount`的值,并设置`RichTextBox.Text = array(stackcount)`。如果他们要重做,则增加计数器的值并再次设置值。如果他们撤消操作,然后更改文本,则清除所有其后的值。
我相信许多其他人可能有更好的建议/更改意见,所以请在评论中发表,我将予以更新,或者您可以自行编辑!
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;
    }
}
}

我不得不将它转换为C#。我从未做过VB。但不幸的是,它并没有进展顺利。我将尝试另一种方法:http://www.codeproject.com/Articles/6947/Implementing-Object-Undo-and-Redo-capabilities-in - Toby
如果(RTBRedoUndo [StackCount-1!= null])错误:无法隐式转换类型“bool”为“int” - Toby
如果我尝试重新执行,同样的情况也会发生。 - Toby
好的。如果可以的话,我真的很感激。无论如何,我现在要去睡觉了。谢谢你的帮助,伙计。 - Toby
if (IsRedoUndo == false && (richTextBox1.Text.Substring(richTextBox1.Text.Length - 1, 1) == " " || richTextBox1.Text.Substring(richTextBox1.Text.Length - 1, 1) == "," || so on and so forth)) - JosephGarrone
显示剩余19条评论

2

一种实现方法是使用TextChanged事件定期将richtextbox.text的内容作为堆栈存储在数组或列表中。当您撤销时,“弹出堆栈”并将堆栈中最近的版本复制到richtextbox.text中。

TextChange可以确定是否应将更改保存到堆栈中,无论是新单词、新行还是新字符。


我该怎么做?如果这是个愚蠢的问题,对不起..我还在学习编程。 - Toby
这里唯一的问题是你将无法重做。一旦你弹出堆栈,它就会丢失。 - James Lawruk
啊,那是一个问题。实际上,我需要撤销和重做两个功能。 - Toby
你可以将“弹出”的元素保留在堆栈数组中,以便用于重做。从技术上讲,它不会是一个堆栈,但你只需保留一个指针来指定当前的“顶部”和最大的“顶部”,两者之差就是可能的重做次数。 - xpda
在richtextbox的textchanged事件中,每次调用时都保存文本。在你完成这个之后,你可以添加一些测试来限制撤销/重做到单词而不仅仅是字符。 - xpda
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接