我正在尝试为文本框的某些事件实现一个简单的撤消/重做机制(基于堆栈)。
  
  
   在提出这个问题之前,我已经看到了很多撤销/重做实现,如
   
    
     these
    
   
   ,但它们或多或少都是不完整的,显示了我已经知道的东西(另一方面,使用稀有接口的专业方式超出了我的理解,所以我想遵循这种基于堆栈的方式),因为这些示例不仅仅是编辑控件的撤消/重做示例,而是堆栈的推/弹出示例,但是撤销/重做比编写一个方法来弹出“
   
    撤销栈
   
   “和另一种弹出”
   
    重做堆栈
   
   “,因为在用户与控件交互的某个时刻,堆栈应该被清除/重置。
  
  
   我的意思是,在编辑控件的真正撤消/重做机制中,“
   
    重做堆栈
   
   “当用户撤消并且用户在控件中进行文本修改时,应清除”
   
    撤销栈
   
   “仍然包含项,因此在这一点上没有什么可重做的,因为撤消时发生了更改。
考虑到控件中发生更改时必须如何操作撤消/重做堆栈,我还没有看到任何以这种方式执行撤消/重作机制的完整示例。
  
  
   我需要帮助来正确地实现我的撤销/重做堆栈的逻辑,我开始自己尝试了几天,尝试了几次,但总是忽略了一些细节,因为当我让一个(撤销或重做)堆栈正常工作时,另一个堆栈会停止按预期工作,撤销它不应该撤销的或重做它不应该重做的,
所以我(再次)放弃了
   
    
     all the conditional logic that I written
    
   
   因为我的逻辑总是错误的,所以我应该用一个合适的条件算法从零开始,我的意思是在合适的时候用合适的条件推送或弹出堆栈项。
  
  
   然后,不仅仅是文字或建议,我需要一个可以用我的算法解决问题的工作代码,我需要完成
   
    AddUndoRedoItem
   
   在下面的代码中,这是一个具体的问题。
  
  
   如果我缺少遵循相同原则的更简单的解决方案(撤销和重做堆栈),我也会接受这个解决方案。
  
  
   不管是在C#还是Vb.Net中。
  
  
   零件编号:
如果因为我的英语不好,我没有正确地解释一些事情,而你也不完全确定我要的是什么样的撤销/重做,只是我要求的是一个听起来很像的撤销/重新做,那就测试一下
   
    Ctrl+Z组合键
   
   (撤销)和
   
    Ctrl+Y组合键
   
   当在记事本中执行撤消或重做的文本更改时,请查看它的行为,这是一个真正的撤消/重做实现,这是我试图用堆栈复制的。
  
  
  
   这是当前代码:
  
  Public Enum UndoRedoCommand As Integer
    Undo
    Redo
End Enum
Public Enum UndoRedoTextBoxEvent As Integer
    TextChanged
