フォームの ActiveControl が変わった (フォーム上のコントロール 1 のフォーカスがコントロール 2 に移動した) ときにフォーム側で発生するイベントがあったらどなたか教えていただけますでしょうか。
表題の発端はここなのですが、途中から「ActiveControl が変わった時のイベント」でなくても事足りるという流れになってしまいましたので、こちらに展開します。向こうのスレッドだけですと、ただのイヤな感じの人にしか見えないですしw
まず、最初に挙げた System.Windows.Forms.UpdateDefaultButton というインフラ用のメソッドをオーバーライドする方法です。C# だとわからないと仰る方が多いので VB で書きます。
VB.NET - UpdateDefaultButton メソッドを使った方法
'/** MasterForm クラス */
Public Class MasterForm : Inherits System.Windows.Forms.Form
Public Event ActiveControlChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Protected Overrides Sub UpDateDefaultButton()
MyBase.UpdateDefaultButton()
RaiseEvent ActiveControlChanged(Me, New System.EventArgs())
End Sub
End Class
単純には上記のような実装になります。しかし、コンテナ内にある子コントロールの場合、複数回イベントが発生してしまいます。よってこのままでは利用できません。(おそらく) このあたりを考慮した小細工を施すくらいなら、最初から真っ当な方法を選んだ方が楽だったりします。
ということで、次に burton999 さんが挙げられた方法に似た方法を挙げます。これは、後でコントロールが追加・削除されても追撃できるようになるであろうという方法です。利用しやすくなるように、イベント引数も独自の型を使うようにしてみましょう。
VB.NET - ActiveControlChangedEventArgs クラス
'/** ActiveControlChanged イベント引数 クラス */
Public Class ActiveControlChangedEventArgs : Inherits System.EventArgs
' コンストラクタ
Public Sub New(ByVal activeControl As System.Windows.Forms.Control, ByVal beforeActiveControl As System.Windows.Forms.Control)
Me._ActiveControl = activeControl
Me._BeforeActiveControl = beforeActiveControl
End Sub
' ActiveControl プロパティ (ReadOnly)
Private _ActiveControl As System.Windows.Forms.Control
Public ReadOnly Property ActiveControl As System.Windows.Forms.Control
Get
Return Me._ActiveControl
End Get
End Property
' ActiveControl プロパティ (ReadOnly)
Private _BeforeActiveControl As System.Windows.Forms.Control
Public ReadOnly Property BeforeActiveControl As System.Windows.Forms.Control
Get
Return Me._BeforeActiveControl
End Get
End Property
End Class
これが、ActiveControlChanged イベント専用のイベント引数 (ActiveControlChangedEventArgs クラス) です。命名は MSDN ライブラリの名前付けのガイドラインに倣いました。このクラスでは、現在の ActiveControl と 1 つ前の ActiveControl の参照を取得できることを想定しています。
VB.NET - ActiveControlChanged イベントの実装
'/** MasterForm クラス */
Public Class MasterForm : Inherits System.Windows.Forms.Form
Public Event ActiveControlChanged(ByVal sender As Object, ByVal e As ActiveControlChangedEventArgs)
Private beforeActiveControl As System.Windows.Forms.Control
Private Sub ChildControls_Enter(ByVal sender As Object, ByVal e As System.EventArgs)
If sender Is Nothing Then
Return
End If
If Not TypeOf sender Is System.Windows.Forms.Control Then
Return
End If
Dim cControl As System.Windows.Forms.Control = DirectCast(sender, System.Windows.Forms.Control)
If Not Me.beforeActiveControl Is sender Then
RaiseEvent ActiveControlChanged(sender, New ActiveControlChangedEventArgs(cControl, Me.beforeActiveControl))
Me.beforeActiveControl = cControl
End If
End Sub
Private Sub ChildControls_ControlAdded(ByVal sender As Object, ByVal e As System.Windows.Forms.ControlEventArgs) Handles Me.ControlAdded
If e Is Nothing Then
Return
End If
If e.Control Is Nothing Then
Return
End If
AddHandler e.Control.ControlAdded, AddressOf ChildControls_ControlAdded
AddHandler e.Control.ControlRemoved, AddressOf ChildControls_ControlRemoved
AddHandler e.Control.Enter, AddressOf ChildControls_Enter
End Sub
Private Sub ChildControls_ControlRemoved(ByVal sender As Object, ByVal e As System.Windows.Forms.ControlEventArgs) Handles Me.ControlRemoved
If e Is Nothing Then
Return
End If
If e.Control Is Nothing Then
Return
End If
RemoveHandler e.Control.ControlAdded, AddressOf ChildControls_ControlAdded
RemoveHandler e.Control.ControlRemoved, AddressOf ChildControls_ControlRemoved
RemoveHandler e.Control.Enter, AddressOf ChildControls_Enter
End Sub
End Class
For Each ステートメントで手動で列挙するのはやめて、コンテナにコントロールが追加された時のイベントで管理します。この方法であれば、初期表示からコントロールが変更されても追撃可能ですから一挙両得になるでしょう。たぶん。
ベタ書きですので間違いがあるかもしれません。検証くらいしてから投稿したかったのですが、検証できる環境が手元にないものでして... ところで、こんなものが欲しくなる場面ってあるのでしょうか?