Winforms TableLayoutPanel fügt programmgesteuert Zeilen hinzu


84

Ich habe eine Weile damit gekämpft und festgestellt, dass einige andere Leute auch mit dem TableLayoutPanel (.net 2.0 Winforms) zu kämpfen haben.

Problem

Ich versuche, ein 'leeres' Tablelayoutpanel mit 10 definierten Spalten zu erstellen und dann zur Laufzeit programmgesteuert Steuerelementzeilen hinzuzufügen (dh ein Steuerelement pro Zelle).

Man hätte denken können, dass es so einfach sein sollte wie

myTableLayoutPanel.Controls.Add(myControl, 0 /* Column Index */, 0 /* Row index */);

Aber das (für mich) fügt die Zeilen nicht hinzu. Also vielleicht in einer Reihe hinzufügen

myTableLayoutPanel.RowStyles.Clear();
myTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F));

Das funktioniert aber auch nicht. Ich habe mich umgesehen und herausgefunden, dass sich die myTableLayoutPanel.RowCountVerwendung von Entwurfszeit zu Laufzeit ändert, daher myTableLayoutPanel.RowCount++;wird keine weitere Zeile hinzugefügt, auch nicht vor / nach dem Hinzufügen eines RowStyle-Eintrags dafür!

Ein weiteres verwandtes Problem, auf das ich stoße, ist, dass die Steuerelemente zur Anzeige hinzugefügt werden, aber alle einfach am Punkt 0,0 des TableLayoutPanel gerendert werden. Außerdem müssen sie nicht einmal innerhalb der Zellengrenzen liegen, die sie sein sollen angezeigt innerhalb (dh mit Dock = DockStyle.Fill erscheinen sie immer noch viel zu groß / klein).

Hat jemand ein funktionierendes Beispiel für das Hinzufügen von Zeilen und Steuerelementen zur Laufzeit?


Das Hinzufügen eines RowStyle erhöht tatsächlich die RowStyles.Count ()
Waffe X

Antworten:


75

Ich habe das erst letzte Woche gemacht. Stellen Sie die GrowStyleauf die TableLayoutPanelzu AddRowsoder AddColumns, geben Sie Ihren Code funktionieren sollte:

// Adds "myControl" to the first column of each row
myTableLayoutPanel.Controls.Add(myControl1, 0 /* Column Index */, 0 /* Row index */);
myTableLayoutPanel.Controls.Add(myControl2, 0 /* Column Index */, 1 /* Row index */);
myTableLayoutPanel.Controls.Add(myControl3, 0 /* Column Index */, 2 /* Row index */);

Hier ist ein Arbeitscode, der dem ähnlich zu sein scheint, was Sie tun:

    private Int32 tlpRowCount = 0;

    private void BindAddress()
    {
        Addlabel(Addresses.Street);
        if (!String.IsNullOrEmpty(Addresses.Street2))
        {
            Addlabel(Addresses.Street2);
        }
        Addlabel(Addresses.CityStateZip);
        if (!String.IsNullOrEmpty(Account.Country))
        {
            Addlabel(Address.Country);
        }
        Addlabel(String.Empty); // Notice the empty label...
    }

    private void Addlabel(String text)
    {            
        label = new Label();
        label.Dock = DockStyle.Fill;
        label.Text = text;
        label.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
        tlpAddress.Controls.Add(label, 1, tlpRowCount);
        tlpRowCount++;
    }

Das TableLayoutPanelpasst mir immer zur Größe. In meinem obigen Beispiel reiche ich eine Adresskarte ein, die je nach Konto mit der Adresszeile zwei oder einem Land wachsen oder schrumpfen kann. Da sich die letzte Zeile oder Spalte des Tabellenlayoutfensters ausdehnt, werfe ich das leere Etikett hinein, um eine neue leere Zeile zu erzwingen, und dann wird alles gut ausgerichtet.

