I have too much problems trying to implement an Undo/Redo operation in a ListView Control, just to add/remove items.
I realized time ago a relative question here Extend this Class to Undo/Redo in a Listview where I was started multiple bountyes of 50, 100, 200 and 300 points, a total of 650 points... but no body could really helped me to finalize this issue in weeks and months.
But after time in that question finally a user ( @ThorstenC ) showed me a possible solution and a great idea, the code of him is incomplete so the code of him is what I'm trying to realize/finish.
The problem is Simple "undo" works fine, but when I try to redo more than 1 time it throws an exception about it can't add the same item again in the listview, also the code has more problems for example at the moment I'm not able to redo a undo operation, or undo a redo operation.
Just I need help to make a working Undo/Redo manager for Listview Item adding/removing, that's all, I have written the half part of the code, I need help to finish it I have a mess in my head with this.
Here is a simple WinForms source project in VS2012 that I've uploaded to test the undo manager fails:
http://elektrostudios.tk/UndoManager.zip
Here is a video to show you the errors that I get trying to undo/redo: http://www.youtube.com/watch?v=MAzChURATpM
Here is the UndoManager Class of @ThorstenC with a little retouches:
Class ListView_UndoManager
Public Property Undostack As New Stack(Of ListView_Action)
Public Property Redostack As New Stack(Of ListView_Action)
Public Property IsDoingUndo As Boolean ' = False
Public Property IsDoingRedo As Boolean ' = False
Private action As ListView_Action = Nothing
''' <summary>
''' Undo the last action.
''' </summary>
''' <remarks></remarks>
Sub UndoLastAction()
If Undostack.Count = 0 Then Exit Sub ' Nothing to Undo.
action = Undostack.Pop ' Get the Action from Stack and remove it.
action.Operation.DynamicInvoke(action.data) ' Invoke the undo Action.
'Redostack = New Stack(Of ListView_Action)(Redostack)
'Redostack.Pop()
'Redostack = New Stack(Of ListView_Action)(Redostack)
End Sub
''' <summary>
''' Redo the last action.
''' </summary>
''' <remarks></remarks>
Sub RedoLastAction()
' If Redostack.Count = Undostack.Count Then Exit Sub
If Redostack.Count = 0 Then Exit Sub ' Nothing to Redo.
'Redostack = New Stack(Of ListView_Action)(Redostack) ' Reverse the Stack contents.
action = Redostack.Pop() ' Get the Action from Stack and remove it.
' action = Redostack.Peek()
action.Operation.DynamicInvoke(action.data) ' Invoke the redo Action.
'Redostack = New Stack(Of ListView_Action)(Redostack) ' Re-Reverse the Stack contents.
End Sub
End Class
Class ListView_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
And here is the rest of the code where I'm trying to Undo/Redo Adding/Deleting listview items:
Public Class Form1
Dim _undoManager As New ListView_UndoManager
Delegate Sub RemoveDelegate(item As ListViewItem)
Delegate Sub AddDelegate(item As ListViewItem)
Dim newItem As ListViewItem = Nothing
Sub AddItem(ByVal item As ListViewItem)
' // Crate an Undo Action
Dim u As New ListView_Action() With {.name = "Remove Item",
.Operation = New RemoveDelegate(AddressOf RemoveItem),
.data = New Object() {newItem}}
_undoManager.Undostack.Push(u)
ListView_Elektro1.AddItem(item)
End Sub
Sub RemoveItem(item As ListViewItem)
' // Create a Redo Action
Dim r As New ListView_Action() With {.name = "Add Item",
.Operation = New AddDelegate(AddressOf AddItem),
.data = New Object() {item}}
_undoManager.Redostack.Push(r)
' Remove the ListViewItem from ListView
ListView_Elektro1.RemoveItem(item)
End Sub
Private Sub Button_AddItem_Click(sender As Object, e As EventArgs) _
Handles Button_AddItem.Click
Dim index As String = CStr(ListView_Elektro1.Items.Count + 1)
newItem = New ListViewItem _
With {.Text = index}
newItem.SubItems.AddRange({"Hello " & index, "World " & index})
AddItem(newItem)
End Sub
Private Sub Button_RemoveItem_Click(sender As Object, e As EventArgs) _
Handles Button_RemoveItem.Click
newItem = ListView_Elektro1.Items.Cast(Of ListViewItem).Last
RemoveItem(newItem)
End Sub
Private Sub Button_Undo_Click(sender As Object, e As EventArgs) _
Handles Button_Undo.Click
' _undoManager.IsDoingUndo = True
_undoManager.UndoLastAction()
' _undoManager.IsDoingUndo = False
End Sub
Private Sub Button_Redo_Click(sender As Object, e As EventArgs) _
Handles Button_Redo.Click
'_undoManager.IsDoingRedo = True
_undoManager.RedoLastAction()
'_undoManager.IsDoingRedo = False
End Sub
Private Sub ListView_Elektro1_ItemAdded() _
Handles ListView_Elektro1.ItemAdded, _
ListView_Elektro1.ItemRemoved
Label_UndoCount_Value.Text = CStr(_undoManager.Undostack.Count)
Label_RedoCount_Value.Text = CStr(_undoManager.Redostack.Count)
End Sub
End Class
_undoManager.RedoLastAction()
you could see it in the video that I've uploaded, but that exception is not all the problem,I'll quote this from my question please read:The problem is when I try to redo more than 1 time it throws an exception about it cant add the same item again in the listview, also the code has more problems for example ATM I'm not able to redo a undo operation, or undo a redo operation
– Morie