【问题标题】:Setting focus when control's top level parent window is the active window?当控件的顶级父窗口是活动窗口时设置焦点?
【发布时间】:2018-05-03 22:07:34
【问题描述】:

我正在开发一个 C# 项目。问题是,当背景窗口不是活动窗口时,像 mouse-enter 这样的背景事件会使背景窗口突出显示为焦点。解决方案的策略是在设置此重点之前添加预防措施。

我的尝试包括以下策略:

在调用control.Focus() 之前,我想实现一个涉及GetActiveWindow() function 的条件,以匹配控件的顶级父级关联窗口句柄。对于后者,我使用Control.TopLevelControl()。但是,每次我这样做时,我都会为这个属性获得null。根据MSDN reference 的原因是该控件不是窗体上的父级。

尝试了 sn-p:

if (myControl.TopLevelControl.Handle == GetActiveWindow())
{
     this.myControl.Focus();
}

代码背景:此代码不归我所有。所以,请原谅我太抽象了。我会尽量详细说明。相关控件是一个私有成员自定义布局面板,它继承自 System.Windows.Forms.Panel,其中 DoubleBuffered 属性设置为 true。此控件已添加到继承自 UserControl(Windows 窗体)的内部部分类中。后一个控件已通过公共部分类(也继承自用户控件)上的私有成员 SplitContainer(Windows 窗体)添加。

在这个布局面板的用户控件的构造函数中,偶数被添加为:

myLayoutPanel.MouseEnter += this.myLayoutPanel_MouseEnter;

没有我改变的事件看起来像:

private void myLayoutPanel_MouseEnter(object sender, EventArgs e)
    {
        myLayoutPanel.SuspendLayout();
        myLayoutPanel.Focus();
        myLayoutPanel.ResumeLayout(false);
    }

此外,我手动查看了控件父层次结构的句柄,但始终无法匹配到活动窗口句柄。直观地说,我觉得GetActiveWindow() 使用互操作性深入研究非托管代码以获取句柄,而顶级属性保留在托管区域中,因此有其局限性。不过我可能错了。

有人对此有什么想法吗?

【问题讨论】:

  • events like mouse-enter make a background window pop out in focus when it is not the active window 这实际上不是正常行为。您是否在 MouseEnter 事件中运行了可以使表单成为焦点的代码?
  • 当您不告诉我们为什么您的用户控件未嵌入表单中时,您并没有完全帮助我们。猜测:当 myControl.IsHandleCreated 为 false 时不要做任何事情。
  • 你确定你的窗口(窗体)是真的活跃吗?窗口/表单可以在顶部(即使不是最顶部)并且处于非活动状态。
  • 在winforms(和Win32 UI)中是动态添加的。这不是问题。问题是,您的表单没有焦点。问题将在其他地方。我认为这将是“鼠标输入”区域中的内容。尝试详细说明这部分,我们可能会有所帮助。
  • 正如我所说 - 控件的组成并不重要。创建最小的代码示例,它(不)工作。我的提示(不知道完整代码)是处理鼠标事件和弹出表单的部分。不是表单中控件的组成。

标签: c# winforms


【解决方案1】:

有两个级别的“焦点”。一个是Control内部表格的“焦点”。其中一个是Form 在桌面上的整个窗口组成中的“焦点”。

Control 使用这些成员:

Form 使用这些成员:

如果您将焦点设置为表单内部的控件(通过Focus()),则焦点仅作用于表单,并且表单状态不会更改。如果您还想将焦点设置到表单,则需要激活(通过Activate())表单。

重现此行为的最小代码是:

public class MyControl : FlowLayoutPanel {
    private TextBox textBox1;
    private TextBox textBox2;

    public MyControl() {
        this.textBox1 = new TextBox();
        this.Controls.Add(this.textBox1);

        this.textBox2 = new TextBox();
        this.Controls.Add(this.textBox2);

        this.BackColor = Color.Blue; // not required

        this.MouseEnter += this.MyControl_MouseEnter;
    }

    private void MyControl_MouseEnter(object sender, EventArgs e) {
        this.textBox1?.Focus(); // sets focus to the control

        var parentForm = this.FindForm();
        parentForm?.Activate(); // activates the form
    }
}

【讨论】:

  • 感谢您的回复。但是,在我的应用程序中,FindForm() 返回 null。我相信根层次结构的核心是进行 COM 级别的 C++ 调用,而不是基于表单。我只是在检查那个。理解没有基本表单的用户控件很奇怪。
  • 您的情况不正常。我真的很想帮助你。但我需要更多线索。你能生成一些与你的条件相似的代码吗?
  • 没错,我也很好奇你的问题,我从一开始就一直在阅读@TcKs cmets。您不必分享您的确切代码您不拥有。只需继续排除与问题无关的部分,直到您拥有重现问题的最少代码,然后您可以共享该代码或创建一个类似的示例确保它也重现该行为。否则,很难猜出问题的原因。
  • @TcKs,我想出了我的问题。虽然没有解决办法。托管此布局面板的顶级控件有一个窗口句柄。这个控件是在一个基础应用程序框架上的。我的顶级控件使用 COM 接口来创建句柄。我无法从 C# 上的任何属性获取 COM 级窗口句柄。对不起,混淆了伙计们。我以前没有这样做过。关于 NDA 有一个非常好的政策。因此,我无法将其转换为流体流。但是,我感谢您提供的帮助。
  • @TcKs 和大家:感谢所有帮助。该问题已通过使用 API 调用 WindowFromPoint 而不是使用控件获取父窗口来解决。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 2015-02-12
  • 2011-03-07
  • 1970-01-01
  • 1970-01-01
  • 2012-07-08
  • 1970-01-01
相关资源
最近更新 更多