Hier ist der Designer-Code, damit Sie die Tabelle sehen können, mit der ich beginne:

        //
        // tlpAddress
        // 
        this.tlpAddress.AutoSize = true;
        this.tlpAddress.BackColor = System.Drawing.Color.Transparent;
        this.tlpAddress.ColumnCount = 2;
        this.tlpAddress.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 25F));
        this.tlpAddress.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
        this.tlpAddress.Controls.Add(this.pictureBox1, 0, 0);
        this.tlpAddress.Dock = System.Windows.Forms.DockStyle.Fill;
        this.tlpAddress.Location = new System.Drawing.Point(0, 0);
        this.tlpAddress.Name = "tlpAddress";
        this.tlpAddress.Padding = new System.Windows.Forms.Padding(3);
        this.tlpAddress.RowCount = 2;
        this.tlpAddress.RowStyles.Add(new System.Windows.Forms.RowStyle());
        this.tlpAddress.RowStyles.Add(new System.Windows.Forms.RowStyle());
        this.tlpAddress.Size = new System.Drawing.Size(220, 95);
        this.tlpAddress.TabIndex = 0;

2
Perfektes, einfaches Beispiel.
RandomInsano

2
Danke für die Idee für eine leere Platzhalterzeile! Meine Größenprobleme wurden gelöst.
JNadal

30

Es ist ein seltsames Design, aber die TableLayoutPanel.RowCountEigenschaft spiegelt nicht die Anzahl der RowStylesSammlung wider , und dies gilt auch für die ColumnCountEigenschaft und die ColumnStylesSammlung.

Was ich in meinem Code gefunden habe, war, RowCount/ manuell zu aktualisieren, ColumnCountnachdem ich Änderungen an RowStyles/ vorgenommen habe ColumnStyles.

Hier ist ein Beispiel für Code, den ich verwendet habe:

    /// <summary>
    /// Add a new row to our grid.
    /// </summary>
    /// The row should autosize to match whatever is placed within.
    /// <returns>Index of new row.</returns>
    public int AddAutoSizeRow()
    {
        Panel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
        Panel.RowCount = Panel.RowStyles.Count;
        mCurrentRow = Panel.RowCount - 1;
        return mCurrentRow;
    }

Andere Gedanken

  • Ich habe noch nie DockStyle.Fillein Steuerelement dazu gebracht, eine Zelle im Raster zu füllen . Ich habe dies getan, indem ich die AnchorsEigenschaft des Steuerelements festgelegt habe.

  • Wenn Sie viele Steuerelemente hinzufügen, stellen Sie sicher, dass Sie den Prozess aufrufen SuspendLayoutund ResumeLayoutum ihn herum ausführen. Andernfalls werden die Dinge langsam ausgeführt, da das gesamte Formular nach dem Hinzufügen jedes Steuerelements erneut angezeigt wird.


2
Wenn es für jemanden nützlich ist, musste ich in meinem Fall tableLayoutPanel1.ColumnStyles.Clear () aufrufen ; wenn das Formular geladen wird.
John

17

Hier ist mein Code zum Hinzufügen einer neuen Zeile zu einer zweispaltigen TableLayoutColumn:

private void AddRow(Control label, Control value)
{
    int rowIndex = AddTableRow();
    detailTable.Controls.Add(label, LabelColumnIndex, rowIndex);
    if (value != null)
    {
        detailTable.Controls.Add(value, ValueColumnIndex, rowIndex);
    }
}

private int AddTableRow()
{
    int index = detailTable.RowCount++;
    RowStyle style = new RowStyle(SizeType.AutoSize);
    detailTable.RowStyles.Add(style);
    return index;
}

Das Beschriftungssteuerelement befindet sich in der linken Spalte und das Wertesteuerelement in der rechten Spalte. Die Steuerelemente sind im Allgemeinen vom Typ Label und haben die AutoSize-Eigenschaft auf true gesetzt.

Ich denke nicht, dass es zu wichtig ist, aber als Referenz ist hier der Designer-Code, der detailTable erstellt:

this.detailTable.ColumnCount = 2;
this.detailTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.detailTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.detailTable.Dock = System.Windows.Forms.DockStyle.Fill;
this.detailTable.Location = new System.Drawing.Point(0, 0);
this.detailTable.Name = "detailTable";
this.detailTable.RowCount = 1;
this.detailTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.detailTable.Size = new System.Drawing.Size(266, 436);
this.detailTable.TabIndex = 0;

