我有一个Windows窗体自定义控件,其作用类似于面板,因为它可以包含任意数量的子窗口。子控件的数量和类型是在运行时确定的,因此我需要以通用方式工作,而不知道可能存在或可能不存在的确切子控件。
我想根据面板是否包含焦点来改变面板的背景颜色。因此,如果面板的孩子(或面板的孩子的孩子等......)获得焦点我想知道这一点,所以我可以更新自定义面板的背景颜色。当焦点转移到不在子层次结构中的东西时,我也需要知道所以我可以恢复到原始背景颜色。
Control.ContainsFocus非常适合告诉我面板是否包含子层次结构中的焦点,但我需要知道何时发生更改。目前我只能提出以下不良机制。
我挂钩了每个孩子的GotFocus / LostFocus以及每个孩子的每个孩子等。我还必须挂钩ControlAdded / ControlRemoved以确保我与可能的改变孩子hieararchy保持同步。正如你所看到的,这可能最终导致很多事件挂钩,我怀疑必须有一个更简单的方法。有什么想法吗?
答案 0 :(得分:7)
似乎使用 Enter 和离开事件就是答案。 GotFocus只会被发送到获得焦点的特定控件,而Enter事件也将被发送到获取GotFocus事件的控件的父(和祖先)控件。
来自http://msdn.microsoft.com/en-us/library/system.windows.forms.control.leave.aspx
“Enter和Leave事件是分层的,将级联起来 沿着母链向下,直到达到适当的控制。对于 假设您有一个带有两个GroupBox控件的Form,每个都有一个 GroupBox控件有一个TextBox控件。当插入符号移动时 一个TextBox到另一个,为TextBox引发Leave事件 和GroupBox,并为其他GroupBox和Enter引发Enter事件 文本框“。
答案 1 :(得分:1)
我担心这是唯一的选择。 Winforms有时会在api中出现一些烦人的漏洞。我没有检查但是如果ContainsFocus只是一个容器控件的控制树的递归遍历,以查看是否有任何控件具有焦点,我不会感到惊讶。
拥有大量事件处理程序并不是一个很大的问题,引发了很多改变UI元素的事件。您可以通过对可添加的控件进行子类化来解决这个问题(但我不确定您是否必须允许所有控件或只是一个子集)并将面板传递给添加的控件,以便控件本身在调用时调用面板/失去焦点。但这也是很多工作,并且在面板中使用代码的类似观察者的模式是恕我直言更容易做到的。