.net 在 WinForms 应用程序中找到焦点控件的首选方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/435433/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the preferred way to find focused control in WinForms app?
提问by Milan Gardian
What is the preferred/easiest way to find the control that is currently receiving user (keyboard) input in WinForms?
在 WinForms 中查找当前接收用户(键盘)输入的控件的首选/最简单方法是什么?
So far I have come up with the following:
到目前为止,我想出了以下几点:
public static Control FindFocusedControl(Control control)
{
var container = control as ContainerControl;
return (null != container
? FindFocusedControl(container.ActiveControl)
: control);
}
From a form, this can be called simply as (in .NET 3.5+ this could even be defined as an extension method on the form) -
从表单中,这可以简单地称为(在 .NET 3.5+ 中,这甚至可以定义为表单上的扩展方法)-
var focused = FindFocusedControl(this);
Is this appropriate?
这合适吗?
Is there a built-in method that I should be using instead?
是否有我应该使用的内置方法?
Note that a single call to ActiveControl is not enough when hierarchies are used. Imagine:
请注意,使用层次结构时,对 ActiveControl 的单个调用是不够的。想象:
Form
TableLayoutPanel
FlowLayoutPanel
TextBox (focused)
(formInstance).ActiveControl will return reference to TableLayoutPanel, not the TextBox (because ActiveControl seems to only be returning immediate active child in the control tree, while I'm looking for the leaf control).
(formInstance).ActiveControl 将返回对 TableLayoutPanel 的引用,而不是 TextBox(因为 ActiveControl 似乎只返回控件树中的直接活动子项,而我正在寻找叶控件)。
回答by Hinek
If you have other calls to the Windows API already, there's no harm in using Peters solution. But I understand your worries about it and would tend to a similar solution as yours, using only the Framework functionalities. After all, the performance difference (if there is one) shouldn't be significant.
如果您已经有其他对 Windows API 的调用,那么使用 Peters 解决方案没有什么坏处。但我理解您对此的担忧,并且倾向于采用与您类似的解决方案,仅使用框架功能。毕竟,性能差异(如果有的话)不应该是显着的。
I would take a non recursive approach:
我会采取非递归的方法:
public static Control FindFocusedControl(Control control)
{
var container = control as IContainerControl;
while (container != null)
{
control = container.ActiveControl;
container = control as IContainerControl;
}
return control;
}
回答by Xn0vv3r
After searching the Internet, I found the following on George Shepherd's Windows Forms FAQ
在互联网上搜索后,我在George Shepherd 的 Windows Forms FAQ上找到了以下内容
The .Net framework libraries does not provide you an API to query for the focused Control. You have to invoke a windows API to do so:
[C#]
.Net 框架库不提供 API 来查询焦点控件。您必须调用 Windows API 才能这样做:
[C#]
public class MyForm : Form
{
[DllImport("user32.dll", CharSet=CharSet.Auto, CallingConvention=CallingConvention.Winapi)]
internal static extern IntPtr GetFocus();
private Control GetFocusedControl()
{
Control focusedControl = null;
// To get hold of the focused control:
IntPtr focusedHandle = GetFocus();
if(focusedHandle != IntPtr.Zero)
// Note that if the focused Control is not a .Net control, then this will return null.
focusedControl = Control.FromHandle(focusedHandle);
return focusedControl;
}
}
回答by BillW
ActiveControl on a Form or Container willreturn that entity's active control no matter how deeply it might be nested inside other containers.
窗体或容器上的 ActiveControl将返回该实体的活动控件,无论它嵌套在其他容器中有多深。
In your example if the TextBox has Focus : then : for Form, TableLayoutPanel, and FlowLayoutPanel : the 'ActiveControl property of all of themwill be the TextBox !
在您的示例中,如果 TextBox 具有 Focus :那么:对于 Form、TableLayoutPanel 和 FlowLayoutPanel:所有这些的 'ActiveControl 属性将是 TextBox !
Some, but not all, "genuine" ContainerControl types ... like Form and UserControl ... expose Key Events (in the case of Form : only if Form.KeyPreview == true can they be used) .
一些(但不是全部)“真正的”ContainerControl 类型……例如 Form 和 UserControl……公开关键事件(在 Form 的情况下:只有当 Form.KeyPreview == true 才能使用它们)。
Other controls which, by design, contain other controls like TableLayOutPanel, GroupBox, Panel, FlowLayoutPanel, etc. are nottype ContainerControl, and they do not expose KeyEvents.
其他控件,根据设计,包含其他控件(如 TableLayOutPanel、GroupBox、Panel、FlowLayoutPanel 等)不是ContainerControl 类型,并且它们不公开 KeyEvent。
Any attempt to cast instancesof objects like TextBox, FlowLayoutPanel, TableLayoutPanel directlyto ContainerControl will not compile : they are not type ContainerControl.
任何将TextBox、FlowLayoutPanel、TableLayoutPanel 等对象的实例直接转换为 ContainerControl 的尝试都不会编译:它们不是 ContainerControl 类型。
The code in the accepted answer, and in the next answer that corrects the first answer's spelling errors, will compile/accept instances of the above as parameters because you are "downcasting" them to type 'Control by making the parameter type 'Control
接受的答案中的代码,以及纠正第一个答案拼写错误的下一个答案中的代码,将编译/接受上述实例作为参数,因为您正在“向下转换”它们以键入 'Control 通过使参数类型为 'Control
But in each case the cast to ControlContainer will return null, and the passed in instance will be returned (downcasted) : essentially a no-op.
但是在每种情况下,对 ControlContainer 的转换都将返回 null,并且传入的实例将被返回(向下转换):本质上是一个无操作。
And, yes, the modified answer code will work if you pass it a "genuine" ControlContainer, like a Form instance, which is in the parent inheritance path of the ActiveControl, but you are still just wasting time duplicating the function of 'ActiveControl.
而且,是的,如果您将修改后的答案代码传递给它一个“真正的”ControlContainer,就像一个 Form 实例,它位于 ActiveControl 的父继承路径中,那么修改后的答案代码将起作用,但您仍然只是在浪费时间复制“ActiveControl”的功能。
So what are "genuine" ContainerControls : check them out : MS docs for ContainerControl
那么什么是“真正的”ContainerControl:查看它们:ContainerControl 的 MS 文档
Only the answer by Peter really answers the explicit question, but that answer carries the price of using interop, and 'ActiveControl will give you what you need.
只有 Peter 的答案才真正回答了明确的问题,但该答案会带来使用互操作的代价,并且“ActiveControl 将为您提供所需的东西。
Also note that every Control (container or non-container) has a Controls Collection that is never null, and that a lot of (I've never tried all of them : why would I ?) the basic WinForms control let you do "crazy stuff" like adding Controls to the ControlCollection of 'simple' controls like Button without an error.
另请注意,每个控件(容器或非容器)都有一个从不为空的控件集合,并且很多(我从未尝试过所有控件:为什么我会?)基本的 WinForms 控件让您“疯狂”东西”,比如将 Controls 添加到“简单”控件的 ControlCollection 中,例如 Button 没有错误。
Now if the real intentof your question was to ask how you find the outermost ContainerControl... that is not on the Form itself... of a regular non-containerControl nested some arbitrary levels deep ... you can use some of the ideasin the answer : but the code can be greatly simplified.
现在,如果您的问题的真正意图是询问您如何找到最外层的 ContainerControl......它不在 Form 本身上......一个常规的非容器Control 嵌套了一些任意深度......你可以使用一些答案中的想法:但代码可以大大简化。
Regular Controls, ContainerControls, UserControls, etc. (but not Form !) all have a 'Container property you can access to get their immediate container, but making sure you have the 'final Container in their inhertance path that's not a Form requires some code to "walk-up" the inheritance tree, which is demonstrated here.
常规控件、ContainerControls、UserControls 等(但不是 Form !)都有一个 'Container 属性,您可以访问以获取它们的直接容器,但要确保在其继承路径中具有 'final Container 不是 Form 需要一些代码“走上”继承树,这里演示。
You may also wish to check out the 'HasChildren property of 'Control which is usually useful in dealing with issues of Focus, ActiveControl, and Select in WinForms. Reviewing the difference between Select and Focus can be valuable here, and SO has some good resources on that.
您可能还希望查看 'Control 的'HasChildren 属性,它通常在处理 WinForms 中的 Focus、ActiveControl 和 Select 问题时很有用。回顾 Select 和 Focus 之间的区别在这里很有价值,SO 有一些很好的资源。
Hope this helps.
希望这可以帮助。
回答by Nate Cook
Hinek's solution works well for me, except it is ContainerControl, not ControlContainer. (Just in case you were scratching your head about that red squiggly line.)
Hinek 的解决方案对我来说效果很好,除了它是ContainerControl,而不是 ControlContainer 。(以防万一你对那条红色波浪线挠头。)
public static Control FindFocusedControl(Control control)
{
ContainerControl container = control as ContainerControl;
while (container != null)
{
control = container.ActiveControl;
container = control as ContainerControl;
}
return control;
}
回答by sliderhouserules
If you follow ActiveControl out recursively it doesn't take you to the leaf control that has focus?
如果您递归地跟踪 ActiveControl,它不会将您带到具有焦点的叶控件?
回答by colin lamarre
ActiveControl doesn't always work out, like with SplitContainer, ActiveControl.Focused is false.
ActiveControl 并不总是有效,就像 SplitContainer 一样,ActiveControl.Focused 是假的。
So for a more fool proof method could do something like this:
因此,对于更简单的证明方法可以执行以下操作:
private IEnumerable<Control> _get_all_controls(Control c)
{
return c.Controls.Cast<Control>().SelectMany(item =>
_get_all_controls(item)).Concat(c.Controls.Cast<Control>()).Where(control =>
control.Name != string.Empty);
}
var _controls = _get_all_controls(this);
foreach (Control control in _controls)
if (control.Focused)
{
Console.WriteLine(control.Name);
break;
}

