1

アイテムを追加/削除するためだけに、ListView コントロールに元に戻す/やり直し操作を実装しようとすると、あまりにも多くの問題があります。

50、100、200、300 ポイント、合計 650 ポイントの複数のバウンティを開始したリストビューで、このクラスを元に戻す/やり直しに拡張するという相対的な質問がここにあることに気づきました...しかし、誰も本当に私を助けてくれませんでしたこの問題を数週間から数か月で仕上げます。

しかし、その質問で最終的にユーザー(@ThorstenC)が可能な解決策と素晴らしいアイデアを示してくれました。彼のコードは不完全であるため、彼のコードは私が実現/終了しようとしているものです。

問題は単純な「元に戻す」が正常に機能することですが、1回以上やり直そうとすると、リストビューに同じアイテムを再度追加できないという例外がスローされます。たとえば、現時点ではコードにさらに問題があります。元に戻す操作をやり直すことも、やり直し操作を元に戻すこともできません。

リストビュー項目の追加/削除用に元に戻す/やり直しマネージャーを機能させるために助けが必要です。それだけです。コードの半分を書きました。それを完了するには助けが必要です。これで頭が混乱しています。

これは、元に戻すマネージャーが失敗することをテストするためにアップロードした VS2012 の単純な WinForms ソース プロジェクトです。

http://elektrostudios.tk/UndoManager.zip

ここに画像の説明を入力

これは、元に戻す/やり直すときに発生するエラーを示すビデオです: http://www.youtube.com/watch?v=MAzChURATpM

これは、少しレタッチした @ThorstenC の UndoManager クラスです。

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

リストビュー項目の追加/削除を元に戻す/やり直すコードの残りの部分は次のとおりです。

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
4

2 に答える 2

1

また、VB.NET で書かれた Undo/Redo Framework もチェックしてみてください。

http://www.codeproject.com/Articles/43436/Undo-Redo-Framework

次のタイプのコントロール用に設計されています (ただし、ほとんどの場合、カスタム コントロールでも動作するはずです)。

  • テキストボックス
  • コンボボックス
  • 日時ピッカー
  • NumericUpDown
  • MaskedTextBox
  • ListBox (単一および複数選択)
  • チェックボックス
  • ラジオボタン
  • 月カレンダー
  • ListView (ラベル テキストの変更)
于 2014-05-17T10:43:05.957 に答える