C# 在面板内的列中动态创建控件

C# 在面板内的列中动态创建控件,c#,winforms,C#,Winforms,我有一个面板,可以在其中创建标签和数字向上向下字段,如下所示: List<string> Labels = new List<string>(); public List<Label> DeliveryBreakdownLabelsModel = new List<Label>(); public List<NumericUpDown> DeliveryBreakdownNumericUp

我有一个面板,可以在其中创建标签和数字向上向下字段,如下所示:

        List<string> Labels = new List<string>();
        public List<Label> DeliveryBreakdownLabelsModel = new List<Label>();
        public List<NumericUpDown> DeliveryBreakdownNumericUpDownModel = new List<NumericUpDown>();


    private void SetDeliveryBreakdownAmountForm_Load(object sender, EventArgs e)
        {
           var rModel = //List data from database
            AddRow(rModel);
            Arrange();
        }




      private void AddRow(IList<DeliveryBreakdownGetViewModel> rModel)
        {
            for (int i = 0; i < rModel.Count; i++)
            {
                Labels.Add(rModel[i].DesignGroupName);
                var label = new Label
                {
                    AutoSize = true, // make sure to enable AutoSize
                    Name = "label" + Labels.Count,
                    Text = rModel[i].DesignGroupName,
                    Location = new Point(12, YPos)
                };
                this.Controls.Add(label);
                pnlDeliveryBreakdown.Controls.Add(label);
                DeliveryBreakdownLabelsModel.Add(label);


                var numericUpDown = new NumericUpDown
                {
                    Name = "numericUpDown" + Labels.Count,
                    Text = rModel[i].ContractedAmount.ToString(),
                    Location = new Point(12, YPos),
                    Size = new Size(60, 19),
                    DecimalPlaces = 2,
                    Maximum = decimal.MaxValue
                };
                this.Controls.Add(numericUpDown);
                this.Controls.Add(numericUpDown);
                pnlDeliveryBreakdown.Controls.Add(numericUpDown);
                DeliveryBreakdownNumericUpDownModel.Add(numericUpDown);


                YPos += 25;
            }
        }





         void Arrange()
        {
            // Determine the widest label sized by the AutoSize 
            var maxLabelX = 0;
            for (int i = 0; i < Labels.Count; i++)
            {
                maxLabelX = Math.Max(maxLabelX, DeliveryBreakdownLabelsModel[i].Location.X + DeliveryBreakdownLabelsModel[i].Size.Width);
            }

            // Move all the text boxes a little to the right of the widest label
            var maxNumericX = 0;
            for (int i = 0; i < Labels.Count; i++)
            {
                maxNumericX = Math.Max(maxNumericX, DeliveryBreakdownNumericUpDownModel[i].Location.X + DeliveryBreakdownNumericUpDownModel[i].Size.Width);
                DeliveryBreakdownNumericUpDownModel[i].Location = new Point(maxLabelX + 10, DeliveryBreakdownNumericUpDownModel[i].Location.Y);
            }

            //Set total wi
            this.Width = maxNumericX + maxLabelX + 60;
        }
列表标签=新列表();
public List DeliveryBreakdownLabelsModel=new List();
public List DeliveryBreakdownNumericUpDownModel=新列表();
私有void SetDeliveryBreakdownAmountForm_加载(对象发送方,事件参数e)
{
var rModel=//列出数据库中的数据
AddRow(rModel);
排列();
}
私有void AddRow(IList rModel)
{
for(int i=0;i
所以它看起来像:

我的问题是,如何修改代码以创建多个列。我想这样做,因为有时我可以有很多数据,所以只有在垂直显示可能是一个问题,在未来。预期结果:即


我建议使用带有
用户控件的
TableLayoutPanel
,该控件只包含一个标签和一个数字框

即使在设计师中,这看起来也很整洁

您只需从用户控件的数字框中公开所需的属性

在上面的示例中,我使用以下代码:

// Fixed height user control
// Some code taken from: https://stackoverflow.com/a/4388922/380384
[Designer(typeof(MyControlDesigner))]
public partial class LabelNumeric : UserControl
{
    public LabelNumeric()
    {
        InitializeComponent();
    }

    protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
    {
        base.SetBoundsCore(x, y, width, 24, specified);
    }
    [DefaultValue("Label")]
    public string Caption
    {
        get => label1.Text;
        set => label1.Text = value;
    }
    [DefaultValue(0)]
    public decimal Value
    {
        get => numericUpDown1.Value;
        set => numericUpDown1.Value =value;
    }
    [DefaultValue(0)]
    public int DecimalPlaces
    {
        get => numericUpDown1.DecimalPlaces;
        set => numericUpDown1.DecimalPlaces = value;
    }
    [DefaultValue(100)]
    public decimal MaxValue
    {
        get => numericUpDown1.Maximum;
    }
    [DefaultValue(0)]
    public decimal MinValue
    {
        get => numericUpDown1.Minimum;
    }
}
internal class MyControlDesigner : ControlDesigner
{
    MyControlDesigner()
    {
        base.AutoResizeHandles = true;
    }
    public override SelectionRules SelectionRules
    {
        get
        {
            return SelectionRules.LeftSizeable | SelectionRules.RightSizeable | SelectionRules.Moveable;
        }
    }
}
您可以从
tableLayoutPanel1.controls
属性访问所有控件,并检查它们在表中的位置,如下所示:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        foreach (var item in tableLayoutPanel1.Controls.OfType<LabelNumeric>())
        {
            var pos = tableLayoutPanel1.GetCellPosition(item);
            item.Caption = $"Row{pos.Row}Col{pos.Column}";
        }
    }
}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
}
受保护的覆盖无效加载(事件参数e)
{
基础荷载(e);
foreach(tableLayoutPanel1.Controls.OfType()中的变量项)
{
var pos=表格布局面板1.GetCellPosition(项目);
item.Caption=$“行{pos.Row}列{pos.Column}”;
}
}
}
因此,在运行时,它如下所示:


