C#中表单控件属性的控件顺序

6

我在将FlowLayoutPanels添加到窗体的controls属性中的顺序上遇到了一个奇特的问题。这是我尝试过的方法,

我从左到右垂直地添加了7个FlowLayoutPanels到C#窗口应用程序中。然后我按照从左到右的顺序为流式布局添加了标记1、2、3、... 7。现在在窗体的加载处理程序中,我编写了以下代码片段,

    foreach (FlowLayoutPanel aDaysControl in this.Controls)
    {
        MessageBox.Show(aDaysControl.Tag.ToString());
    }

我期望消息按照1, 2, ... 7的顺序出现。但我得到了相反的顺序(7, 6, ... 1)。有人能帮我找出我的错误吗?
保持顺序的原因是,

我正在尝试制作一个日历控件,每一行代表一天。如果一个月从星期三开始,那么我需要在第一(星期一)和第二(星期二)行添加一个空标签。所以顺序有点重要。


你在我的回答中评论说,顺序对你很重要。我非常想了解为什么。你能否编辑你的问题来解释原因?谢谢。 - Steve Morgan
5个回答

11

我知道这是一个比较旧的问题,但是...

你可能想要使用 SetChildIndex。例如:this.Controls.SetChildIndex(button1, 0);


4

请查看yourForm.designer.cs中它们添加到表单的顺序。


是的,那就是问题所在。它们被以相反的方式添加了进去。不知道为什么。谢谢。 - doekman

1
如果你查看由设计器 Form1.designer.cs 生成的代码,它会像这样:
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(658, 160);
        this.Controls.Add(this.flowLayoutPanel7);
        this.Controls.Add(this.flowLayoutPanel6);
        this.Controls.Add(this.flowLayoutPanel5);
        this.Controls.Add(this.flowLayoutPanel4);
        this.Controls.Add(this.flowLayoutPanel3);
        this.Controls.Add(this.flowLayoutPanel2);
        this.Controls.Add(this.flowLayoutPanel1);
        this.Name = "Form1";
        this.Text = "Form1";
        this.ResumeLayout(false);

注意它是如何建立的,您首先添加面板1,然后添加2等等。但是随着代码的运行,它将首先添加7,然后是6。

此代码将位于设计工具生成的InitializeComponent()函数中。

您为什么需要它们按特定顺序运行?

我不会依赖设计工具来保持您想要的顺序...我会自己排序控件:

        var flowpanelinOrder = from n in this.Controls.Cast<Control>()
                               where n is FlowLayoutPanel
                               orderby int.Parse(n.Tag.ToString())
                               select n;

        /* non linq
        List<Control> flowpanelinOrder = new List<Control>();
        foreach (Control c in this.Controls)
        {
            if (c is FlowLayoutPanel) flowpanelinOrder.Add(c);                
        }
        flowpanelinOrder.Sort();
         * */

        foreach (FlowLayoutPanel aDaysControl in flowpanelinOrder)
        {
            MessageBox.Show(aDaysControl.Tag.ToString());
        }

我正在尝试制作一个日历控件,每一行代表一天。如果一个月从周三开始,那么我需要在第一行(星期一)和第二行(星期二)添加一个空标签。因此,顺序有点重要。 - doekman
嗯,我有点懒。现在学到了教训。 - doekman

1
如果将来其他设计师删除了控件,或者重新添加了控件怎么办?总是检查设计师会很麻烦。更好的方法是在枚举之前对容器控件中的控件进行排序。如果您使用Linq,可以使用此扩展方法:
public static List<Control> ToControlsSorted(this Control panel)
{
    var controls = panel.Controls.OfType<Control>().ToList();
    controls.Sort((c1, c2) => c1.TabIndex.CompareTo(c2.TabIndex));
    return controls;
}

而且你可以:

foreach (FlowLayoutPanel aDaysControl in this.ToControlsSorted())
{
    MessageBox.Show(aDaysControl.TabIndex.ToString());
}

(上面是针对TabIndex的)。根据那个可以很轻松地根据Tag排序。

0

这真的是个问题吗?

只要UI操作正确(例如选项卡顺序等),我建议您不要对它们枚举的顺序做出任何假设。

编辑:感谢您详细说明您的需求。我仍然建议不要使用它们在控件集合中存储的顺序。最好将这些实现细节视为'opaque'。您有一个关联每个控件的标签,因此可以使用它来识别正确的控件。为了加快处理速度,您可以构建一个7元素数组,按顺序引用控件:

FlowLayoutPanel[] panels = new FlowLayoutPanel[7];

foreach(FlowLayoutPanel panel in this.Controls)
{
    panels[(int)panel.Tag] = panel;
}

// Now, you can reference the panels directly by subscript:

panels[2].BackColor = Color.Aquamarine;

虽然我会加入一些类型检查,使这段代码更加健壮!


但在我的情况下,顺序确实很重要!! - doekman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接