【入門編】Windows FormsにおけるUndo/Redo(元に戻す・やり直し)機能の実装:Commandパターンの適用で複雑な入力フォームの操作履歴を完璧に管理する – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

伝説のアーキテクトが教える:Windows Formsで「Undo/Redo」を極めるCommandパターンの真髄

こんにちは。VB.NETの世界へようこそ。

マクロの記録で「動いた!」と喜んでいたあの頃から、一歩先へ進みたいあなたへ。今日は、プロフェッショナルなアプリケーションの証とも言える「Undo(元に戻す)/ Redo(やり直し)」機能の実装術を伝授します。

多くの初心者は、Undoのために「すべての状態を巨大な配列に保存する」といった愚策に陥ります。しかし、メモリを食いつぶし、バグの温床になるだけです。真の解決策は「Commandパターン」にあります。

—

1. なぜ「Commandパターン」なのか?

Commandパターンとは、「操作そのものをオブジェクト(部品)として扱う」設計思想です。

例えば、「テキストボックスの文字を変えた」という操作を、単なるデータではなく、「実行(Execute)」と「逆実行(UnExecute)」というメソッドを持つ「命令書」としてパッケージ化するのです。

これにより、履歴管理は「命令書をスタック(積み重ね)という箱に入れるだけ」というシンプルな仕組みに変わります。

—

2. 「命令書」の設計図を作る(Interface)

まずは、すべての操作が守るべき「ルール」をインターフェースとして定義します。VB.NETで最も重要な設計の第一歩です。

‘ すべての操作(Undo/Redo対象)が実装すべき契約
Public Interface ICommand
Sub Execute() ‘ 操作を実行する
Sub UnExecute() ‘ 操作を逆回転させる
End Interface

—

3. 具体的な「命令」を実装する

例えば、「テキストボックスの値を変更する」という操作をクラス化してみましょう。

Public Class ChangeTextCommand
Implements ICommand

Private _target As TextBox
Private _oldValue As String
Private _newValue As String

Public Sub New(target As TextBox, newValue As String)
_target = target
_oldValue = target.Text
_newValue = newValue
End Sub

Public Sub Execute() Implements ICommand.Execute
_target.Text = _newValue
End Sub

Public Sub UnExecute() Implements ICommand.UnExecute
_target.Text = _oldValue
End Sub
End Class

—

4. 履歴を管理する「司令塔(CommandManager)」

履歴を保存する箱(Stack)を用意します。ここが脳の役割を果たします。

Public Class CommandManager
‘ 操作履歴をスタックで管理(後入れ先出し)
Private _undoStack As New Stack(Of ICommand)
Private _redoStack As New Stack(Of ICommand)

‘ 操作を実行して履歴に残す
Public Sub ExecuteCommand(cmd As ICommand)
cmd.Execute()
_undoStack.Push(cmd)
_redoStack.Clear() ‘ 新しい操作をしたらやり直し履歴は消すのがルール
End Sub

‘ Undo機能
Public Sub Undo()
If _undoStack.Count > 0 Then
Dim cmd = _undoStack.Pop()
cmd.UnExecute()
_redoStack.Push(cmd)
End If
End Sub
End Class

—

5. 実装で陥りやすい「罠」と解決策

初心者がこの実装でよくつまづくポイントを、現場の視点から教えます。

  • イベントの無限ループに注意!

`TextBox.TextChanged` イベントで `ExecuteCommand` を呼ぶと、Undo操作でテキストを書き換えた際にもイベントが発火し、無限ループに陥ります。
解決策: 操作中はフラグを立ててイベントを一時的に無効化する `Private isUndoing As Boolean = False` のようなガードを必ず入れてください。

  • メモリの肥大化

巨大なデータをUndo対象にするとメモリが枯渇します。オブジェクト全体を保持せず、「変更差分」だけを保持するように設計を絞りましょう。

—

6. まとめ:ここを越えれば、あなたはもう初心者ではない

このCommandパターンを習得すると、単なる入力フォームが、まるでプロ仕様のグラフィックソフトのような「洗練された挙動」を持つようになります。

今日のステップ:
1. `ICommand` インターフェースを書く。
2. 小さな操作(テキスト変更など)をクラスにする。
3. `Stack`を使って履歴を管理してみる。

最初は難しく感じるかもしれません。しかし、これこそがオブジェクト指向の醍醐味です。「状態」を管理するのではなく、「操作」を管理する。この発想の転換ができたとき、あなたのVB.NETスキルは一段上の領域へと進化します。

何か分からないことがあれば、いつでも聞いてください。焦らず、一歩ずつ。あなたのコードが、より美しくなることを応援しています。

タイトルとURLをコピーしました