【入門編】Application.IsUndoingOrRedoingを活用した安全なイベント処理:Undo/Redo時の無限ループ回避 – Visio VBA解析バイブル

スポンサーリンク

こんにちは!Visio VBAの世界へようこそ。
マクロの記録ボタンを押してコードを眺めるだけの日々は、もう卒業です。ここからは、Visioのオブジェクトモデルを自在に操り、業務を完全に自動化する「プロの領域」へ踏み込んでいきましょう。

今回は、Visio VBAにおいて避けて通れない「イベント処理の罠」と、それを美しく回避する極意を伝授します。
ここをクリアすれば、あなたの書くマクロは「おもちゃ」から「堅牢な業務システム」へと劇的に進化します。しっかりついてきてくださいね!

1. なぜVisioのイベント処理は「暴走」するのか?

Visio VBAでは、図形が動かされたり、ページが追加されたりした瞬間にコードを走らせる「イベントハンドラー」という強力な機能があります。

例えば、「ユーザーが図形を動かしたら、自動的にログを記録する」「特定のシェイプのテキストが変わったら、連動して別の処理をする」といった自動化です。

ここで、こんな状況を想像してください。

1. ユーザーが図形を移動した。
2. イベントが発火し、VBAコードが走って図形をさらに加工した。
3. ユーザーが「あ、今の移動ミスった!Ctrl + Z(元に戻す:Undo)しよう」と押した。
4. ここで大惨事が起きます。

Visioにとって「Undo(元に戻す)」や「Redo(やり直し)」も、内部的には「図形を別の位置に変更するイベント」として扱われます。
つまり、ユーザーがUndoした瞬間、VBAがそれを「新たな変更」と勘違いして再び割り込み、無限ループに突入。最終的にVisioごとフリーズ、あるいはクラッシュ……これが、開発者を絶望の淵に落とす「イベントの無限ループ地獄」です。

2. 救世主:`Application.IsUndoingOrRedoing` とは?

この恐怖の無限ループをスマートに防ぐために用意されているのが、Visioのアプリケーションオブジェクトが持つプロパティ、`IsUndoingOrRedoing` です。

> `Application.IsUndoingOrRedoing`
> 現在、ユーザーが「元に戻す(Undo)」または「やり直し(Redo)」の最中であるかどうかを `True` / `False` で返す読み取り専用のプロパティ。

仕組みはとてもシンプルです。
イベントが発生したときに、「今、ユーザーがUndoしてる最中じゃないよね?」とこのプロパティでガードをかけ、もし`True`(Undo中)であれば、VBAの独自処理を実行せずに即座に抜ける(Exit)ようにするのです。

これを知っているだけで、あなたの書くコードの安全性はプロ基準に達します。

3. 実践!安全なイベントハンドリングの実装コード

それでは、実際にこの仕組みを組み込んだ安全なイベント処理のコードを見てみましょう。
今回は、ドキュメントレベルのイベント(`DocumentEvent`)を監視し、図形が変更されたときに安全に処理を行うテンプレートをご紹介します。

ステップ1:クラスモジュールの作成(例:`clsEventSink`)

まずは、イベントを受け取るためのクラスモジュールを作成します。

‘ =================================================================
‘ クラスモジュール名: clsEventSink
‘ 概要: Visioのイベントを安全にキャッチするクラス
‘ =================================================================
Public WithEvents VisApp As Visio.Application

‘ 図形が変更されたときに走るイベント
Private Sub VisApp_ShapeChanged(ByVal Shape As IVShape)

‘ 【極意】今、Undo/Redoの最中なら、処理を一切行わずに即終了する!
If VisApp.IsUndoingOrRedoing Then
Exit Sub
End If

‘ — ここから下が、通常の変更時にのみ実行したい安全な処理 —
On Error GoTo ErrorHandler

‘ 例:変更された図形の名前を出力ウィンドウに表示する
Debug.Print “図形が変更されました: ” & Shape.Name

Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End Sub

ステップ2:標準モジュールでのイベント有効化

次に、標準モジュールから上記のクラスをアプリケーションにアタッチします。

‘ =================================================================
‘ 標準モジュール
‘ 概要: イベント監視の開始・停止を制御する
‘ =================================================================
Dim cEventSink As clsEventSink

Public Sub StartMonitoring()
‘ すでに監視中でなければ、イベントのフックを開始
If cEventSink Is Nothing Then
Set cEventSink = New clsEventSink
Set cEventSink.VisApp = Visio.Application
MsgBox “Visioの安全なイベント監視を開始しました。”, vbInformation
Else
MsgBox “すでに監視は稼働中です。”, vbExclamation
End If
End Sub

Public Sub StopMonitoring()
‘ 監視を終了
Set cEventSink = Nothing
MsgBox “イベント監視を停止しました。”, vbInformation
End Sub

4. プログラミング初学者への温かいアドバイス

最初は「クラスモジュール? `WithEvents`?」と難しく感じるかもしれません。でも、安心してください。ここをクリアすれば、あなたは単なる「マクロの記録者」ではなく、「Visioアプリケーションのアーキテクト」の仲間入りです。

実務でVisioの自動化ツールを納品するとき、ユーザーは必ず「うっかりCtrl+Zを押す」という想定外の操作をします。そのときにツールが耐えられるかどうかは、この `IsUndoingOrRedoing` を知っているかどうかにかかっています。

「あ、危ないところだった。先輩の教え通り、ここでしっかりガードしておこう」
そう思っていただければ、この記事を書いた甲斐があります。

ぜひ、あなたの開発するVisioツールにこの知見を取り入れて、堅牢で美しい自動化を実現してくださいね。応援しています!

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