C# 动态添加到TableLayoutPanel的行显示在不同的行位置

C# 动态添加到TableLayoutPanel的行显示在不同的行位置,c#,winforms,dynamic,position,tablelayoutpanel,C#,Winforms,Dynamic,Position,Tablelayoutpanel,我正在尝试通过单击按钮将文本框动态添加到TableLayoutPanel。单击鼠标可选择一行。 在选择行之后,单击按钮可在所选行号上插入文本框。 问题是,在不同选择的行上正确地显示文本框3或4次后,进一步单击按钮开始在随机行上显示文本框,即使调试时显示了正确的行号 我需要帮助,这里是完整的代码: public partial class Form1 : Form { private TableLayoutPanel _tableLayout; private int _selec

我正在尝试通过单击按钮将文本框动态添加到TableLayoutPanel。单击鼠标可选择一行。
在选择行之后,单击按钮可在所选行号上插入文本框。
问题是,在不同选择的行上正确地显示文本框3或4次后,进一步单击按钮开始在随机行上显示文本框,即使调试时显示了正确的行号

我需要帮助,这里是完整的代码:

public partial class Form1 : Form
{
    private TableLayoutPanel _tableLayout;
    private int _selectedRow = -1;
    public Form1()
    {
        InitializeComponent();

        var button = new Button()
        {
            Text = "Add Text"
        };
        button.MouseClick += AddText;

        this.Controls.Add(button);

        _tableLayout = new TableLayoutPanel()
        {
            Dock = DockStyle.Fill,
            AutoScroll = true,
            AutoSize = true,
            AutoSizeMode = AutoSizeMode.GrowAndShrink,
            CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
        };
        _tableLayout.MouseClick += SelectRow;

        this.Controls.Add(_tableLayout);
    }

    private void SelectRow(object sender, MouseEventArgs e)
    {
        _selectedRow = GetRowColIndex(_tableLayout, e.Location).Value.Y;
    }

    private void AddText(object sender, MouseEventArgs e)
    {
        _tableLayout.ColumnStyles.Add(new ColumnStyle() { SizeType = SizeType.AutoSize });
        _tableLayout.RowStyles.Add(new RowStyle() { SizeType = SizeType.AutoSize });
        _tableLayout.Controls.Add(new TextBox(), 0, _selectedRow);
    }

    Point? GetRowColIndex(TableLayoutPanel tlp, Point point)
    {
        if (point.X > tlp.Width || point.Y > tlp.Height)
            return null;

        int w = tlp.Width;
        int h = tlp.Height;
        int[] widths = tlp.GetColumnWidths();

        int i;
        for (i = widths.Length - 1; i >= 0 && point.X < w; i--)
            w -= widths[i];
        int col = i + 1;

        int[] heights = tlp.GetRowHeights();
        for (i = heights.Length - 1; i >= 0 && point.Y < h; i--)
            h -= heights[i];

        int row = i + 1;

        return new Point(col, row);
    }
}
公共部分类表单1:表单
{
私人桌面布局面板_桌面布局;
private int _selectedRow=-1;
公共表格1()
{
初始化组件();
var按钮=新按钮()
{
Text=“添加文本”
};
button.MouseClick+=添加文本;
此.Controls.Add(按钮);
_tableLayout=新建TableLayoutPanel()
{
Dock=DockStyle.Fill,
AutoScroll=true,
AutoSize=true,
AutoSizeMode=AutoSizeMode.growthandshrink,
CellBorderStyle=表格布局面板CellBorderStyle.Single
};
_tableLayout.MouseClick+=选择行;
this.Controls.Add(_tableLayout);
}
private void SelectRow(对象发送者,鼠标指针)
{
_selectedRow=GetRowColIndex(_tableLayout,e.Location).Value.Y;
}
私有void AddText(对象发送者,MouseEventArgs e)
{
_tableLayout.ColumnStyles.Add(新ColumnStyle(){SizeType=SizeType.AutoSize});
_tableLayout.RowStyles.Add(新的RowStyle(){SizeType=SizeType.AutoSize});
_tableLayout.Controls.Add(新文本框(),0,_selectedRow);
}
点?GetRowColIndex(表格布局面板tlp,点)
{
if(点X>tlp.宽度| |点Y>tlp.高度)
返回null;
int w=tlp.宽度;
int h=tlp高度;
int[]widths=tlp.GetColumnWidths();
int i;
对于(i=widths.Length-1;i>=0&&point.X=0&&point.Y
当前代码中缺少某些部分。它不考虑滚动条和当前TableLayoutPanel的DisplayRectangle。正如您在.Net源代码中看到的,该方法已经执行了这些计算,以获取每个单元格的坐标,并调用使用当前单元格的边界和剪贴簿初始化的类

您可以在代码中使用相同的逻辑或使用已知的度量,从事件中的
e.CellBounds
参数检索单击的单元格边界

在这里的示例中,从TLP的
MouseClick
事件中获取鼠标位置,并使用
e.cellbunds.Contains(currentPointerLocation)
中的方法在单元格边界包含鼠标指针时绘制单元格背景,并使用存储在此处的两个字段中的当前坐标更新两个标签,对于semplicity:

Point currentPointerLocation = Point.Empty;
Rectangle currentCellBounds = Rectangle.Empty;
Point currentCell = Point.Empty;

private void tableLayoutPanel1_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
{
    if (e.CellBounds.Contains(currentPointerLocation)) {
        currentCellBounds = e.CellBounds;
        currentCell = new Point(e.Row, e.Column);
        e.Graphics.FillRectangle(Brushes.Red, e.CellBounds);
    }
    else {
        using (var brush = new SolidBrush(tableLayoutPanel1.BackColor)) {
            e.Graphics.FillRectangle(brush, e.CellBounds);
        }
    }
}

private void tableLayoutPanel1_MouseClick(object sender, MouseEventArgs e)
{
    currentPointerLocation = e.Location;

    this.tableLayoutPanel1.Invalidate();
    this.tableLayoutPanel1.Update();

    lblCurrentCell.Text = currentCell.ToString();
    lblCellBounds.Text = currentCellBounds.ToString();
}
使用这些值,可以更简单地确定当前单元格的坐标,并在向使用鼠标指针选定的单元格添加控件时使用这些坐标

例如,使用按钮(
btnAddControl
)和ContextMenuStrip向TableLayoutPanel添加不同的控件:

private void btnAddControl_Click(object sender, EventArgs e)
{
    tableLayoutPanel1.Controls.Add(new TextBox() {
        Multiline = true, Text = "TextBox from Button", Dock = DockStyle.Fill }, currentCell.Y, currentCell.X);
}

// Each ToolStripMenuItem sub-item subscribes to the event using this handler
private void contextTLPMenu_Clicked(object sender, EventArgs e)
{
    Control ctl = null;
    switch ((sender as ToolStripMenuItem).Text)
    {
        case "TextBox":
            ctl = new TextBox() { Multiline = true, Text = "TextBox from ContextMenu" };
            break;
        case "Button":
            ctl = new Button() { Text = "A Button", ForeColor = Color.White };
            break;
        case "Panel":
            ctl = new Panel() { BackColor = Color.LightGreen };
            break;
        default:
            break;
    }
    if (ctl != null) {
        ctl.Dock = DockStyle.Fill;
        tableLayoutPanel1.Controls.Add(ctl, currentCell.Y, currentCell.X);
    }
}
视觉效果: