【问题标题】:Is there a way to catch when ContainsFocus changes?有没有办法捕捉 ContainsFocus 的变化?
【发布时间】:2008-12-05 21:18:11
【问题描述】:

我需要能够确定ContainsFocus 何时在Control(特别是Windows 窗体)上发生变化。覆盖OnGotFocus 不是答案。当我将表单带到前台时,ContainsFocus 为真,Focused 为假。那么OnGotFocus 是否与ContainsFocus 等效?还是其他方式?

【问题讨论】:

    标签: c# winforms events


    【解决方案1】:

    注意:如果您有子控件,则会触发子控件的 GotFocus 事件。否则调用表单的 OnGotFocus。

    如果我正确理解了这个问题,那么这应该有效:

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

    【讨论】:

    • 我知道这应该可行,但是当表单被带到前台时,甚至不会调用 OnGotFocus。因此,不会调用 CheckContainsFocus()。所以你留下了同样的问题。 :(
    • 如果您有子控件,则会触发子控件的 GotFocus 事件。否则调用表单的 OnGotFocus。只需检查是否调用了“private void OnContainsFocus()”。我做到了,它正在工作。
    • 我试过了,它奏效了。使用表单上的控件,从未调用过覆盖 OnGotFocus,但确实调用了 control_GotFocus。就是这样。谢谢。
    【解决方案2】:

    解决此问题的一种方法是使用计时器。这绝对是蛮力,但它可以完成工作:

    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;
    }
    

    但是有没有更简单的方法?

    【讨论】:

    • 等了 12 年才找到需要这个提示的人?我来了!
    【解决方案3】:

    应该处理 GotFocus 和 LostFocus 事件。

    还有一点需要注意...... SDK 对 ContainsFocus 属性的描述如下:

    您可以使用此属性来确定 无论是控制或任何 其中包含的控件具有 输入焦点。要确定是否 控制有焦点,不管 它的任何子控件是否有 焦点,使用 Focused 属性。

    编辑:

    在处理 GotFocus 事件时,您可能仍需要检查 Focused/ContainsFocus 属性,具体取决于控件层次结构的设置方式。

    如果控件或其任何子控件具有焦点,

    ContainsFocus 将为真。 仅当特定控件本身具有焦点时,焦点才会为真,无论其子控件如何。

    【讨论】:

    • 对不起,但就像我在问题中所说的那样,GotFocus 不适用于此。
    • @MikeHall 是对的。 GotFocus 不会在其子控件之一获得焦点的父对象上触发。所以,问题仍然是当父 ContainsFocus 发生变化时如何获取事件。不幸的是,这个问题的答案只适用于通过 Controls.Add 添加的控件,而不是如果孩子们自己添加了控件...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    • 2012-04-07
    相关资源
    最近更新 更多