Das alles funktioniert gut. Sie sollten sich bewusst sein, dass es Probleme beim dynamischen Entsorgen von Steuerelementen aus einem TableLayoutPanel mithilfe der Controls-Eigenschaft zu geben scheint (zumindest in einigen Versionen des Frameworks). Wenn Sie Steuerelemente entfernen müssen, empfehle ich, das gesamte TableLayoutPanel zu entsorgen und ein neues zu erstellen.


Das war sehr hilfreich. Ich fand, dass das DockStyle.Fill-Attribut wesentlich war. Es ist auch überraschend leicht, Fehler beim Zählen zu machen! Beachten Sie auch die Spalten- und Zeilengrößen, die mit Stilen festgelegt wurden. Als der RowStyle auf AutoSize eingestellt war, stellte ich fest, dass einige unbeabsichtigte Änderungen in den TextAlign-Einstellungen (zwischen oben, Mitte und unten) den Eindruck erweckten, dass die Tabelle auf seltsame Weise zusätzliche Zeilen generierte, aber das war nicht der Fall. Das Ding funktioniert ziemlich gut, wenn Sie es herausgefunden haben, aber es war schmerzhaft, dorthin zu gelangen!
Jan Hettich

7

Erstellen Sie ein Tabellenlayoutfenster mit zwei Spalten in Ihrem Formular und benennen Sie es tlpFields.

Fügen Sie dann einfach ein neues Steuerelement zum Tabellenlayout hinzu (in diesem Fall habe ich 5 Beschriftungen in Spalte 1 und 5 Textfelder in Spalte 2 hinzugefügt).

tlpFields.RowStyles.Clear();  //first you must clear rowStyles

for (int ii = 0; ii < 5; ii++)
{
    Label l1= new Label();
    TextBox t1 = new TextBox();

    l1.Text = "field : ";

    tlpFields.Controls.Add(l1, 0, ii);  // add label in column0
    tlpFields.Controls.Add(t1, 1, ii);  // add textbox in column1

    tlpFields.RowStyles.Add(new RowStyle(SizeType.Absolute,30)); // 30 is the rows space
}

Führen Sie abschließend den Code aus.


Wie greifen Sie auf tlpfields zu? Ich habe tablelayoutpanel erstellt und der Name ist tabkelayout, aber ich bin nicht in der Lage, darauf zuzugreifen.
Muneem Habib

@ MunemHabib gehen zu tabkelayout Eigenschaften und ändern Modifikatoren von privat zu öffentlich
RookieCoder

4

Ich habe gerade in meinen Code geschaut. In einer Anwendung füge ich nur die Steuerelemente hinzu, ohne jedoch den Index anzugeben. Wenn ich fertig bin, durchlaufe ich einfach die Zeilenstile und setze den Größentyp auf AutoSize. Wenn Sie sie also nur hinzufügen, ohne die Indizes anzugeben, werden die Zeilen wie beabsichtigt hinzugefügt (vorausgesetzt, der GrowStyle ist auf AddRows eingestellt).

