web-dev-qa-db-ja.com

VBA:ユーザーフォームでWithEventsを使用する

さまざまなタイプの60以上のコントロールを備えたWordユーザーフォームがあります。 control_changeイベントがトリガーされるたびにフォームを評価し、フォームの送信ボタンの有効状態を変更したいと思います。ただし、変更イベントハンドラーで60を記述して維持したくはありません。

19
user51498

特定のタイプのすべてのコントロールのイベント処理コードを含むイベントシンククラスを作成できます。

たとえば、次のようにTextBoxEventHandlerというクラスを作成します。

Private WithEvents m_oTextBox as TextBox

Public Property Set TextBox(ByVal oTextBox as TextBox)
    Set m_oTextBox = oTextBox
End Property

Private Sub m_oTextBox_Change()
    ' Do something
End Sub

次に、フォーム上の適切なタイプのコントロールごとに、そのクラスのインスタンスを作成して接続する必要があります。

Private m_oCollectionOfEventHandlers As Collection

Private Sub UserForm_Initialise()

    Set m_oCollectionOfEventHandlers = New Collection

    Dim oControl As Control
    For Each oControl In Me.Controls

        If TypeName(oControl) = "TextBox" Then

            Dim oEventHandler As TextBoxEventHandler
            Set oEventHandler = New TextBoxEventHandler

            Set oEventHandler.TextBox = oControl

            m_oCollectionOfEventHandlers.Add oEventHandler

        End If

    Next oControl

End Sub

イベントハンドラインスタンスをコレクションに追加する必要がある理由は、それらが参照されたままになり、終了する前にガベージコレクタによって破棄されないようにするためです。

明らかに、この手法を拡張して、他のタイプの制御を処理することができます。タイプごとに個別のイベントハンドラークラスを使用することも、処理する必要のあるコントロールタイプごとにメンバー変数(および関連するプロパティとイベントハンドラー)を持つ単一のクラスを使用することもできます。

28
Gary McGill

その場合、イベントハンドラーはVBA/VB6で共有できないため、オプションはほとんどありません。

オプション1:すべてのイベントハンドラーから呼び出される中央処理関数を使用します。

Sub Control1_ChangeEvent()
  CommonChangeEvent // Just call the common handler, parameters as needed
End Sub

Sub Control2_ChangeEvent()
  CommonChangeEvent
End Sub
...
Sub CommonChangeEvent(/* Add necessary parameters */)
  //Do the heavy lifting here
End Sub

オプション2:コントロールをコントロール配列に整理します。

Sub TextBox_ChangeEvent(Index As Integer)
  CommonChangeEvent
End Sub

Sub OtherControlType_ChangeEvent(Index As Integer)
  CommonChangeEvent
End Sub

両方のオプションを組み合わせると、イベントハンドラーの総数が大幅に減少し、残りのハンドラーは1つの真のイベントハンドラーの頭の悪いスタブになります。

2
Daniel Rikowski