【问题标题】:Reset focus to control with lowest tab index重置焦点以控制具有最低标签索引
【发布时间】:2025-12-12 18:40:01
【问题描述】:

我有一个可重复使用的表单。也就是说,不是每次都创建表单的新实例,而是将表单保​​持隐藏,并在需要时使其可见。 (我继承的设计;我认为这是性能优化。)

问题:第二次使用表单时,焦点在确定或取消按钮上,从第一次使用表单开始。

用户希望焦点以表单第一次出现时的方式启动 - 在具有最低标签索引的控件上。

如果只有一个这样的表单,我会破解它:添加一行代码硬连线到所需的控件。

但是这样的形式很多,可见性逻辑在一个通用的基类中。

因此,正确执行此操作会更有意义,并告诉表单专注于其第一个(最低 tabindex)控件。

有没有简单的方法?

(我可以遍历所有控件,但是我必须正确处理嵌套控件。由于 GUI 必须在第一次显示表单时执行此操作,我希望有一些我可以调用的方法来做到这一点对我来说。)

(在 VB.net 中编码,但 C# 答案会很好。)

【问题讨论】:

  • 注意:我想出的一个解决方案是向基类添加一个自定义字段。每个子类都可以将此字段设置为打开表单时应选择的控件(或重新显示;再次可见)。 Pro:独立于标签索引,有时这很有用。 Con:独立于标签索引,这是额外的工作和维护。
  • 第二种解决方案,看起来有点晦涩,是让基类区分第一次创建表单和重新使用表单。第一次,我不确定哪个事件,记住哪个控件激活了。随后的时间,SELECT(或设置 ActiveControl)记住了控件。

标签: vb.net winforms


【解决方案1】:

它是单行的,寻找下一个控件的逻辑被暴露为一个方法,SelectNextControl()。您应该从永远无法获得焦点的 Form 对象开始,并要求它以跳位顺序查找下一个对象。哪个是 TabIndex 最低的孩子,不管它可能有什么值。

所以是这样的:

public void ShowAgain() {
    this.Show();
    this.SelectNextControl(this, true, true, true, true);
}

并且确实考虑到不可见的 Form 对象是一个相当大的资源消耗,为了一点点方便而占用了大量的操作系统资源。当然,您也可以关闭/处置它并在需要时重新创建它。 YMMV。

【讨论】:

  • 在我的情况下,似乎有一些不同的问题干扰了焦点。无论我使用我的初始代码(只是显示),还是使用您的代码和/或 Jacob 的代码,form2 似乎处于一种奇怪的状态:对于我最简单的 form2,一个带有 OK 和取消按钮的文本框,通过它们进行切换通过 3 种状态,但是当文本框处于活动状态时,它仍然没有获得键盘焦点:没有光标,按下键时没有任何反应。首次亮相时效果很好;这只会在第二次出现时发生。
  • (虽然它需要在这个大型应用程序中更改每个表单中的代码,但我确实希望最终处理所有表单。我永远不会以这种方式实现它。这可能是“次要”的迫使我重写代码。Leary 这个组织不善的代码库可能会滥用某些表单来保存数据,所以除非我必须避免这样做。)
  • 如果我单击其他窗口,然后单击返回到 form2,文本框的焦点神奇地开始正常工作。如果我用 Alt-Tab 键切换到不同的应用程序,然后返回,则相同。
  • 您可以将此代码放在表单的 Activated 事件的事件处理程序中。你的用户会恨你的。
  • 不,我是说在应用程序之间切换时效果很好。所以不需要对Activated做一些特别的事情。 Alt-tabbing 只是一个随机测试,以确定焦点的奇怪之处。奇怪的是,在我做一些强制第二次激活的事情之前,它不起作用。但是,我确实尝试将其添加到 Activated,并确保它在那里遇到断点。在 Alt-tab 和返回之前仍然不起作用。
【解决方案2】:

您可以尝试在使表单可见之前设置ActiveControl 属性:

_frm.ActiveControl = null;

这应该清除表单的活动控件并从其控件中移除焦点。

【讨论】:

  • 根据我对汉斯回答的评论,这对我的情况没有帮助——尽管可能是一个很好的解决方案,一旦我发现在我的特定情况下干扰焦点的原因。
  • 如果我 Alt-tab 到另一个应用程序,然后返回,我确实看到文本框处于活动状态(而不是第一次使用 form2 时的取消按钮)。所以这确实像宣传的那样工作(如果我可以确定为什么当重新显示 form2 时键盘焦点处于混乱状态,直到我 Alt-tab 或单击另一个表单然后返回)。
  • 注意:虽然我检查了 Hans 作为答案,但这个解决方案同样有效。