将 Winforms 控件置于最前面
Posted
技术标签:
【中文标题】将 Winforms 控件置于最前面【英文标题】:Bring Winforms control to front 【发布时间】:2011-02-06 18:23:00 【问题描述】:除了control.BringToFront()
之外,还有其他方法可以将控件置于最前面吗?
我在用户控件上有一系列标签,当我尝试将其中一个放在前面时,它不起作用。我什至遍历了所有控件并将它们全部发送回去,除了我感兴趣的那个,它不会改变任何事情。
这里是给用户控件添加标签的方法
private void AddUserLabel()
var field = new UserLabel();
userContainer.Controls.Add(field);
SendLabelsToBack(); // Send All labels to back
userContainer.Controls[field.FieldName].BringToFront();
这是将它们全部发送到后面的方法。
private void SendLabelsToBack()
foreach (var label in userContainer.Controls);
label.SendToBack();
【问题讨论】:
一些示例代码会很好。您确定控件在同一个容器控件中吗?将控件设置为前端只会使其成为其容器中的前端控件。 这篇文章帮助我解决了完全相同的问题。 【参考方案1】:是的,还有另一种方法。 Controls.SetChildIndex()
也会改变 Z 顺序。索引为 0 的那个是最上面的那个。不过不会给你买任何东西,BringToFront()
使用这种方法。
您给定的SendLabelsToBack()
方法不起作用,它还会将标签发送到添加到后面。但是你的下一个语句再次解决了这个问题。
好的,这不起作用,这意味着 BringToFront()
方法没有被执行。在“输出”窗口中查找“第一次机会异常”通知。如所写,如果用户控件包含除 UserLabel 之外的任何控件,您的 SendLabelsToBack()
将导致异常。此外,在BringToFront()
调用之后设置一个断点,并在它中断时检查userContainer.Controls[0].Name
的值。
【讨论】:
我并没有真正遵循最后一部分,因为表单只实例化了一次。 只是想找出标签不可见的原因。它实际上是可见的但定位错误吗?还是根本不可见? 在另一个标签后面可见。 重新检查标签的名称后,我意识到另一个标签不小心被赋予了相同的名称。所以它的 BringToFont 被调用而不是我想要的。在问这个问题之前应该抓住这个......谢谢汉斯。【参考方案2】:控件的 z-index 是每个容器的。
如果您对容器内的控件(例如 Panel
)调用 BringToFront,它不会将容器置于最前面。
因此,该控件只会排在该容器中的其他控件之前。
要查看您的控件所在的容器,您可以使用“视图”菜单中的“文档大纲”窗格。
编辑:您的userContainer
控件可能位于不同的控件后面。
【讨论】:
这是“陷阱”!尝试将要更改其可见性的控件移出容器,例如将Label
控件移出GroupBox
容器父级,使其成为主Form
容器的子级,它会起作用。【参考方案3】:
你在BringToFront()
之后尝试过Invalidate()
吗? BringToFront 不会引发 Paint 事件
试试这个:
private void SendLabelsToBack()
foreach (var label in userContainer.Controls)
label.SendToBack();
label.Invalidate();
【讨论】:
我刚试过,也没有用。似乎有几个标签具有相同的 z-index,而有些则没有。据我了解,如果我手动设置它们,它们应该都具有相同的 z-index。 完美答案。为我工作!【参考方案4】:我认为您只需要更改最后一行:
userContainer.Controls[field.FieldName].BringToFront();
到这里:
userContainer.Controls[field.Name].BringToFront();
当您使用字符串作为 Controls 集合的索引器时,它通过控件的 Name
属性(而不是 FieldName
属性)。
由于您只是想将最近添加的控件置于顶部,这也可以:
userContainer.Controls[userContainer.Controls.Count - 1].BringToFront();
【讨论】:
否;否则,他会得到一个例外。 @Slaks:根据问题中的用法,看起来FieldName
无论哪个实例都会返回相同的值,例如FieldTop
和FieldLeft
等。所以FieldName
可能恰好与第一个实例同名,因此对 BringToFront 的调用始终应用于第一个控件。
为什么不直接输入field.BringToFront()
?当他已经有对它的引用时,真的不需要在控件集合中找到它。
FieldName 是我为标签创建的属性(也是一个用户控件)【参考方案5】:
从我的经验看来,Windows 将属于一个图形容器(窗格、组框...等)的所有控件都放在了一个软件集合中。集合按子索引排序,子索引是该容器中每个控件的属性。 诀窍是具有相同索引的孩子可以并且确实存在。在这种情况下,windows 将绘制那些相对于其他子排序的子元素,但在它们之间,它将以它们添加到容器中的相反顺序绘制它们。
长话短说:对于一个容器,当您想要更改 z 顺序时,您需要通过更改所有而不只是某些索引来确保控件具有不同的索引。例如:
foreach (Control newControl in TopControl.Controls)
TopControl.Controls.SetChildIndex(newControl,indexlogic(newControl));
其中indexLogic(newControl )
是您计算特定控件索引的方法。
【讨论】:
以上是关于将 Winforms 控件置于最前面的主要内容,如果未能解决你的问题,请参考以下文章