C# – Table layout and moving / hiding controls

cnettablelayoutpanelwinforms

I have a form which has a table layout control on it. The table layout has 3 columns and a number of rows.

The first column contains a label, the second is either a textbox, comboBox or date time picker. The third column contains a picture which is toggled on or off if the information the user has entered contains errors. This is to allow them to see which fields they have filled in wrongly or missed.

The fifth row contains a comboBox where the user can select which type of transaction they are entering. Depending on what the user selects the controls may have to re-arrange themselves.

Let me show an example using screenshots:

http://i.stack.imgur.com/OZmFH.png

This is a standard version of the form running, the user hasn't selected a transaction type.

Now, let's say the user selects a Loan Payment. The form would re-arrange to show the following:

http://i.stack.imgur.com/j76wG.png

You can see the narrative and gross have moved down a couple of rows and a new box has been shown to allow the user to select a loan and the number of payments being made.

There are 3 different layouts that can be presented depending on the transaction type selected.

Right now I do this by checking for the SelectedIndexChanged event on the Transaction Type comboBox and I call a method to setup the view.

What would be the best way to achieve this ? Right now I have code that does it, but it's incredibly messy.

Should I look at something other than a table layout panel ?

    readonly TableLayoutPanelCellPosition tlCCccLbl = new TableLayoutPanelCellPosition(0, 5);
    readonly TableLayoutPanelCellPosition tlCCccList = new TableLayoutPanelCellPosition(1, 5);
    readonly TableLayoutPanelCellPosition tlCCccError = new TableLayoutPanelCellPosition(2, 5);

    readonly TableLayoutPanelCellPosition tlCCnarrativeLbl = new TableLayoutPanelCellPosition(0, 6);
    readonly TableLayoutPanelCellPosition tlCCnarrativeTxt = new TableLayoutPanelCellPosition(1, 6);

    readonly TableLayoutPanelCellPosition tlCCgrossLbl = new TableLayoutPanelCellPosition(0, 7);
    readonly TableLayoutPanelCellPosition tlCCgrossTxt = new TableLayoutPanelCellPosition(1, 7);
    readonly TableLayoutPanelCellPosition tlCCgrossError = new TableLayoutPanelCellPosition(2, 7);

    readonly TableLayoutPanelCellPosition tlStdnarrativeLbl = new TableLayoutPanelCellPosition(0, 5);
    readonly TableLayoutPanelCellPosition tlStdnarrativeTxt = new TableLayoutPanelCellPosition(1, 5);

    readonly TableLayoutPanelCellPosition tlStdgrossLbl = new TableLayoutPanelCellPosition(0, 6);
    readonly TableLayoutPanelCellPosition tlStdgrossTxt = new TableLayoutPanelCellPosition(1, 6);
    readonly TableLayoutPanelCellPosition tlStdgrossError = new TableLayoutPanelCellPosition(2, 6);

    readonly TableLayoutPanelCellPosition tlStdLoanPymntsLbl = new TableLayoutPanelCellPosition(0, 8);
    readonly TableLayoutPanelCellPosition tlStdLoanPymntsCmb = new TableLayoutPanelCellPosition(1, 8);
    readonly TableLayoutPanelCellPosition tlStdLoanPymntsError = new TableLayoutPanelCellPosition(2, 8);

    readonly TableLayoutPanelCellPosition tlStdLoanLbl = new TableLayoutPanelCellPosition(0, 9);
    readonly TableLayoutPanelCellPosition tlStdLoanError = new TableLayoutPanelCellPosition(2, 9);
    readonly TableLayoutPanelCellPosition tlStdccLbl = new TableLayoutPanelCellPosition(0, 10);
    readonly TableLayoutPanelCellPosition tlStdccList = new TableLayoutPanelCellPosition(1, 10);
    readonly TableLayoutPanelCellPosition tlStdccError = new TableLayoutPanelCellPosition(2, 10);

    readonly TableLayoutPanelCellPosition tlLnLoanLbl = new TableLayoutPanelCellPosition(0, 5);
    readonly TableLayoutPanelCellPosition tlLnLoanCmb = new TableLayoutPanelCellPosition(1, 5);
    readonly TableLayoutPanelCellPosition tlLnLoanError = new TableLayoutPanelCellPosition(2, 5);

    readonly TableLayoutPanelCellPosition tlLnLoanPymntsLbl = new TableLayoutPanelCellPosition(0, 6);
    readonly TableLayoutPanelCellPosition tlLnLoanPymntsCmb = new TableLayoutPanelCellPosition(1, 6);
    readonly TableLayoutPanelCellPosition tlLnLoanPymntsError = new TableLayoutPanelCellPosition(2, 6);

    readonly TableLayoutPanelCellPosition tlLnnarrativeLbl = new TableLayoutPanelCellPosition(0, 7);
    readonly TableLayoutPanelCellPosition tlLnnarrativeTxt = new TableLayoutPanelCellPosition(1, 7);

    readonly TableLayoutPanelCellPosition tlLngrossLbl = new TableLayoutPanelCellPosition(0, 8);
    readonly TableLayoutPanelCellPosition tlLngrossTxt = new TableLayoutPanelCellPosition(1, 8);
    readonly TableLayoutPanelCellPosition tlLngrossError = new TableLayoutPanelCellPosition(2, 8);

    private void cmbTransactionType_SelectedIndexChanged(object sender, EventArgs e)
    {
        ToggleLoanControls(false);
        ToggleCreditCardControls(false);
        ToggleReceiptNumbers();

        if (clsTransactionTypes.TransactionStringToTransactionID(cmbTransactionType.Text) == clsTransactionTypes.LoanPayments || clsTransactionTypes.TransactionStringToTransactionID(cmbTransactionType.Text) == clsTransactionTypes.HpPayment)
             ToggleLoanControls(true);
        else if(clsTransactionTypes.TransactionStringToTransactionID(cmbTransactionType.Text) == clsTransactionTypes.TransferToCreditCardCard)
            ToggleCreditCardControls(true);

        SetupViews(cmbTransactionType.Text);
    }

    private void SetupViews(string transactionTypeSelected)
    {
         if (transactionTypeSelected == "Payment to Credit Card")
            SetupCreditCardsLayouts();
        else if(transactionTypeSelected == "HP Payment" || transactionTypeSelected == "Loan Payment")
            SetupLoanLayouts();
        else
            SetupStandardLayouts();
    }

    private void SetupLoanLayouts()
    {
        tableBank1Income.SetCellPosition(panelLoans, tlLnLoanCmb);
        tableBank1Income.SetCellPosition(lblLoans, tlLnLoanLbl);
        tableBank1Income.SetCellPosition(lblErrorLoanName, tlLnLoanError);

        tableBank1Income.SetCellPosition(cmbNumberOfLoanPayments, tlLnLoanPymntsCmb);
        tableBank1Income.SetCellPosition(lblLoanPayments, tlLnLoanPymntsLbl);
        tableBank1Income.SetCellPosition(lblErrorLoanPayments, tlLnLoanPymntsError);

        tableBank1Income.SetCellPosition(txtTransactionGross, tlLngrossTxt);
        tableBank1Income.SetCellPosition(lblTransactionAmount, tlLngrossLbl);
        tableBank1Income.SetCellPosition(lblErrorTransactionGross, tlLngrossError);

        tableBank1Income.SetCellPosition(txtTransactionNarrative, tlLnnarrativeTxt);
        tableBank1Income.SetCellPosition(lblTransactionNarrative, tlLnnarrativeLbl);

        tableBank1Income.SetCellPosition(panelCreditCards, tlStdccList);
        tableBank1Income.SetCellPosition(lblCreditCard, tlStdccLbl);
        tableBank1Income.SetCellPosition(lblCCError, tlStdccError);

    }

    private void SetupStandardLayouts()
    {
        tableBank1Income.SetCellPosition(txtTransactionGross, tlStdgrossTxt);
        tableBank1Income.SetCellPosition(lblTransactionAmount, tlStdgrossLbl);
        tableBank1Income.SetCellPosition(lblErrorTransactionGross, tlStdgrossError);

        tableBank1Income.SetCellPosition(txtTransactionNarrative, tlStdnarrativeTxt);
        tableBank1Income.SetCellPosition(lblTransactionNarrative, tlStdnarrativeLbl);

        tableBank1Income.SetCellPosition(txtTransactionGross, tlStdgrossTxt);
        tableBank1Income.SetCellPosition(lblTransactionAmount, tlStdgrossLbl);
        tableBank1Income.SetCellPosition(lblErrorTransactionGross, tlStdgrossError);

        tableBank1Income.SetCellPosition(panelLoans, tlStdLoanLbl);
        tableBank1Income.SetCellPosition(lblLoans, tlStdLoanLbl);
        tableBank1Income.SetCellPosition(lblErrorLoanName, tlStdLoanError);

        tableBank1Income.SetCellPosition(cmbNumberOfLoanPayments, tlStdLoanPymntsCmb);
        tableBank1Income.SetCellPosition(lblLoanPayments, tlStdLoanPymntsLbl);
        tableBank1Income.SetCellPosition(lblErrorLoanPayments, tlStdLoanPymntsError);

        tableBank1Income.SetCellPosition(panelCreditCards, tlStdccList);
        tableBank1Income.SetCellPosition(lblCreditCard, tlStdccLbl);
        tableBank1Income.SetCellPosition(lblCCError, tlStdccError);

        lblCCError.Visible = false;
        lblErrorLoanName.Visible = false;
        lblErrorLoanPayments.Visible = false;
    }

    private void SetupCreditCardsLayouts()
    {
        tableBank1Income.SetCellPosition(panelCreditCards, tlCCccList);
        tableBank1Income.SetCellPosition(lblCreditCard, tlCCccLbl);
        tableBank1Income.SetCellPosition(lblCCError, tlCCccError);

        tableBank1Income.SetCellPosition(txtTransactionGross, tlCCgrossTxt);
        tableBank1Income.SetCellPosition(lblTransactionAmount, tlCCgrossLbl);
        tableBank1Income.SetCellPosition(lblErrorTransactionGross, tlCCgrossError);

        tableBank1Income.SetCellPosition(txtTransactionNarrative, tlCCnarrativeTxt);  
        tableBank1Income.SetCellPosition(lblTransactionNarrative, tlCCnarrativeLbl);

        tableBank1Income.SetCellPosition(panelLoans, tlStdLoanLbl);
        tableBank1Income.SetCellPosition(lblLoans, tlStdLoanLbl);
        tableBank1Income.SetCellPosition(lblErrorLoanName, tlStdLoanError);

        tableBank1Income.SetCellPosition(cmbNumberOfLoanPayments, tlStdLoanPymntsCmb);
        tableBank1Income.SetCellPosition(lblLoanPayments, tlStdLoanPymntsLbl);
        tableBank1Income.SetCellPosition(lblErrorLoanPayments, tlStdLoanPymntsError);

     }

