Winforms TableLayoutPanel programowe dodawanie wierszy

85

Walczyłem z tym od jakiegoś czasu i odkryłem, że wiele innych osób ma również problemy z TableLayoutPanel (.net 2.0 Winforms).

Problem

Usiłuję wziąć „pusty” tablelayoutpanel, który ma zdefiniowane 10 kolumn, a następnie programowo dodać wiersze kontrolek w czasie wykonywania (tj. Po jednej kontrolce na komórkę).

Można by pomyśleć, że powinno to być tak proste, jak

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

Ale to (dla mnie) nie dodaje wierszy. Więc może dodanie stylu wierszowego

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

Ale to też nie działa. Przekopałem się i odkryłem, że myTableLayoutPanel.RowCountużycie zmienia się od czasu projektowania do czasu wykonywania, dlatego myTableLayoutPanel.RowCount++;tak naprawdę nie dodaje to kolejnego wiersza, nawet przed / po dodaniu dla niego wpisu RowStyle!

Innym powiązanym problemem, z którym się spotykam, jest to, że kontrolki zostaną dodane do ekranu, ale wszystkie są po prostu renderowane w punkcie 0,0 TableLayoutPanel, a ponadto nie są nawet ograniczone tak, aby znajdowały się w granicach komórki, które powinny być wyświetlane w ramach (tj. z Dock = DockStyle.Fill nadal wydają się zbyt duże / małe).

Czy ktoś ma działający przykład dodawania wierszy i kontrolek w czasie wykonywania?

Popiół
źródło
Dodanie RowStyle faktycznie zwiększy RowStyles.Count ()
Eduardo Hernández

Odpowiedzi:

75

Właśnie to zrobiłem w zeszłym tygodniu. Ustaw GrowStylena TableLayoutPanelcelu AddRowslub AddColumns, następnie Twój kod powinien działać:

// 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 */);

Oto działający kod, który wydaje się podobny do tego, co robisz:

    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++;
    }

TableLayoutPanelZawsze daje mi pasuje rozmiarem. W powyższym przykładzie wypełniam kartę adresową, która może się zwiększyć lub zmniejszyć w zależności od konta z drugą linią adresu lub kraju. Ponieważ ostatni wiersz lub kolumna panelu układu tabeli się rozciągnie, wrzucam tam pustą etykietę, aby wymusić nowy pusty wiersz, a następnie wszystko ładnie się układa.

Oto kod projektanta, dzięki czemu możesz zobaczyć tabelę, od której zaczynam:

        //
        // 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;
Billy Coover
źródło
2
Doskonały, prosty przykład.
RandomInsano
2
Dziękujemy za pomysł na pusty wiersz zastępczy! Rozwiązałem problemy z rozmiarami.
JNadal
30

To dziwny projekt, ale TableLayoutPanel.RowCountwłaściwość nie odzwierciedla liczby RowStyleskolekcji, podobnie jak w przypadku ColumnCountwłaściwości i ColumnStyleskolekcji.

W moim kodzie znalazłem potrzebę ręcznej aktualizacji RowCount/ ColumnCountpo wprowadzeniu zmian w RowStyles/ ColumnStyles.

Oto przykład kodu, którego użyłem:

    /// <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;
    }

Inne przemyślenia

  • Nigdy nie robiłem, DockStyle.Fillaby kontrolka wypełniała komórkę w siatce; Zrobiłem to, ustawiając Anchorswłaściwość kontrolki.

  • Jeśli dodajesz wiele kontrolek, upewnij się, że wywołujesz SuspendLayouti ResumeLayoutomijasz proces, w przeciwnym razie wszystko będzie działać wolno, gdy cały formularz zostanie ponownie umieszczony po dodaniu każdej kontrolki.

Bevan
źródło
2
Jeśli jest to przydatne dla kogoś, w moim przypadku musiałem wywołać tableLayoutPanel1.ColumnStyles.Clear (); kiedy formularz się ładuje.
John,
17

Oto mój kod dodawania nowego wiersza do dwukolumnowej 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;
}