End Enum
Public NotInheritable Class UndoRedoTextBox
    Private ReadOnly undoStack As Stack(Of KeyValuePair(Of UndoRedoTextBoxEvent, Object))
    Private ReadOnly redoStack As Stack(Of KeyValuePair(Of UndoRedoTextBoxEvent, Object))
    Private lastCommand As UndoRedoCommand
    Private lastText As String
    Public ReadOnly Property Control As TextBox
        Get
            Return Me.controlB
        End Get
    End Property
    Private WithEvents controlB As TextBox
    Public ReadOnly Property CanUndo As Boolean
        Get
            Return (Me.undoStack.Count <> 0)
        End Get
    End Property
    Public ReadOnly Property CanRedo As Boolean
        Get
            Return (Me.redoStack.Count <> 0)
        End Get
    End Property
    Public ReadOnly Property IsUndoing As Boolean
        Get
            Return Me.isUndoingB
        End Get
    End Property
    Private isUndoingB As Boolean
    Public ReadOnly Property IsRedoing As Boolean
        Get
            Return Me.isRedoingB
        End Get
    End Property
    Private isRedoingB As Boolean
    Public Sub New(ByVal tb As TextBox)
        Me.undoStack = New Stack(Of KeyValuePair(Of UndoRedoTextBoxEvent, Object))
        Me.redoStack = New Stack(Of KeyValuePair(Of UndoRedoTextBoxEvent, Object))
        Me.controlB = tb
        Me.lastText = tb.Text
    End Sub
    Public Sub Undo()
        If (Me.CanUndo) Then
            Me.InternalUndoRedo(UndoRedoCommand.Undo)
        End If
    End Sub
    Public Sub Redo()
        If (Me.CanRedo) Then
            Me.InternalUndoRedo(UndoRedoCommand.Redo)
        End If
    End Sub
    ' Undoes or redoues.
    Private Sub InternalUndoRedo(ByVal command As UndoRedoCommand)
        Dim undoRedoItem As KeyValuePair(Of UndoRedoTextBoxEvent, Object) = Nothing
        Dim undoRedoEvent As UndoRedoTextBoxEvent
        Dim undoRedoValue As Object = Nothing
        Select Case command
            Case UndoRedoCommand.Undo
                Me.isUndoingB = True
                undoRedoItem = Me.undoStack.Pop
                Me.AddUndoRedoItem(UndoRedoCommand.Redo, UndoRedoTextBoxEvent.TextChanged, Me.lastText, undoRedoItem.Value)
            Case UndoRedoCommand.Redo
                Me.isRedoingB = True
                undoRedoItem = Me.redoStack.Pop
                Me.AddUndoRedoItem(UndoRedoCommand.Undo, UndoRedoTextBoxEvent.TextChanged, undoRedoItem.Value, Me.lastText)
        End Select
        undoRedoEvent = undoRedoItem.Key
        undoRedoValue = undoRedoItem.Value
        Select Case undoRedoEvent
            Case UndoRedoTextBoxEvent.TextChanged
                Me.controlB.Text = CStr(undoRedoValue)
        End Select
        Me.isUndoingB = False
        Me.isRedoingB = False
    End Sub
    Private Sub AddUndoRedoItem(ByVal command As UndoRedoCommand, ByVal [event] As UndoRedoTextBoxEvent,
                                ByVal data As Object, ByVal lastData As Object)
        Console.WriteLine()
        Console.WriteLine("command     :" & command.ToString)
        Console.WriteLine("last command:" & lastCommand.ToString)
        Console.WriteLine("can undo    :" & Me.CanUndo)
        Console.WriteLine("can redo    :" & Me.CanRedo)
        Console.WriteLine("is undoing  :" & Me.isUndoingB)
        Console.WriteLine("is redoing  :" & Me.isRedoingB)
        Console.WriteLine("data        :" & data.ToString)
        Console.WriteLine("last data   :" & lastData.ToString)
        Dim undoRedoData As Object = Nothing
        Me.lastCommand = command
        Select Case command
            Case UndoRedoCommand.Undo
                If (Me.isUndoingB) Then
                    Exit Select
                End If
                undoRedoData = lastData
                Me.undoStack.Push(New KeyValuePair(Of UndoRedoTextBoxEvent, Object)([event], undoRedoData))
            Case UndoRedoCommand.Redo
                If (Me.isRedoingB) Then
                    Exit Select
                End If
                undoRedoData = lastData
                Me.redoStack.Push(New KeyValuePair(Of UndoRedoTextBoxEvent, Object)([event], undoRedoData))
        End Select
    End Sub
    Private Sub TextBox_TextChanged(ByVal sender As Object, ByVal e As EventArgs) _
    Handles controlB.TextChanged
        Dim currentText As String = Me.controlB.Text
        If Not String.Equals(Me.lastText, currentText, StringComparison.Ordinal) Then
            Select Case Me.lastCommand
                Case UndoRedoCommand.Undo
                    Me.AddUndoRedoItem(UndoRedoCommand.Undo, UndoRedoTextBoxEvent.TextChanged, currentText, Me.lastText)
                Case UndoRedoCommand.Redo
                    Me.AddUndoRedoItem(UndoRedoCommand.Redo, UndoRedoTextBoxEvent.TextChanged, Me.lastText, currentText)
            End Select
            Me.lastText = currentText
        End If
    End Sub
End Class