In einer anderen Anwendung lösche ich die Steuerelemente und setze die RowCount-Eigenschaft auf den erforderlichen Wert. Dies fügt die RowStyles nicht hinzu. Dann füge ich meine Steuerelemente hinzu, diesmal unter Angabe der Indizes, und füge einen neuen RowStyle hinzu (RowStyles.Add(new RowStyle(...) ) hinzu. Dies funktioniert auch.

Wählen Sie also eine dieser Methoden, beide funktionieren. Ich erinnere mich an die Kopfschmerzen, die mir das Tabellenlayout verursacht hat.


Ich werde diese versuchen, um zu sehen, ob es sich selbst verhält!
Ash

0
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim dt As New DataTable
        Dim dc As DataColumn
        dc = New DataColumn("Question", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)

        dc = New DataColumn("Ans1", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)
        dc = New DataColumn("Ans2", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)
        dc = New DataColumn("Ans3", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)
        dc = New DataColumn("Ans4", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)
        dc = New DataColumn("AnsType", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)


        Dim Dr As DataRow
        Dr = dt.NewRow
        Dr("Question") = "What is Your Name"
        Dr("Ans1") = "Ravi"
        Dr("Ans2") = "Mohan"
        Dr("Ans3") = "Sohan"
        Dr("Ans4") = "Gopal"
        Dr("AnsType") = "Multi"
        dt.Rows.Add(Dr)

        Dr = dt.NewRow
        Dr("Question") = "What is your father Name"
        Dr("Ans1") = "Ravi22"
        Dr("Ans2") = "Mohan2"
        Dr("Ans3") = "Sohan2"
        Dr("Ans4") = "Gopal2"
        Dr("AnsType") = "Multi"
        dt.Rows.Add(Dr)
        Panel1.GrowStyle = TableLayoutPanelGrowStyle.AddRows
        Panel1.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
        Panel1.BackColor = Color.Azure
        Panel1.RowStyles.Insert(0, New RowStyle(SizeType.Absolute, 50))
        Dim i As Integer = 0

        For Each dri As DataRow In dt.Rows



            Dim lab As New Label()
            lab.Text = dri("Question")
            lab.AutoSize = True

            Panel1.Controls.Add(lab, 0, i)


            Dim Ans1 As CheckBox
            Ans1 = New CheckBox()
            Ans1.Text = dri("Ans1")
            Panel1.Controls.Add(Ans1, 1, i)

            Dim Ans2 As RadioButton
            Ans2 = New RadioButton()
            Ans2.Text = dri("Ans2")
            Panel1.Controls.Add(Ans2, 2, i)
            i = i + 1

            'Panel1.Controls.Add(Pan)
        Next

Die Frage bezieht sich auf TableLayoutPanel, dieser Beitrag bezieht sich auf DataTable. Der Beitrag ist nur Code. Es gibt keinen Text, der beschreibt, worum es geht. Auch keine Kommentare im Code. Also -1.
Nick Alexeev

0

Dies funktioniert perfekt zum Hinzufügen von Zeilen und Steuerelementen in einem TableLayoutPanel.

Definieren Sie ein leeres Tablelayoutpanel mit 3 Spalten auf der Entwurfsseite

    Dim TableLayoutPanel3 As New TableLayoutPanel()

    TableLayoutPanel3.Name = "TableLayoutPanel3"

    TableLayoutPanel3.Location = New System.Drawing.Point(32, 287)

    TableLayoutPanel3.AutoSize = True

    TableLayoutPanel3.Size = New System.Drawing.Size(620, 20)

    TableLayoutPanel3.ColumnCount = 3

    TableLayoutPanel3.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single

    TableLayoutPanel3.BackColor = System.Drawing.Color.Transparent

    TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 26.34146!))

    TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 73.65854!))

    TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Absolute, 85.0!))

    Controls.Add(TableLayoutPanel3)

Erstellen Sie eine Schaltfläche btnAddRow, um bei jedem Klick Zeilen hinzuzufügen

     Private Sub btnAddRow_Click(sender As System.Object, e As System.EventArgs) Handles btnAddRow.Click

          TableLayoutPanel3.GrowStyle = TableLayoutPanelGrowStyle.AddRows

          TableLayoutPanel3.RowStyles.Add(New RowStyle(SizeType.Absolute, 20))

          TableLayoutPanel3.SuspendLayout()

          TableLayoutPanel3.RowCount += 1

          Dim tb1 As New TextBox()

          Dim tb2 As New TextBox()

          Dim tb3 As New TextBox()

          TableLayoutPanel3.Controls.Add(tb1 , 0, TableLayoutPanel3.RowCount - 1)

          TableLayoutPanel3.Controls.Add(tb2, 1, TableLayoutPanel3.RowCount - 1)

          TableLayoutPanel3.Controls.Add(tb3, 2, TableLayoutPanel3.RowCount - 1)

          TableLayoutPanel3.ResumeLayout()

          tb1.Focus()

 End Sub

0

Ich hatte gerade ein verwandtes Problem (so fand ich diesen Thread), bei dem meine dynamisch hinzugefügten Zeilen- und Spaltenstile nicht wirksam wurden. Normalerweise betrachte ich SuspendLayout () / ResumeLayout () als Optimierungen, aber in diesem Fall haben sich die Zeilen und Spalten korrekt verhalten, wenn ich meinen Code in sie eingeschlossen habe.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.