Ele*_*ios 8 .net vb.net listview undo-redo winforms
我正在使用第三方代码来管理WindowsForm项目中的撤消/重做操作.
我需要扩展Class来管理Listview中的撤消/重做操作,这意味着:
·撤消/重做添加/删除项目和子项目
·撤消/重做检查/取消选中行
·撤消/重做其他一些我可能错过的重要事情
我不知道如何开始这样做,代码对我来说太复杂了,关于这个的任何帮助/提示/例子都会让我非常满意,但是在3个月内我无法进行这个改变,我我想我需要很好的解释或完整的例子,这里是代码:
********************************************************
Undo/Redo framework (c) Copyright 2009 Etienne Nijboer
********************************************************
Run Code Online (Sandbox Code Playgroud)
(我没有在这里发布代码,因为它超过了StackOverflow的30.000字符限制)
更新:
这是来自作者的一些有用的信息,解释了我需要做的事情来添加Listview支持,但实际上我不能自己:
为列表视图添加功能不应该是那么难,也是了解它如何工作的好方法.您需要创建一个新的监视器,它将捕获listview更改事件并在更改之前存储当前值.如果您检测到已撤消或重做操作所需的所有信息进行了更改,则会创建一个命令.而已.只要您的监视器和命令从基类继承,它就会被自动检测和使用.
http://www.codeproject.com/Articles/43436/Undo-Redo-Framework
更新:
该类的所有者更新了代码,添加了我需要的东西之一,我要求的标签项撤销/重做操作.
·Listview内的撤消/重做文本更改(正常模式或详细信息模式)
Unafortunatelly这个更新不足以让我能够添加我需要的其他撤消/重做操作,请阅读@Plutonix评论解释事物
以下是更新类的一部分,适用于可以提出想法并帮助扩展它的人:
'****************************************************************************************************************
' ListView Undo/Redo Example, (c) Copyright 2013 Etienne Nijboer
'****************************************************************************************************************
' This is an example implementation of the Monitor and Command to add support for listviewitem labeltext changes
' Only the two classes arre needed to add support for an additional control. There were no extra changes needed
' in other code because the UndoRedoManager class uses reflection to discover the new Monitor and if you check
' the message box on startup you'll notice the new addition of the ListViewMonitor to the list.
'
' Hopefully this example makes it easier for others to understand the mechanism behind this and how to add
' undo/redo functionality for other actions and controls.
'
' Note: Beware that this example doesn't work if items in the listview can be sorted, moved and/or deleted. You
' would need to expand the Monitor for these actions and add Command classes as well. Hopefully this
' addition to will make it easier for you to do just that ;-)
'
' Good luck!
'
'****************************************************************************************************************
' Because we want to perform undo on a specific item at a certain index within the listview it is important this
' index is also stored. Otherwise we know that a label is changed but not to which item it belongs
Structure ListViewUndoRedoData
Public ItemIndex As Integer
Public LabelText As String
End Structure
'****************************************************************************************************************
' ListViewMonitor
'****************************************************************************************************************
Public Class ListViewMonitor : Inherits BaseUndoRedoMonitor
Private Data As ListViewUndoRedoData
Public Sub New(ByVal AUndoRedoManager As UndoRedoManager)
MyBase.New(AUndoRedoManager)
End Sub
Public Overrides Function Monitor(ByVal AControl As System.Windows.Forms.Control) As Boolean
If TypeOf AControl Is ListView Then
AddHandler CType(AControl, ListView).BeforeLabelEdit, AddressOf ListView_BeforeLabelEdit
AddHandler CType(AControl, ListView).AfterLabelEdit, AddressOf ListView_AfterLabelEdit
Return True
End If
Return False
End Function
Private Sub ListView_BeforeLabelEdit(sender As System.Object, e As System.Windows.Forms.LabelEditEventArgs)
' Before change, make sure to save the data of what it is you want to be able to undo later.
Data.ItemIndex = e.Item
Data.LabelText = CType(sender, ListView).Items(e.Item).Text
End Sub
Private Sub ListView_AfterLabelEdit(sender As System.Object, e As System.Windows.Forms.LabelEditEventArgs)
' Events that are also fired when the undo/redo value is changed by code, like change events,
' it is important to make sure that no undo/redo command is added when performing a undo/redo action.
If Not isPerformingUndoRedo Then
If Not (Data.ItemIndex = e.Item And String.Equals(Data.LabelText, e.Label)) Then
AddCommand(UndoRedoCommandType.ctUndo, New ListViewUndoRedoCommand(Me, sender, Data))
ListView_BeforeLabelEdit(sender, e)
End If
End If
End Sub
End Class
'****************************************************************************************************************
' ListViewUndoRedoCommand
'****************************************************************************************************************
Public Class ListViewUndoRedoCommand : Inherits BaseUndoRedoCommand
Public Sub New(ByVal AUndoMonitor As BaseUndoRedoMonitor, ByVal AMonitorControl As Control)
MyBase.New(AUndoMonitor, AMonitorControl)
Debug.Assert(False, "This constructor cannot be used because creating the current state of the control should be done at the actual undo or redo action!")
End Sub
Public Sub New(ByVal AUndoMonitor As BaseUndoRedoMonitor, ByVal AMonitorControl As Control, ByVal AUndoRedoData As Object)
MyBase.New(AUndoMonitor, AMonitorControl, AUndoRedoData)
End Sub
Public ReadOnly Property Control() As ListView
Get
Return CType(UndoRedoControl, ListView)
End Get
End Property
Private ReadOnly Property Data() As ListViewUndoRedoData
Get
Return CType(UndoRedoData, ListViewUndoRedoData)
End Get
End Property
Private Function GetCurrentStateData() As ListViewUndoRedoData
GetCurrentStateData.ItemIndex = Data.ItemIndex
GetCurrentStateData.LabelText = Control.Items(Data.ItemIndex).Text
End Function
Public Overrides Sub Undo()
MyBase.Undo(GetCurrentStateData())
Control.Items(Data.ItemIndex).Text = Data.LabelText
End Sub
Public Overrides Sub Redo()
MyBase.Redo(GetCurrentStateData())
Control.Items(Data.ItemIndex).Text = Data.LabelText
End Sub
Public Overrides Function CommandAsText() As String
Return String.Format("Item {0}: {1}", Data.ItemIndex, Data.LabelText)
End Function
End Class
Run Code Online (Sandbox Code Playgroud)
更新2:
这就是作者所说的如何添加listview undo/redo操作所需的功能:
我认为你不需要重写全班.最难的部分是找到一种方法来检测项目何时可能被删除以及何时被删除.在ListViewMonitor中,您需要添加必要的事件处理程序(在您找到AddHandler for BeforeLabelEdit和AfterLabelEdit的源代码中).对于Command类,您需要在删除之前将实际的ListViewItem和项目在ListView中的位置放在一起.您可以使用此信息创建结构,例如ListViewItemRemoveUndoRedoData.撤消删除时,只需将存储的ListViewItem添加到ListView中与您一起存储的位置即可.我建议在ListViewItemRemoveUndoRedoData结构中添加一个额外的Count,它保存listview中的项目数.此外,我认为您需要的唯一事件是SelectedIndexChanged.发生此事件时,有两种情况.
1-项目数与先前存储的计数相同(在创建监视器时将其设置为-1):存储项目,位置和项目总计数.
2-项目数小于先前存储的计数:删除项目并设置其UndoRedoCommand以便撤消.
- 当然有第3个选项,这意味着添加了一个项目
它需要一些创造力来找到正确的事件以及需要存储什么来执行撤消/重做.它甚至可能意味着您需要找到具有更好事件和支持的替代列表视图(您可以在codeproject上找到)
更新3:
试图遵循@ThorstenC解决方案,我遇到了RedoLastAction的问题,即使我没有撤消任何内容,它也会重做.
我也可以重做无限次,它只重做最后一个动作,我的意思是如果我撤消3个不同的LV项目,那么我只能重做最后添加的项目.
·UndoManager类:
Class ListView_UndoManager
Public Property Undostack As New Stack(Of ListView_Action)
Public Property Redostack As New Stack(Of ListView_Action)
Private action As ListView_Action = Nothing
''' <summary>
''' Undo the top of the stack
''' </summary>
''' <remarks></remarks>
Sub UndoLastAction()
If Undostack.Count = 0 Then Exit Sub ' Nothing to Undo.
action = Undostack.Pop ' Get the Action from Stack.
action.Operation.DynamicInvoke(action.data) ' Invoke the reverse Action .
End Sub
''' <summary>
''' Redo the top of the stack
''' </summary>
''' <remarks></remarks>
Sub RedoLastAction()
If Redostack.Count = 0 Then Exit Sub ' Nothing to Redo.
action = Redostack.Peek ' Get the Action from Stack, but don't remove it.
action.Operation.DynamicInvoke(action.data) ' Invoke the reverse 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 Object()
End Class
Run Code Online (Sandbox Code Playgroud)
·主要表格代码:
' Undo/Redo
Dim _undoManager As New ListView_UndoManager
Delegate Sub RemoveDelegate(item As Object)
Delegate Sub AddDelegate(text As String, subtext1 As String, subtext2 As String)
' Button Add Song [Click]
Private Sub Button_Add_Song_Click(sender As Object, e As EventArgs) _
Handles Button_Add_Song.Click
AddItem(ListView_Monitor.Items.Count + 1, WinampFile, ComboBox_Sendto.Text)
End Sub
Sub AddItem(ByVal name As String, ByVal subitem1 As String, ByVal subitem2 As String)
Dim newItem = ListView_Monitor.Items.Add(name)
newItem.SubItems.Add(subitem1)
newItem.SubItems.Add(subitem2)
'Crate an Undo Operation
Dim u As New ListView_Action() With {.name = "Remove Item",
.Operation = New RemoveDelegate(AddressOf RemoveItem),
.data = New Object() {newItem}}
_undoManager.Undostack.Push(u)
' Create a Redo
Dim r As New ListView_Action() With {.name = "Add Item",
.Operation = New AddDelegate(AddressOf AddItem),
.data = New Object() {name, subitem1, subitem2}}
_undoManager.Redostack.Push(r)
End Sub
Sub RemoveItem(item As Object)
ListView_Monitor.Items.Remove(item)
End Sub
Run Code Online (Sandbox Code Playgroud)
尝试这种方法:忘记当前的实现,开始实现您自己的撤消/重做类。
每个操作某些内容的方法都需要创建自己的撤消方法。存储委托并在需要时调用它。我制作了一个简单的添加/删除列表视图项目的示例。
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
782 次 |
| 最近记录: |