Resolved Overriding Control.LostFocus

pizzaboy

Well-known member
Joined
Jan 5, 2008
Messages
57
Programming Experience
1-3
I have a custom control, that shows a panel (similar to a combobox dropdown, or toolbar menu list) when it has focus.

When the control loses focus, it raises an event to close the panel (make it invisible).

The problem I'm having is that the panel has options to edit the custom control. How do I override the lostfocus, so that when focus is switched to either the custom control OR any controls in the panel I can ignor the Raiseevent.


I'm currently doing this:
VB.NET:
Custom control:
    Public Event ConfirmSelection()
    Private Sub txtText_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtText.LostFocus
        RaiseEvent ConfirmSelection()
    End Sub


The EventHandler for the panel:
    Private Sub ConfirmSelection() Handles InputBox.ConfirmSelection
        If Not (HaveFocus()) Then
                Me.Visible = False
        End If
    End Sub
    Private Function HaveFocus() As Boolean
        Dim result As Boolean = False
        For Each itm As Control In Me.Controls
            If itm.Focused Then
                result = True
                Exit For
            End If
        Next
        Return result
    End Function


When I click on something inside the panel, the custom control raises the txtText.LostFocus which is fine, I presume the problem is that the focus has not yet been passed to a new control, so the Me.Controls.Control.Focused is not set to anything.

Any suggestions on how to keep the panel open?


Any help would be greatly appreciated.

Thanks.
 
Last edited:
Nasty, nasty, nasty!!!

Turns out that "For Each itm As Control In Me.Controls" was not sufficient as child controls contained in controls were not getting referenced...

Resolved the problem, but surely there must be a better way of handling this problem?


VB.NET:
Custom control:
    Public Event ConfirmSelection()
    Private Sub txtText_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtText.LostFocus
        RaiseEvent ConfirmSelection()
    End Sub


The EventHandler for the panel:
    Private Sub ConfirmSelection() Handles InputBox.ConfirmSelection
        If Not (HaveFocus(Me)) Then
                Me.Visible = False
        End If
    End Sub


Check to see if Focus has been passed into a control on the panel:
    Private Function HaveFocus(ByVal ctl As Control) As Boolean
        Dim result As Boolean = False
        If ctl.Focused Then
            result = True
        Else
            If ctl.HasChildren Then
                For Each itm As Control In ctl.Controls
                    If HaveFocus(itm) Then
                        result = True
                        Exit For
                    End If
                Next
            End If
        End If
        Return result
    End Function


In the Panel.Load() event, handle all the LostFocus() events for EVERY control on the panel!!!:
    Private Sub ctlDropDown_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        AddLostFocusHandler(Me)
    End Sub

    Private Sub AddLostFocusHandler(ByVal ctl As Control)
        For Each itm As Control In ctl.Controls
            AddHandler itm.LostFocus, AddressOf ConfirmSelection

            If itm.HasChildren Then AddLostFocusHandler(itm)
        Next
    End Sub
 
Control.ContainsFocus Property (System.Windows.Forms) this has same effect as your HaveFocus recursive method.
Overriding Control.LostFocus
What you're doing there is handling an event, not overriding. In control development it is better practice to override the corresponding OnSomething protected methods. Type 'Overrides' keyword and the list of overridable members present itself by intellisense.
Public Event ConfirmSelection()
To provide default sender/e parameters it should be:
VB.NET:
Public Event ConfirmedSelection [U]As EventHandler[/U]
I think the naming should be ConfirmingSelection or ConfirmedSelection perhaps.

Following common event pattern this should also be accompanied with a corresponding OnConfirmedSelection protected member:
VB.NET:
Protected Overridable Sub OnConfirmedSelection(ByVal e As EventArgs)        
    RaiseEvent ConfirmedSelection(Me, e)    
End Sub
internal calling:
VB.NET:
OnConfirmedSelection(EventArgs.Empty)
Design Guidelines for Developing Class Libraries
 
Back
Top