Clearly I could manually code things in the OnLostFocus/OnLeave methods, or listen for LostFocus or Leave events on each of the controls, but that seemed like plenty of work and plenty ugly. (After all, I'm only interested when the user clicks on the button and the button's GetFocus / Enter events fire, so this functionality should belong to the button, right?)
The "Win32" event which the .Net framework is massaging into its own events does provide the control that's losing focus, apparently. And you can override the framework method, WndProc, that's way up the stack there somewhere.
Anyway, I'm working in vb.net at the moment so I've come up with something like what's below...
(I haven't necessarily worked out all the foibles, but it's certainly doing the basic job. I also haven't bothered synchronising access to the PreviousControl property - can't see when that's going to cause me an issue, but YMMV. BTW, Google tells me Microsoft Access had a PreviousControl property... hence the name.)
Public Class ButtonThatTracksPreviousFocus
Inherits Button
''' <summary>
''' This PreviousControl property holds the last control that was known to have focus before this button
''' received the focus. Note that where this button has the focus on an inactive window, when the parent
''' window activates the PreviousControl will end up being the last control to have focus on the
''' other form, it seems.
''' </summary>
''' <remarks></remarks>
Private _previousControl As Control
Public Property PreviousControl() As Control
Get
Return _previousControl
End Get
Set(ByVal value As Control)
_previousControl = value
End Set
End Property
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
' First check to see if this message is related to our gaining focus. If it is, make a note of the
' window / control that's losing it.
If m.Msg = 7 Then 'This is the WM_SETFOCUS message (which tells us in WParam the "window" that's losing focus)
Try
' We don't expect errors, but in the event that we get them we can simply assume we couldn't
' find the control and otherwise ignore.
If Not IntPtr.Zero.Equals(m.WParam) Then
Dim ctrl As Control = Control.FromHandle(m.WParam)
If Not ctrl Is Nothing AndAlso Not (ctrl.Equals(Me)) Then
' Store a reference to the "lost-focus" control. Note that this could actually be on
' another form so client-code may need to take account of this!
Me.PreviousControl = ctrl
End If
End If
Catch
Me.PreviousControl = Nothing
End Try
End If
'Regardless, normal message processing is carried out...
MyBase.WndProc(m)
End Sub
End Class
No comments:
Post a Comment