views:

316

answers:

3

I need to be able to determine when ContainsFocus changes on a Control (specifically a windows form). Overriding OnGotFocus is not the answer. When I bring the form to the foreground, ContainsFocus is true and Focused is false. So is there an OnGotFocus equivalent for ContainsFocus? Or any other way?

A: 

One way to solve this is to use a Timer. It's definitely brute force, but it gets the job done:

private Timer m_checkContainsFocusTimer = new Timer();
private bool m_containsFocus = true;

m_checkContainsFocusTimer.Interval = 1000; // every second is good enough
m_checkContainsFocusTimer.Tick += new EventHandler(CheckContainsFocusTimer_Tick);
m_checkContainsFocusTimer.Start();

private void CheckContainsFocusTimer_Tick(object sender, EventArgs e)
{
    if (!m_containsFocus && ContainsFocus)
        OnAppGotFocus();

    m_containsFocus = ContainsFocus;
}

But is there an easier way?

Mike Hall
A: 

Handling the GotFocus and LostFocus events should do it.

Another thing to note... the SDK says this about the ContainsFocus property:

You can use this property to determine whether a control or any of the controls contained within it has the input focus. To determine whether the control has focus, regardless of whether any of its child controls have focus, use the Focused property.

EDIT:

When handling the GotFocus event, you may still have to check the Focused/ContainsFocus property depending on how the hierarchy of your controls is set up.

ContainsFocus will be true if the control or any of its children have focus. Focus will only be true if the specific control itself has focus, regardless of its children.

Daniel Schaffer
Sorry, but like I stated in the question, GotFocus doesn't work for this.
Mike Hall
+1  A: 

Note: GotFocus events of the child controls are fired if you have a child control. Otherwise OnGotFocus of the form is called.

If I understood the question correctly, then this should work:

    bool lastNotificationWasGotFocus = false;

    protected override void OnControlAdded(ControlEventArgs e)
    {
        SubscribeEvents(e.Control);
        base.OnControlAdded(e);
    }

    protected override void OnControlRemoved(ControlEventArgs e)
    {
        UnsubscribeEvents(e.Control);
        base.OnControlRemoved(e);
    }

    private void SubscribeEvents(Control control)
    {
        control.GotFocus += new EventHandler(control_GotFocus);
        control.LostFocus += new EventHandler(control_LostFocus);
        control.ControlAdded += new ControlEventHandler(control_ControlAdded);
        control.ControlRemoved += new ControlEventHandler(control_ControlRemoved);

        foreach (Control innerControl in control.Controls)
        {
            SubscribeEvents(innerControl);
        }
    }

    private void UnsubscribeEvents(Control control)
    {
        control.GotFocus -= new EventHandler(control_GotFocus);
        control.LostFocus -= new EventHandler(control_LostFocus);
        control.ControlAdded -= new ControlEventHandler(control_ControlAdded);
        control.ControlRemoved -= new ControlEventHandler(control_ControlRemoved);

        foreach (Control innerControl in control.Controls)
        {
            UnsubscribeEvents(innerControl);
        }
    }

    private void control_ControlAdded(object sender, ControlEventArgs e)
    {
        SubscribeEvents(e.Control);
    }

    private void control_ControlRemoved(object sender, ControlEventArgs e)
    {
        UnsubscribeEvents(e.Control);
    }

    protected override void OnGotFocus(EventArgs e)
    {
        CheckContainsFocus();
        base.OnGotFocus(e);
    }

    protected override void OnLostFocus(EventArgs e)
    {
        CheckLostFocus();
        base.OnLostFocus(e);
    }

    private void control_GotFocus(object sender, EventArgs e)
    {
        CheckContainsFocus();
    }

    private void control_LostFocus(object sender, EventArgs e)
    {
        CheckLostFocus();
    }

    private void CheckContainsFocus()
    {
        if (lastNotificationWasGotFocus == false)
        {
            lastNotificationWasGotFocus = true;
            OnContainsFocus();
        }
    }

    private void CheckLostFocus()
    {
        if (ContainsFocus == false)
        {
            lastNotificationWasGotFocus = false;
            OnLostFocus();
        }
    }

    private void OnContainsFocus()
    {
        Console.WriteLine("I have the power of focus!");
    }

    private void OnLostFocus()
    {
        Console.WriteLine("I lost my power...");
    }
Eren Aygunes
I know that that should work, but OnGotFocus doesn't even get called when the form is brought to the foreground. Hence, CheckContainsFocus() won't get called. So you're left with the same problem. :(
Mike Hall
GotFocus events of the child controls is fired if you have a child control. Otherwise OnGotFocus of the form is called. Just check if "private void OnContainsFocus()" is called or not. I did, an it is working.
Eren Aygunes
I tried it and it worked. With controls on the form, the override OnGotFocus was never called, but the control_GotFocus was indeed getting called. So that was it. Thanks.
Mike Hall