我已经完成了这个用户控件,并在某些人的帮助下集成了 UndoRedo Manager 。
目前它只能在你添加或删除项目时撤消/重做,而这就是全部,但我想实现LabelEdit undo / redo和checkbox undo / redo。
PS:请注意,Listview_Action
需要ListviewItem
这是Undo / Redo管理器Class,不是完整的代码,只是必要的。
我需要在此类中执行哪些更改才能添加我需要的改进?
如果有人可以向我展示一个完整的代码示例,我将不胜感激。
Public Class myListView : Inherits ListView
Public Event ItemAdded As EventHandler(Of ItemAddedEventArgs)
Public Class ItemAddedEventArgs : Inherits EventArgs
Property Item As ListViewItem
End Class
Public Event ItemRemoved As EventHandler(Of ItemRemovedEventArgs)
Public Class ItemRemovedEventArgs : Inherits EventArgs
Property Item As ListViewItem
End Class
#Region " Undo/Redo Manager "
''' <summary>
''' Enable or disble the Undo/Redo monitoring.
''' </summary>
Public Property Enable_UndoRedo_Manager As Boolean = False
' Stacks to store Undo/Redo actions.
Private Property Undostack As New Stack(Of ListView_Action)
Private Property Redostack As New Stack(Of ListView_Action)
' Flags to check if it is doing a Undo/Redo operation.
Private IsDoingUndo As Boolean = False
Private IsDoingRedo As Boolean = False
' Delegate to Add an Item for Undo/Redo operations.
Private Delegate Sub AddDelegate(item As ListViewItem)
' Delegate to Remove an Item for Undo/Redo operations.
Private Delegate Sub RemoveDelegate(item As ListViewItem)
' The Undo/Redo action.
Private action As ListView_Action = Nothing
' The operation.
Public Enum Operation As Short
Undo = 0
Redo = 1
End Enum
' The method for the Undo/Redo operation.
Public Enum Method As Short
Add = 0
Remove = 1
End Enum
''' <summary>
''' Creates a Undo/Redo Action.
''' </summary>
Class ListView_Action
''' <summary>
''' Names the Undo/Redo Action.
''' </summary>
Property Name As String
''' <summary>
''' Points to a method to excecute.
''' </summary>
Property Operation As [Delegate]
''' <summary>
''' Method of the Undo/Redo operation.
''' </summary>
Property Method As Method
''' <summary>
''' Data Array for the method to excecute.
''' </summary>
Property Data As ListViewItem
End Class
''' <summary>
''' This event is raised after an Undo/Redo action is performed.
''' </summary>
Public Event UndoRedo_IsPerformed As EventHandler(Of UndoneRedoneEventArgs)
Public Class UndoneRedoneEventArgs : Inherits EventArgs
Property Operation As Operation
Property Method As Method
Property Item As ListViewItem
Property UndoStack As Stack(Of ListView_Action)
Property RedoStack As Stack(Of ListView_Action)
End Class
''' <summary>
''' This event is raised when Undo/Redo Stack size changed.
''' </summary>
Public Event UndoRedo_StackSizeChanged As EventHandler(Of StackSizeChangedEventArgs)
Public Class StackSizeChangedEventArgs : Inherits EventArgs
Property UndoStack As Stack(Of ListView_Action)
Property RedoStack As Stack(Of ListView_Action)
Property UndoStackIsEmpty As Boolean
Property RedoStackIsEmpty As Boolean
End Class
''' <summary>
''' Undo the last action.
''' </summary>
Public Sub Undo()
If Me.Undostack.Count = 0 Then Exit Sub ' Nothing to Undo.
Me.IsDoingUndo = True
Me.action = Me.Undostack.Pop ' Get the Action from the Stack and remove it.
Me.action.Operation.DynamicInvoke(Me.action.Data) ' Invoke the undo Action.
Me.IsDoingUndo = False
Raise_UndoRedo_IsPerformed(Operation.Undo, Me.action.Method, Me.action.Data)
End Sub
''' <summary>
''' Redo the last action.
''' </summary>
Public Sub Redo()
If Me.Redostack.Count = 0 Then Exit Sub ' Nothing to Redo.
Me.IsDoingRedo = True
Me.action = Me.Redostack.Pop() ' Get the Action from the Stack and remove it.
Me.action.Operation.DynamicInvoke(Me.action.Data) ' Invoke the redo Action.
Me.IsDoingRedo = False
Raise_UndoRedo_IsPerformed(Operation.Redo, Me.action.Method, Me.action.Data)
End Sub
' Reverses an Undo/Redo action
Private Function GetReverseAction(ByVal e As UndoneRedoneEventArgs) As ListView_Action
Me.action = New ListView_Action
Me.action.Name = e.Item.Text
Me.action.Data = e.Item
Me.action.Operation = If(e.Method = Method.Add, _
New RemoveDelegate(AddressOf Me.RemoveItem), _
New AddDelegate(AddressOf Me.AddItem))
Me.action.Method = If(e.Method = Method.Add, _
Method.Remove, _
Method.Add)
Return Me.action
End Function
' Raises the "UndoRedo_IsPerformed" Event
Private Sub Raise_UndoRedo_IsPerformed(ByVal Operation As Operation, _
ByVal Method As Method, _
ByVal Item As ListViewItem)
RaiseEvent UndoRedo_IsPerformed(Me, New UndoneRedoneEventArgs _
With {.Item = Item, _
.Method = Method, _
.Operation = Operation, _
.UndoStack = Me.Undostack, _
.RedoStack = Me.Redostack})
Raise_UndoRedo_StackSizeChanged()
End Sub
' Raises the "UndoRedo_StackSizeChanged" Event
Private Sub Raise_UndoRedo_StackSizeChanged()
RaiseEvent UndoRedo_StackSizeChanged(Me, New StackSizeChangedEventArgs _
With {.UndoStack = Me.Undostack, _
.RedoStack = Me.Redostack, _
.UndoStackIsEmpty = Me.Undostack.Count = 0, _
.RedoStackIsEmpty = Me.Redostack.Count = 0})
End Sub
' This handles when an Undo or Redo operation is performed.
Private Sub UndoneRedone(ByVal sender As Object, ByVal e As UndoneRedoneEventArgs) _
Handles Me.UndoRedo_IsPerformed
Select Case e.Operation
Case Operation.Undo
' Create a Redo Action for the undone action.
Me.Redostack.Push(GetReverseAction(e))
Case Operation.Redo
' Create a Undo Action for the redone action.
Me.Undostack.Push(GetReverseAction(e))
End Select
End Sub
' Monitors when an Item is added to create an Undo Operation.
Private Sub OnItemAdded(sender As Object, e As ItemAddedEventArgs) _
Handles Me.ItemAdded
If Me.Enable_UndoRedo_Manager _
AndAlso (Not Me.IsDoingUndo And Not Me.IsDoingRedo) Then
Me.Redostack.Clear()
' // Crate an Undo Action
Me.action = New ListView_Action
Me.action.Name = e.Item.Text
Me.action.Operation = New RemoveDelegate(AddressOf Me.RemoveItem)
Me.action.Data = e.Item
Me.action.Method = Method.Remove
Me.Undostack.Push(action)
Raise_UndoRedo_StackSizeChanged()
End If
End Sub
' Monitors when an Item is removed to create an Undo Operation.
Private Sub OnItemRemoved(sender As Object, e As ItemRemovedEventArgs) _
Handles Me.ItemRemoved
If Me.Enable_UndoRedo_Manager _
AndAlso (Not Me.IsDoingUndo And Not Me.IsDoingRedo) Then
Me.Redostack.Clear()
' // Crate an Undo Action
Me.action = New ListView_Action
Me.action.Name = e.Item.Text
Me.action.Operation = New AddDelegate(AddressOf Me.AddItem)
Me.action.Data = e.Item
Me.action.Method = Method.Add
Me.Undostack.Push(action)
Raise_UndoRedo_StackSizeChanged()
End If
End Sub
#End Region
End Class
答案 0 :(得分:1)
首先,因为您从派生类开始,所以将这些事件添加到它:
' (your Item events still lack a Sender and Item to save a lot of work)
Public Event CheckChanged(ByVal sender As Object, _
ByVal lice As ListItemCheckChangedArgs)
Public Shadows Event BeforeLabelEdit(ByVal sender As Object, _
ByVal oldText As String)
需要BeforeLabelEdit,因为基本LV在开始时将旧标签文本存储为Nothing
,您需要将其更改为.Text属性以实际检测更改。接下来,观察文本更改将要求您执行与ItemAdded不同的操作(无论是通用还是内部)。
当Before...
触发时,存储副本......观察者会将_BeforeText与_AfterText(观察正常的AfterLabelEdit事件)进行比较,如果它们不同,则将_BEforeText推入堆栈。
CheckChanged
有点作弊。您可以直接单击LVItem Check,而不会触发任何类型的Enter / GotFocus等事件。这意味着观察者无法获得_BeforeChecked
值。原生的LV ItemChecked确实触发了,我只是重新组织它的args,将我需要的东西传递给Watcher(通过上面的事件)。虱子:
Public Class ListItemCheckChangedArgs
Public Index As Integer ' index of item checked
Public OldValue As CheckState
Public NewValue As CheckState
Public Sub New(ByVal ndx As Integer, ByVal ov As CheckState, _
ByVal nv As CheckState)
Index = ndx
OldValue = ov
NewValue = nv
End Sub
End Class
观察者然后使用OldValue作为数据创建一个UnDoAction对象。即使没有观察者,这也有助于捕捉您的需求。
重要的部分是Undo类(内部UM会有所不同):
Public Class ListViewEUndo
'... WHO this action applies to
Friend Ctl As ListViewEX
' a listview item, or string (Text) or bool (Check)
Friend UnDoData As Object
Friend LVActionType As LVEActionType = LVEActionType.None
' original index of items removed / index of item checked
Friend Index As Integer = -1
Public Sub New(ByVal _ctl As ListViewEX, ByVal _LvAType As LVEActionType, _
ByVal _data As Object)
Ctl = _ctl
LVActionType = _LvAType
UnDoData = _data
End Sub
...
LVEActionType
只是AddItem,RemoveItem等(这个动作类型是什么)
你可以设计一个基类,然后为TextUndo,CheckUndo和ItemUndo继承它。抛出这个或由此产生的短SELECT CASE语句是否更好。最后,没有DELEGATES,因为UndoManager类/帮助程序将自己应用更改而不是将工作导出到from或control(这也有助于避免推动由撤消/重做操作引起的操作!)。
我不确定它是full code example
,但可能会对你的问题有所帮助,具体取决于它是否是内部的(内部几乎不需要任何事件 - 主要需要触发Watcher操作 - 在值之前捕获,捕获/比较后值,响应Add / RemoveItem等)。