[C#]实现RichTextBox的多步撤销
RichTextBox默认的Undo、Redo只能进行多个单元的撤销合并操作。以下组件实现了RichTextBox的单个单元的撤销,即可以撤销一个字符。
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace RichTextBoxEs
{
/// <summary>
/// 可以执行多步撤销文本框
/// </summary>
public partial class RichTextBoxEs : RichTextBox
{
private List<UndoRedoInfo> mUndoList = new List<UndoRedoInfo>();
private Stack<UndoRedoInfo> mRedoStack = new Stack<UndoRedoInfo>();
private bool mlsUndo = false;
private string oldStr = "";
/// <summary>
/// 文本覆盖
/// </summary>
/// <param name="e"></param>
protected override void OnTextChanged(EventArgs e)
{
//base.OnTextChanged(e);
if (!mlsUndo)
{
mRedoStack.Clear();
mUndoList.Insert(0, new UndoRedoInfo(oldStr, SelectionStart));
this.LiMitUndo();
}
oldStr = Rtf;
//Invalidate();
}
/// <summary>
/// 设置最大撤销步数
/// </summary>
public int MaxUndoRedSteps { get; set; } = 50;
/// <summary>
/// 清空Undo、Redo操作信息
/// </summary>
public void ClearUndoAndRedo()
{
mUndoList.Clear();
mRedoStack.Clear();
}
/// <summary>
/// 判断是否可执行Undo
/// </summary>
public new bool CanUndo
{
get => mUndoList.Count > 0;
}
/// <summary>
/// 判断是否可以执行Redo
/// </summary>
public new bool CanRedo
{
get => mRedoStack.Count > 0;
}
/// <summary>
/// 撤销
/// </summary>
public new void Undo()
{
if (!CanUndo) return;
mlsUndo = true;
int InitialPosition = -Text.Length;
UndoRedoInfo Info = (UndoRedoInfo)mUndoList[0];
mUndoList.RemoveAt(0);
mRedoStack.Push(new UndoRedoInfo(oldStr, Info.CursorLocation));
Rtf = Info.Rtf;
SelectionStart = Info.CursorLocation + InitialPosition + Text.Length;
ScrollToCaret();
mlsUndo = false;
Focus();
}
/// <summary>
/// 重做
/// </summary>
public new void Redo()
{
if (!CanRedo) return;
mlsUndo = true;
UndoRedoInfo Info = (UndoRedoInfo)mRedoStack.Pop();
mUndoList.Insert(0, new UndoRedoInfo(oldStr, Info.CursorLocation));
LiMitUndo();
Rtf = Info.Rtf;
SelectionStart = Info.CursorLocation;
ScrollToCaret();
mlsUndo = false;
Focus();
}
private void LiMitUndo()
{
while (mUndoList.Count > MaxUndoRedSteps)
{
mUndoList.RemoveAt(MaxUndoRedSteps);
}
}
private class UndoRedoInfo
{
public readonly int CursorLocation;
public readonly string Rtf;
public UndoRedoInfo(string rtf, int cursorLoc)
{
Rtf = rtf;
CursorLocation = cursorLoc;
}
}
}
}
文章思路来源于TextBox多步撤销