诀窍是在底部增加一行自动调整大小,包含控件的所有其他行的固定高度为
24pt

我建议使用
TableLayoutPanel
UserControl
,该控件正好包含一个标签和一个数字框

即使在设计师中,这看起来也很整洁

您只需从用户控件的数字框中公开所需的属性

在上面的示例中,我使用以下代码:

// Fixed height user control
// Some code taken from: https://stackoverflow.com/a/4388922/380384
[Designer(typeof(MyControlDesigner))]
public partial class LabelNumeric : UserControl
{
    public LabelNumeric()
    {
        InitializeComponent();
    }

    protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
    {
        base.SetBoundsCore(x, y, width, 24, specified);
    }
    [DefaultValue("Label")]
    public string Caption
    {
        get => label1.Text;
        set => label1.Text = value;
    }
    [DefaultValue(0)]
    public decimal Value
    {
        get => numericUpDown1.Value;
        set => numericUpDown1.Value =value;
    }
    [DefaultValue(0)]
    public int DecimalPlaces
    {
        get => numericUpDown1.DecimalPlaces;
        set => numericUpDown1.DecimalPlaces = value;
    }
    [DefaultValue(100)]
    public decimal MaxValue
    {
        get => numericUpDown1.Maximum;
    }
    [DefaultValue(0)]
    public decimal MinValue
    {
        get => numericUpDown1.Minimum;
    }
}
internal class MyControlDesigner : ControlDesigner
{
    MyControlDesigner()
    {
        base.AutoResizeHandles = true;
    }
    public override SelectionRules SelectionRules
    {
        get
        {
            return SelectionRules.LeftSizeable | SelectionRules.RightSizeable | SelectionRules.Moveable;
        }
    }
}
您可以从
tableLayoutPanel1.controls
属性访问所有控件,并检查它们在表中的位置,如下所示:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        foreach (var item in tableLayoutPanel1.Controls.OfType<LabelNumeric>())
        {
            var pos = tableLayoutPanel1.GetCellPosition(item);
            item.Caption = $"Row{pos.Row}Col{pos.Column}";
        }
    }
}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
}
受保护的覆盖无效加载(事件参数e)
{
基础荷载(e);
foreach(tableLayoutPanel1.Controls.OfType()中的变量项)
{
var pos=表格布局面板1.GetCellPosition(项目);
item.Caption=$“行{pos.Row}列{pos.Column}”;
}
}
}
因此,在运行时,它如下所示:


诀窍是在底部增加一行自动调整大小,并且包含控件的所有其他行的固定高度为
24pt

请参见此->位置=新点(12,YPos),当YPos不断变化时,您总是将X指定给12。这就像垂直填充。您需要改变这两种方式才能得到从左到右的填充。为什么不使用
TableLayoutPanel
?如果我使用
TableLayoutPanel
如何将一个在右侧,另一个在左侧,依此类推@ja72@Leon-您的意思是如何在同一单元格中包含标签和数字框?我的答案是使用一列作为标签,一列作为上下框,或者创建一个包含标签和上下框的
UserControl
。另外,关于如何使
UserControl
固定高度,使其感觉像一个文本框。请参见此->位置=新点(12,YPos),您始终是