The default textbox can only be undo in one step, and there is no redo operation (secondary Undo is equivalent to a redo operation ). The following component implements the multi-step Undo (undo and redo) operations of textbox. The code is adapted to Kevin. syntaxtextbox (the original code is the Undo and redo functions implemented for RichTextBox ). UsingSystem;UsingSystem. Collections. Generic;UsingSystem. Windows. forms;NamespaceEkinglong. Drawing. Forms {/// <Summary> /// textbox that can be undone in multiple steps /// </Summary> Public partial classTextboxex: textbox {// Undo/Redo members privateList <undoredoinfo> mundolist =NewList <undoredoinfo> ();PrivateStack <undoredoinfo> mredostack =NewStack <undoredoinfo> ();Private boolMisundo =False;PrivateUndoredoinfo mlastinfo =NewUndoredoinfo ("", 0 );Private intMmaxundoredosteps = 50;/// <Summary> // The on text changed overrided. // </Summary> // <Param name = "E"> </param> protected override voidOntextchanged (eventargs e ){Base. Ontextchanged (E );If(! Misundo) {mredostack. Clear (); mundolist. insert (0, mlastinfo );This. Limitundo (); mlastinfo =NewUndoredoinfo (text, selectionstart );}// Invalidate ();}/// <Summary> /// sets and obtains the maximum number of steps allowed by the Undo operation. // </Summary> Public intMaxundoredosteps {Set{Mmaxundoredosteps = value ;}Get{ReturnMmaxundoredosteps ;}}/// <Summary> /// clear undo and redo operation information /// </Summary> Public voidClearundoandredo () {mundolist. Clear (); mredostack. Clear ();}/// <Summary> /// determine whether undo operations can be performed /// </Summary> Public new boolCanundo {Get{ReturnMundolist. Count> 0 ;}}/// <Summary> /// determine whether redo operations can be performed. /// </Summary> Public boolCanredo {Get{ReturnMredostack. Count> 0 ;}}/// <Summary> /// undo the operation /// </Summary> Public new voidUndo (){If(! Canundo)Return; Misundo =True; Mredostack. Push (NewUndoredoinfo (text, selectionstart); undoredoinfo info = (undoredoinfo) mundolist [0]; mundolist. removeat (0); text = info. text; selectionstart = info. cursorlocation; scrolltocaret (); mlastinfo = Info; misundo =False;}/// <Summary> /// repeated operation /// </Summary> Public voidRedo (){If(! Canredo)Return; Misundo =True; Mundolist. insert (0,NewUndoredoinfo (text, selectionstart); limitundo (); undoredoinfo info = (undoredoinfo) mredostack. pop (); text = info. text; selectionstart = info. cursorlocation; scrolltocaret (); misundo =False;}Private voidLimitundo (){While(Mundolist. Count> mmaxundoredosteps) {mundolist. removeat (mmaxundoredosteps );}}Private classUndoredoinfo {PublicUndoredoinfo (StringText,IntCursorloc) {text = text; cursorlocation = cursorloc ;}Public readonly intCursorlocation;Public readonly stringText ;}}}
http://www.chenjiliang.com/Article/View.aspx?ArticleID=19079