ここで、この質問の 2 番目の部分について説明します。ListView項目の追加/削除のための Undo/Redo 操作の実装と、この他のExtend this Class to Undo/Redo in a Listviewです。
ListView アイテムの追加/削除の元に戻す/やり直し操作を実装しようとしています。
この LV UndoManager コードのコーディングをもう少し進めましたが、常に進めようとすると非常に困難です。
現時点では、単一のアイテムを追加してから、追加したアイテムを完全に元に戻す/やり直すことができます。
私が抱えている問題は次のとおりです。
· Listview から 1 つのアイテムを削除すると、LV に削除されたアイテムを再度追加するための「元に戻す」を実行できません。
・元に戻せないアイテムの場合に範囲を追加すると、それを呼び出すと例外UndoLastAction
がスローされますSystem.Reflection.TargetParameterCountException
·アイテムの範囲を削除すると、操作を元に戻す/やり直すことができず、同じ例外が発生します。
履歴書では、単一のアイテムを追加すると、完全に元に戻す/やり直すことができます。単一のアイテムを削除すると、正しく元に戻すことができず、ListViewItems の範囲を元に戻す/やり直すこともできません。
それらの問題を解決するのを手伝ってくれる人が必要です... または少なくともそのうちの1つを、忍耐強く。
コードが少し大きいので、アップロードしたソース プロジェクトを開いてテストする際に、理解してエラーを見つけるのに時間がかからないのではないかと思います。
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
最後に、Test アプリケーションの 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: 私が言ったように、ソースをダウンロードしてテストする方が実際には非常に友好的です。