将 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 无论哪个实例都会返回相同的值,例如FieldTopFieldLeft 等。所以FieldName 可能恰好与第一个实例同名,因此对 BringToFront 的调用始终应用于第一个控件。 为什么不直接输入field.BringToFront()?当他已经有对它的引用时,真的不需要在控件集合中找到它。 FieldName 是我为标签创建的属性(也是一个用户控件)【参考方案5】:

从我的经验看来,Windows 将属于一个图形容器(窗格、组框...等)的所有控件都放在了一个软件集合中。集合按子索引排序,子索引是该容器中每个控件的属性。 诀窍是具有相同索引的孩子可以并且确实存在。在这种情况下,windows 将绘制那些相对于其他子排序的子元素,但在它们之间,它将以它们添加到容器中的相反顺序绘制它们。

长话短说:对于一个容器,当您想要更改 z 顺序时,您需要通过更改所有而不只是某些索引来确保控件具有不同的索引。例如:

foreach (Control newControl in TopControl.Controls)

   TopControl.Controls.SetChildIndex(newControl,indexlogic(newControl));

其中indexLogic(newControl ) 是您计算特定控件索引的方法。

【讨论】:

以上是关于将 Winforms 控件置于最前面的主要内容,如果未能解决你的问题,请参考以下文章

winform 如何将panel中的某一个控件置于最上层?

将 WPF 控件与 WinForms 一起使用

Winforms:创建动态时间线控件

C# WinForms 用鼠标拖动控件

WinForms:使用 c# 添加控件

在 C# (WinForms) 中拦截应用程序中所有控件的单击事件