Что ж, здесь я должен поговорить о второй части этого вопроса Операции отмены/возврата для добавления/удаления элементов ListView и других Расширить этот класс до Undo/Redo в Listview.
Я пытаюсь реализовать операции Undo/Redo для добавления/удаления элементов ListView.
Я продвинулся еще немного с кодированием этого кода LV UndoManager, но мне всегда очень сложно, когда я пытаюсь продвинуться вперед.
На данный момент я могу добавлять отдельные элементы, а затем я могу отлично отменить/повторить ДОБАВЛЕННЫЕ элементы, не более того.
Проблемы, которые у меня есть, следующие:
· Когда я удаляю один элемент из списка, я не могу выполнить «отмену», чтобы снова добавить этот удаленный элемент в LV.
· Когда я добавляю диапазон, если элементы, которые я не могу отменить, Когда я вызываю UndoLastAction
, возникает исключение System.Reflection.TargetParameterCountException
· Когда я удаляю ряд элементов, я не могу отменить/повторить операцию и запускаю то же исключение.
В резюме, если я добавлю один элемент, я могу отменить/повторить его идеально, если я удалю один элемент, который я не могу отменить правильно, также я не могу отменить/повторить ряд ListViewItems.
Мне нужен кто-то, кто мог бы помочь мне решить эти проблемы... или хотя бы одну из них, проявив терпение.
Код немного великоват, поэтому я думаю, что может потребоваться меньше времени, чтобы понять и найти ошибки, открывая и тестируя этот исходный проект, который я загрузил.
Вот full
Источник:
http://elektrostudios.tk/UndoManager%20Test%20Application.zip
Просто изображение:
вот класс UndoManager:
Class ListView_UndoManager
Private action As ListView_Action = Nothing
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
''' <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.
End Sub
''' <summary>
''' Redo the last action.
''' </summary>
''' <remarks></remarks>
Sub RedoLastAction()
If Redostack.Count = 0 Then Exit Sub ' Nothing to Redo.
action = Redostack.Pop() ' Get the Action from Stack and remove it.
action.Operation.DynamicInvoke(action.data) ' Invoke the redo Action.
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 ListViewItem()
End Class
Вот пользовательский элемент управления ListView, который я использую, я публикую его, потому что важны события, которые я запускаю: ItemAdded
, ItemRemoved
, RangeItemAdded
и RangeItemRemoved
.
Public Class LV : Inherits ListView
Public Shared Event ItemAdded As EventHandler(Of ItemAddedEventArgs)
Public Class ItemAddedEventArgs : Inherits EventArgs
Public Property Item As ListViewItem
End Class
Public Shared Event ItemRemoved As EventHandler(Of ItemRemovedEventArgs)
Public Class ItemRemovedEventArgs : Inherits EventArgs
Public Property Item As ListViewItem
End Class
Public Shared Event RangeItemAdded As EventHandler(Of RangeItemAddedEventArgs)
Public Class RangeItemAddedEventArgs : Inherits EventArgs
Public Property Items As ListViewItem()
End Class
Public Shared Event RangeItemRemoved As EventHandler(Of RangeItemRemovedEventArgs)
Public Class RangeItemRemovedEventArgs : Inherits EventArgs
Public Property Items As ListViewItem()
End Class
Public Sub New()
Me.Name = "ListView_Elektro"
Me.GridLines = True
Me.FullRowSelect = True
Me.MultiSelect = True
Me.View = View.Details
End Sub
''' <summary>
''' Adds an Item to the ListView,
''' to monitor when an Item is added to the ListView.
''' </summary>
Public Function AddItem(ByVal Item As ListViewItem) As ListViewItem
RaiseEvent ItemAdded(Me, New ItemAddedEventArgs With { _
.Item = Item
})
Return MyBase.Items.Add(Item)
End Function
''' <summary>
''' Adds a range of Items to the ListView,
''' to monitor when an Item is added to the ListView.
''' </summary>
Public Sub AddItem_Range(ByVal Items As ListViewItem())
RaiseEvent RangeItemAdded(Me, New RangeItemAddedEventArgs With { _
.Items = Items
})
MyBase.Items.AddRange(Items)
End Sub
''' <summary>
''' Removes an Item from the ListView
''' to monitor when an Item is removed from the ListView.
''' </summary>
Public Sub RemoveItem(ByVal Item As ListViewItem)
RaiseEvent ItemRemoved(Me, New ItemRemovedEventArgs With { _
.Item = Item
})
MyBase.Items.Remove(Item)
End Sub
''' <summary>
''' Removes a range of Items from the ListView
''' to monitor when an Item is removed from the ListView.
''' </summary>
Public Sub RemoveItem_Range(ByVal Items As ListViewItem())
RaiseEvent RangeItemRemoved(Me, New RangeItemRemovedEventArgs With { _
.Items = Items
})
For Each Item As ListViewItem In Items
MyBase.Items.Remove(Item)
Next
End Sub
End Class
И, наконец, вот код Form1 тестового приложения, вот то, что я использую для добавления/удаления элементов и вызова отмены/повторения, но я вызываю методы моего пользовательского элемента управления ListView, поэтому вы должны заметить, что... :
Public Class Form1
Dim _undoManager As New ListView_UndoManager
Dim LVItem As ListViewItem
Delegate Sub AddDelegate(item As ListViewItem)
Delegate Sub RemoveDelegate(item As ListViewItem)
Delegate Sub AddRangeDelegate(item As ListViewItem())
Delegate Sub RemoveRangeDelegate(item As ListViewItem())
' Adds a single item
Private Sub Button_AddItem_Click(sender As Object, e As EventArgs) _
Handles Button_AddItem.Click
Dim index As String = CStr(LV1.Items.Count + 1)
LVItem = New ListViewItem With {.Text = index}
LVItem.SubItems.AddRange({"Hello " & index, "World " & index})
LV1.AddItem(LVItem)
End Sub
' Adds a range of 2 items to the ListView
Private Sub Button_AddRange_Of_Items_Click(sender As Object, e As EventArgs) Handles Button_AddRange_Of_Items.Click
Dim index As String = CStr(LV1.Items.Count + 1)
Dim lvitem As New ListViewItem With {.Text = index}
lvitem.SubItems.AddRange({"Hello " & index, "World " & index})
Dim lvitem2 As New ListViewItem With {.Text = index + 1}
lvitem2.SubItems.AddRange({"Hello " & index + 1, "World " & index + 1})
LV1.AddItem_Range({lvitem, lvitem2})
End Sub
' Removes the last item
Private Sub Button_RemoveLastItem_Click(sender As Object, e As EventArgs) _
Handles Button_RemoveLastItem.Click
If LV1.Items.Count <> 0 Then
LV1.RemoveItem(LV1.Items.Cast(Of ListViewItem).Last)
End If
End Sub
' Clear all items
Private Sub Button_Clear_Items_Click(sender As Object, e As EventArgs) _
Handles Button_Clear_Items.Click
LV1.Items.Clear()
End Sub
' Clear the Undo/Redo Stacks
Private Sub Button_Clear_Stacks_Click(sender As Object, e As EventArgs) _
Handles Button_Clear_Stacks.Click
_undoManager.Undostack = New Stack(Of ListView_Action)
_undoManager.Redostack = New Stack(Of ListView_Action)
Label_UndoCount_Value.Text = CStr(0)
Label_RedoCount_Value.Text = CStr(0)
End Sub
' Refreshes the Stacks Count
Private Sub Refresh_StackCount()
Label_UndoCount_Value.Text = CStr(_undoManager.Undostack.Count)
Label_RedoCount_Value.Text = CStr(_undoManager.Redostack.Count)
End Sub
' Monitors when an Item is added
Private Sub ListView_ItemAdded(sender As Object, e As LV.ItemAddedEventArgs) _
Handles LV1.ItemAdded
' // Crate an Undo Action
Dim u As New ListView_Action()
With u
.name = "Remove Item"
.Operation = New RemoveDelegate(AddressOf LV1.RemoveItem)
.data = {e.Item}
End With
_undoManager.Undostack.Push(u)
Refresh_StackCount()
End Sub
' Monitors when a range of Items are added
Private Sub ListView_RangeItemAdded(sender As Object, e As LV.RangeItemAddedEventArgs) _
Handles LV1.RangeItemAdded
' // Crate an Undo Action
Dim u As New ListView_Action()
With u
.name = "Remove Item Range"
.Operation = New RemoveRangeDelegate(AddressOf LV1.RemoveItem_Range)
.data = e.Items
End With
_undoManager.Undostack.Push(u)
Refresh_StackCount()
End Sub
' Monitors when an Item is removed
Private Sub ListView_ItemRemoved(sender As Object, e As LV.ItemRemovedEventArgs) _
Handles LV1.ItemRemoved
' // Create a Redo Action
Dim r As New ListView_Action()
With r
.name = "Add Item"
.Operation = New AddDelegate(AddressOf LV1.AddItem)
.data = {e.Item}
End With
_undoManager.Redostack.Push(r)
Refresh_StackCount()
End Sub
' Monitors when a range of Items are removed
Private Sub ListView_RangeItemRemoved(sender As Object, e As LV.RangeItemRemovedEventArgs) _
Handles LV1.RangeItemRemoved
' // Create a Redo Action
Dim r As New ListView_Action()
With r
.name = "Add Item"
.Operation = New AddRangeDelegate(AddressOf LV1.AddItem_Range)
.data = e.Items
End With
_undoManager.Redostack.Push(r)
Refresh_StackCount()
End Sub
' Undo
Private Sub Button_Undo_Click(sender As Object, e As EventArgs) _
Handles Button_Undo.Click
_undoManager.UndoLastAction()
End Sub
' Redo
Private Sub Button_Redo_Click(sender As Object, e As EventArgs) _
Handles Button_Redo.Click
_undoManager.RedoLastAction()
End Sub
Private Sub Button_Remove_Range_Of_Items_Click(sender As Object, e As EventArgs) Handles Button_Remove_Range_Of_Items.Click
If LV1.Items.Count > 1 Then
Dim lvi1 As ListViewItem = LV1.Items(LV1.Items.Count - 1)
Dim lvi2 As ListViewItem = LV1.Items(LV1.Items.Count - 2)
LV1.RemoveItem_Range({lvi1, lvi2})
End If
End Sub
End Class
PS: Как я уже сказал, действительно было бы гораздо удобнее скачать исходный код и протестировать его.