Kontrolka etykiety znajduje się w lewej kolumnie, a kontrolka wartości w prawej kolumnie. Kontrolki są zazwyczaj typu Label i mają właściwość AutoSize ustawioną na true.

Nie sądzę, żeby to miało zbyt duże znaczenie, ale dla odniesienia, oto kod projektanta, który konfiguruje detailTable:

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;

To wszystko działa dobrze. Należy pamiętać, że wydaje się, że istnieją pewne problemy z usuwaniem formantów z TableLayoutPanel dynamicznie przy użyciu właściwości Controls (przynajmniej w niektórych wersjach struktury). Jeśli chcesz usunąć kontrolki, sugeruję pozbycie się całego TableLayoutPanel i utworzenie nowego.

Cory McCarty
źródło
To było bardzo pomocne. Okazało się, że atrybut DockStyle.Fill jest niezbędny. Zaskakująco łatwo jest też popełniać błędy w liczeniu! Zwróć także uwagę na rozmiary kolumn i wierszy ustawione za pomocą stylów. Zauważyłem, że gdy RowStyle został ustawiony na AutoSize, pewne niezamierzone odchylenia w ustawieniach TextAlign (między Górą, Środkiem i Dołem) sprawiły, że wyglądało na to, że tabela generowała dodatkowe wiersze w jakiś dziwny sposób, ale tak nie było. Sprawa działa całkiem nieźle, kiedy już się zorientujesz, ale dotarcie do celu było bolesne!
Jan Hettich
7

Utwórz panel układu tabeli z dwiema kolumnami w formularzu i nazwij go tlpFields.

Następnie po prostu dodaj nową kontrolkę do panelu układu tabeli (w tym przypadku dodałem 5 etykiet w kolumnie-1 i 5 pól tekstowych w kolumnie-2).

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
}

Na koniec uruchom kod.

Ali Motamedi
źródło
jak uzyskujesz dostęp do tlpfields? Utworzyłem tablelayoutpanel i jego nazwa to tabkelayout, ale nie mogę uzyskać do niego dostępu.
Muneem Habib
@MuneemHabib przejdź do właściwości tabkelayout i zmień modyfikatory z prywatnego na publiczny
RookieCoder
4

Właśnie przejrzałem swój kod. W jednej aplikacji po prostu dodaję kontrolki, ale bez określania indeksu, a po zakończeniu po prostu przechodzę przez style wierszy i ustawiam typ rozmiaru na AutoSize. Więc samo dodanie ich bez określania indeksów wydaje się dodawać wiersze zgodnie z przeznaczeniem (pod warunkiem, że GrowStyle jest ustawiony na AddRows).

W innej aplikacji wyczyszczam kontrolki i ustawiam właściwość RowCount na wymaganą wartość. Nie powoduje to dodania RowStyles. Następnie dodaję moje kontrolki, tym razem określając indeksy, i dodaję nowy RowStyle ( RowStyles.Add(new RowStyle(...)) i to również działa.

Więc wybierz jedną z tych metod, obie działają. Pamiętam bóle głowy spowodowane przez panel układu stołu.

OregonGhost
źródło
Spróbuję sprawdzić, czy zachowuje się samo!
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
Sujeet
źródło
Pytanie dotyczy TableLayoutPanel, ten post dotyczy DataTable. Poczta zawiera tylko kod. Nie ma żadnego tekstu opisującego, o co chodzi. Brak komentarzy w kodzie. Więc -1.
Nick Alexeev
0

Działa to doskonale w przypadku dodawania wierszy i kontrolek w TableLayoutPanel.

Zdefiniuj pusty panel Tablelayoutpanel z 3 kolumnami na stronie projektu

    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)

Utwórz przycisk btnAddRow, aby dodawać wiersze po każdym kliknięciu

     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
EIV
źródło
0

Właśnie miałem powiązany problem (i tak znalazłem ten wątek), w którym moje dynamicznie dodane style wierszy i kolumn nie działały. Zwykle traktuję SuspendLayout () / ResumeLayout () jako optymalizacje, ale w tym przypadku zawijanie w nie mojego kodu sprawiło, że wiersze i kolumny zachowywały się poprawnie.

Początek mądrości
źródło