The code works by moving the controls that aren't needed to the bottom of the table and moving those that are needed up. That way there are no gaps in the table. e.g. I wouldn't want to just turn the visibility of Loan combobox on and off because then there would be a gap between the transaction type and narrative of two rows. I always want it as compact as possible.

Only problem with the current system is there are empty rows at the bottom containing invisible controls. It's also difficult to add rows as I have to go and change all the code which deals with moving stuff around.

Thanks for reading, if you go this far.

Have a >phew<

Thanks

The toggle controls methods aren't listed. They basically turn the controls that aren't need visibility on / off.

Best Answer

I find myself in similar situations occasionally and prefer a less messy approach:

  1. First of all, your screenshot seems to indicate that one column would suffice, as the width of the first column is already "fixed" with the long label "Transaction Amount (Gross)". So remove one column.
  2. Put each Label/TextBox pair into its own (regular) Panel. So one Panel per row. (Since the left "column" width is fixed, you can make all Panels the same width and make sure the TextBoxes align.)
  3. Add all Panels to the TableLayoutPanel.
  4. Set the hight of all rows of the TableLayoutPanel to "auto size". Set AutoSize=true and AutoSizeMode=GrowAndShrink for the TableLayoutPanel.

To adjust the layout of your form, you now only need to set the Visible-property of the 9 Panels. If a Panel gets hidden, the entire row of the table layout will disappear because of the AutoSizing rows and the other rows will move up. Same if you make a new row appear. So the layout is automated, you only need to decide which row to show.

Also, the TableLayoutPanel will now shrink to its content. If you like, you can now also mess around with the AutoSize* properties of the containing form to make the form auto size, but be careful to avoid annoying your users with this behaviour. You could also handle the SizeChanged event of the TableLayoutPanel to adjust the size of your form as necessary.

I hope that my description is comprehensible, otherwise feel free to ask for details.