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

时间:2022-02-10 15:02:02

I am having a peculiar problem with the order in which FlowLayoutPanels are added in to the form's controls property. This is what I tried,

我对FlowLayoutPanels添加到表单的controls属性的顺序有一个特殊的问题。这是我试过的,

I added 7 FlowLayoutPanels in to a C# window application from left to right in vertical strips. Then I tagged the flow layouts as 1, 2, 3, ... 7 again from left to right. Now in the load handler of the form, I wrote the following snippet,

我在垂直条带中从左到右添加了7个FlowLayoutPanel到C#窗口应用程序。然后我再次从左到右标记流量布局为1,2,3,... 7。现在在表单的加载处理程序中,我编写了以下代码段,

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

I expected messages to appear in the order of 1, 2, ... 7. But I got it in the reverse order (7, 6, ...1). Could some one help me out with the mistake I did ??

我希望消息以1,2,...的顺序出现。但是我按相反的顺序(7,6,... 1)得到它。有人可以帮我解决我做的错误吗?

Reason behind preserving the order,

保留订单背后的原因,

I am trying to make a calendar control with each row representing a day. If a month starts from Wednesday, then I need to add a empty label to the first(Monday) and the second(Tuesday) row. So the order matters a bit

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

5 个解决方案

#1


3  

look at the order in which they are added to the form in the yourForm.designer.cs

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

#2


7  

I know this is quite an old question, but...

我知道这是一个很老的问题,但......

You might want to use SetChildIndex. e.g. this.Controls.SetChildIndex(button1, 0);

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

#3


1  

if you look at the code generated by the designer Form1.designer.cs it will look something like this:

如果你看看设计师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);

note how it was built up you added panel 1 first then 2 etc. but as the code runs through it will add 7 first then 6.

注意它是如何构建你先添加面板1然后再添加2等等但是当代码运行时它会先添加7然后再添加6。

this code will be in the InitializeComponent() function generated by the designer.

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

Why do you need them to run in a certain order?

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

I wouldn't rely on the designer to keep the order you want.. i would sort the controls my self:

我不会依赖设计师来保持你想要的订单..我会自动对控件进行排序:

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

#4


1  

What if in future some other designer removed the controls, added back etc? Checking the designer always is a mess. What would be better is to sort the controls in the container control before you enumerate. I use this extension method (if you have Linq):

如果将来某些其他设计师删除了控件,添加回来等怎么办?检查设计师总是一团糟。更好的是在枚举之前对容器控件中的控件进行排序。我使用这种扩展方法(如果你有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;
}

And you can:

你可以:

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

(Above is for TabIndex). Would be trivial to sort according to Tag from that.

(上面是TabIndex)。根据Tag从那里排序是微不足道的。

#5


0  

Is it really a problem?

这真的是个问题吗?

As long as the UI operates correctly (in terms of tab order, for example), I'd recommend that you don't make any assumptions about the order in which they're enumerated.

只要UI正常运行(例如,按Tab键顺序),我建议您不要对它们被枚举的顺序做出任何假设。

EDIT: Thanks for explaining your requirement in more detail. I think I'd still recommend against using the order that they're stored in the Controls collection. It's always best to consider these implementation details to be 'opaque'. You have a tag associated with each control, so you can use this to identify the correct control. In order to speed up the processing, you could build a 7-element array that references the controls by ordinal:

编辑:感谢您更详细地解释您的要求。我想我仍然建议不要使用它们存储在Controls集合中的顺序。最好将这些实现细节视为“不透明”。您有一个与每个控件关联的标记,因此您可以使用它来标识正确的控件。为了加快处理速度,您可以构建一个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;

Though I'd put some type-checking in to make this code a bit more robust!

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

#1


3  

look at the order in which they are added to the form in the yourForm.designer.cs

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

#2


7  

I know this is quite an old question, but...

我知道这是一个很老的问题,但......

You might want to use SetChildIndex. e.g. this.Controls.SetChildIndex(button1, 0);

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

#3


1  

if you look at the code generated by the designer Form1.designer.cs it will look something like this:

如果你看看设计师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);

note how it was built up you added panel 1 first then 2 etc. but as the code runs through it will add 7 first then 6.

注意它是如何构建你先添加面板1然后再添加2等等但是当代码运行时它会先添加7然后再添加6。

this code will be in the InitializeComponent() function generated by the designer.

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

Why do you need them to run in a certain order?

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

I wouldn't rely on the designer to keep the order you want.. i would sort the controls my self:

我不会依赖设计师来保持你想要的订单..我会自动对控件进行排序:

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

#4


1  

What if in future some other designer removed the controls, added back etc? Checking the designer always is a mess. What would be better is to sort the controls in the container control before you enumerate. I use this extension method (if you have Linq):

如果将来某些其他设计师删除了控件,添加回来等怎么办?检查设计师总是一团糟。更好的是在枚举之前对容器控件中的控件进行排序。我使用这种扩展方法(如果你有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;
}

And you can:

你可以:

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

(Above is for TabIndex). Would be trivial to sort according to Tag from that.

(上面是TabIndex)。根据Tag从那里排序是微不足道的。

#5


0  

Is it really a problem?

这真的是个问题吗?

As long as the UI operates correctly (in terms of tab order, for example), I'd recommend that you don't make any assumptions about the order in which they're enumerated.

只要UI正常运行(例如,按Tab键顺序),我建议您不要对它们被枚举的顺序做出任何假设。

EDIT: Thanks for explaining your requirement in more detail. I think I'd still recommend against using the order that they're stored in the Controls collection. It's always best to consider these implementation details to be 'opaque'. You have a tag associated with each control, so you can use this to identify the correct control. In order to speed up the processing, you could build a 7-element array that references the controls by ordinal:

编辑:感谢您更详细地解释您的要求。我想我仍然建议不要使用它们存储在Controls集合中的顺序。最好将这些实现细节视为“不透明”。您有一个与每个控件关联的标记,因此您可以使用它来标识正确的控件。为了加快处理速度,您可以构建一个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;

Though I'd put some type-checking in to make this code a bit more robust!

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