什么是在WinForms应用程序中find集中控制的首选方法?
在WinForms中查找当前正在接收用户(键盘)input的控件的首选/最简单的方法是什么?
到目前为止,我已经拿出了以下内容:
public static Control FindFocusedControl(Control control) { var container = control as ContainerControl; return (null != container ? FindFocusedControl(container.ActiveControl) : control); }
从表单中,这可以简单地称为(在.NET 3.5+中,这甚至可以被定义为表单上的扩展方法) –
var focused = FindFocusedControl(this);
这是否合适?
有没有我应该使用的内置方法?
请注意,使用层次结构时,对ActiveControl的单个调用是不够的。 想像:
Form TableLayoutPanel FlowLayoutPanel TextBox (focused)
(formInstance).ActiveControl将返回对TableLayoutPanel的引用,而不是TextBox(因为ActiveControl似乎只是在控制树中返回直接活动子,而我正在寻找叶控件)。
如果您还有其他的Windows API调用,使用Peters解决scheme没有任何坏处。 但是我理解你对此的担心,并且倾向于采用类似的解决scheme,只使用框架function。 毕竟,性能差异(如果有的话)不应该是显着的。
我会采取一个非recursion的方法:
public static Control FindFocusedControl(Control control) { var container = control as IContainerControl; while (container != null) { control = container.ActiveControl; container = control as IContainerControl; } return control; }
在search互联网之后,我在George Shepherd的Windows Forms FAQ上find了以下内容
.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; } }
表单或容器上的ActiveControl 将返回该实体的主动控制,无论它嵌套在其他容器内的程度如何。
在你的例子中,如果TextBox具有Focus:那么:对于Form,TableLayoutPanel和FlowLayoutPanel: 所有这些的ActiveControl属性将是TextBox!
一些,但不是全部,“真正”的ContainerControltypes…像Form和UserControl …揭露关键事件(在Form的情况下:只有当Form.KeyPreview == true可以使用)。
其他控件,包括其他控件,如TableLayOutPanel,GroupBox,Panel,FlowLayoutPanel等, 都不是typesContainerControl,而且也不公开KeyEvent。
任何将TextBox,FlowLayoutPanel,TableLayoutPanel等实例 直接转换到ContainerControl的尝试都不会编译:它们不是ContainerControltypes。
接受答案中的代码和下一个更正第一个答案的拼写错误的答案将编译/接受上述参数的实例作为参数,因为您将它们“向下转换”为键入“通过使参数types进行控制”控制
但是在每种情况下,ControlContainer的转换都将返回null,并且传入的实例将被返回(下转):实质上是一个no-op。
而且,是的,如果您将一个“真正的”ControlContainer传递给它,就像修改后的答案代码一样,它就像在ActiveControl的父inheritancepath中的一个Form实例一样,但是您仍然在浪费时间来重复“ActiveControl”的function。
那么什么是“真正的”ContainerControl:检查出来: ContainerControl的MS文档
只有Peter的回答真的回答了这个明确的问题,但是这个答案带有使用interop的代价,“ActiveControl会给你你所需要的。
另外请注意,每个Control(容器或非容器)都有一个Controls集合,它永远不为null,而且很多(我从来没有尝试过所有这些:我为什么要这样做)基本的WinForms控件让你“疯狂东西“就像添加控件到”简单“控件的ControlCollection像Button没有错误。
现在如果你的问题的真正意图是要问你如何find最外层的ContainerControl … 不在Form本身上 …一个普通的非容器控件嵌套一些任意级别深…你可以使用一些在答案中的想法 :但代码可以大大简化。
常规控件,ContainerControls,UserControls等等(但不是Form!)都有一个'Container属性,你可以访问它们的直接容器,但是确保你有'最后的Container在他们的Inhertancepath中,而不是Form需要一些代码来“inheritance”这里演示的inheritance树。
您也可能希望查看'HasChildren属性'控件,它通常用于处理Focus,ActiveControl和WinForms中的select问题。 回顾Select和Focus之间的区别在这里是很有价值的,所以SO有一些很好的资源。
希望这可以帮助。
Hinek的解决scheme适用于我,除了是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; }
如果您按recursion方式跟踪ActiveControl,它不会将您带到具有焦点的叶控件?