C# 将Winforms控件置于最前面

C# 将Winforms控件置于最前面,c#,winforms,controls,C#,Winforms,Controls,除了control.BringToFront()之外,还有其他方法将控件置于前端吗 我在一个用户控件上有一系列标签,当我试图将其中一个标签放到前面时,它不起作用。我甚至循环了所有的控件,并将它们全部发回,除了我感兴趣的那一个,它不会改变任何事情 下面是将标签添加到用户控件的方法 private void AddUserLabel() { var field = new UserLabel(); userContainer.Controls.Add(field); Sen

除了
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();
}

控件的z索引是每个容器的

如果在容器内的控件(如
面板
)上调用BringToFront,它将不会将容器带到前面。
因此,该控件将仅位于该容器中其他控件的前面

要查看控件所在的容器,可以使用“视图”菜单中的“文档大纲”窗格


EDIT:您的
userContainer
控件可能位于另一个控件后面。

您是否在
BringToFront()之后尝试了
Invalidate()
?BringToFront不会引发绘制事件

试试这个:

private void SendLabelsToBack()
{
    foreach (var label in userContainer.Controls)
    {
        label.SendToBack();
        label.Invalidate();
    }
}

我想您只需要更改最后一行:

userContainer.Controls[field.FieldName].BringToFront(); 
为此:

userContainer.Controls[field.Name].BringToFront(); 
当您使用字符串作为控件集合的索引器时,它使用控件的
Name
属性(而不是
FieldName
属性)

由于您只是试图将最近添加的控件置于顶部,因此这也会起作用:

userContainer.Controls[userContainer.Controls.Count - 1].BringToFront();

是的,还有另一种方法。
控制.SetChildIndex()
也会更改Z顺序。索引为0的是位于顶部的。虽然,
BringToFront()
使用此方法,但不会给您买任何东西

给定的
SendLabelsToBack()
方法无法工作,它还会将标签发送到添加到后面的位置。但你的下一句话再次修正了这一点


好的,这不起作用,这意味着
BringToFront()
方法无法执行。在输出窗口中查找“首次机会异常”通知。如前所述,如果用户控件包含UserLabel以外的任何控件,则您的
SendLabelsToBack()
将导致异常。另外,在调用
BringToFront()
后设置一个断点,并检查
userContainer.Controls[0].Name
的值。根据我的经验,windows似乎将属于一个图形容器(窗格、组框…等)的所有控件放在一个软件集合中。集合按子索引排序,子索引是该容器中每个控件的属性。 诀窍在于,具有相同索引的子级可以并且确实存在。在这种情况下,windows将绘制相对于其他子对象排序的子对象,但在这些子对象之间,它将按照添加到容器中的相反顺序绘制它们

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

foreach (Control newControl in TopControl.Controls)
{
   TopControl.Controls.SetChildIndex(newControl,indexlogic(newControl));
}

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

一些示例代码会很好。您确定这些控件位于同一个容器控件中吗。将控件设置为front只能使其成为容器中的front控件。这篇文章帮助我解决了完全相同的问题。我只是尝试了一下,但也没有帮助。看起来好像有两个标签具有相同的z索引,而有些则没有。根据我的理解,如果我手动设置它们,它们应该都有相同的z索引。完美的答案。为我工作!不否则,他会得到一个例外。@Slaks:根据问题中的用法,看起来无论是哪个实例,
FieldName
都会返回相同的值,如
FieldTop
FieldLeft
等。因此
FieldName
可能恰好与第一个实例的名称相同,因此,对BringToFront的调用始终应用于第一个控件。为什么不只键入
字段。BringToFront()
?当控件集合中已经有引用时,实际上没有必要在控件集合中找到它。FieldName是我为标签(也是一个用户控件)创建的属性。我在最后一部分没有真正遵循这一点,因为表单只实例化了一次。只是试图找出标签不可见的原因。它实际上是可见的,但定位错误吗?或者它根本不可见?它在另一个标签后面可见。在重新检查标签名称后,我意识到另一个标签意外地被赋予了相同的名称。所以它的BringToFont被调用,而不是我想要的。在问这个问题之前应该已经知道了…谢谢汉斯。这是“抓住你了”!尝试将要更改其可见性的控件移出容器,例如将
标签
控件移出
组框
容器父级,使其成为主
表单
容器的子级,这样就可以了。