Extend this Class to Undo/Redo in a Listview

感情迁移 提交于 2019-11-30 19:32:14

Try this approach: Forget this current implementation, start implementing your own Undo/Redo class.

Every Method that manipulates something needs to create it own Undo methods. Store the delegates and invoke it when required. I have make an example with a simple Add / Remove of listview items.

Public Class Form1

Dim _undoManager As New UndoManager

''' <summary>
''' Delegates to Remove an item
''' </summary>
''' <param name="rowNumber"></param>
''' <remarks></remarks>
Delegate Sub RemoveDelegate(item As Object)

''' <summary>
''' Delegates to Add an Item
''' </summary>
''' <param name="text"></param>
''' <remarks></remarks>
Delegate Sub AddDelegate(text As String)


Sub AddItem(name As String)


    Dim newItem = ListView1.Items.Add(name)

    'Crate an Undo Operation
    Dim a As New action() With {.name = "Remove Item",
                        .Operation = New RemoveDelegate(AddressOf RemoveItem),
                                .data = New Object() {newItem}}

    _undoManager.Undostack.Push(a)

    ' Create a Redo        
    Dim a As New action() With {.name = "Add Item",
                        .Operation = New AddDelegate(AddressOf AddItem),
                                .data = New Object() {name}}

    _undoManager.Redostack.Push(a)



End Sub

Sub RemoveItem(item As Object)
    ListView1.Items.Remove(item)
End Sub

''' <summary>
''' Changes the Text of the Item
''' </summary>
''' <param name="item"></param>
''' <param name="text"></param>
''' <remarks></remarks>
Sub changetext(item As Object, text As String)
    Dim oldtext As String = item.text

End Sub


Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Me.AddItem("new Item")
End Sub

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
    _undoManager.UndoLastAction()
End Sub

End Class

Class UndoManager


Public Property Undostack As New Stack(Of action)
Public Property Redostack As New Stack(Of action)

''' <summary>
''' Undos the top of the stack
''' </summary>
''' <remarks></remarks>
Sub UndoLastAction()
    Dim action As action = Undostack.Pop ' Get the Action from Stack
    action.Operation.DynamicInvoke(action.data) ' Invoke the reverse Action 

End Sub

Sub RedoLastAction()
    Dim action As action = Redostack.Peek' Get the Action from Stack, but dont remove
    action.Operation.DynamicInvoke(action.data) ' Invoke the reverse Action 

End Sub


End Class

Class action
''' <summary>
''' Name the Undo / Redo Action
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Property name As String
''' <summary>
''' Points to a method to excecute
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Property Operation As [Delegate]
''' <summary>
''' Data Array for the method to excecute
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Property data As Object()
End Class

If look closely at line 328, it already handles a ListView. Is it lacking in some way?

I see. It's a bit of how you define what a "Redo" should do. In your case you want to Redo an Undo operation. By default, a Redo repeats the last action. Even If you Undo something, the Redo Undos again. Try this approach: Understand the Code fragment only as building blocks. The "RemoveItem" Method don't add Code to Undo/Redo stack - Add this Undo Redo like in the Add - Method. If you don't need to 'Undo an Undo' - Operation, add a

Property IsDoingUndo as boolean

To UndoManager and set it true if doing an Undo. Check this Property in Add/Remove Method and don't add something to the Undo/Redo Stack. Like :

If not _UndoManager.IsDoingUndo then 
...
else
...
endif

With this you will get control of what should be undo-able and redo-able. Sorry that I can not provide sourcecode this time.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!