Mike Hall
Mike Hall

Reputation: 1151

Is there a way to catch when ContainsFocus changes?

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?

Upvotes: 0

Views: 2008

Answers (3)

Eren Aygunes
Eren Aygunes

Reputation: 997

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...");
    }

Upvotes: 2

Daniel Schaffer
Daniel Schaffer

Reputation: 57822

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.

Upvotes: 0

Mike Hall
Mike Hall

Reputation: 1151

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?

Upvotes: 1

Related Questions