Robert Burke
Robert Burke

Reputation: 340

Moving controls from TabPage to Panel; controls being skipped

So everyone knows a very popular way to display settings now is to have a ListView on the left with options that changes a Panel on the right, when clicked.

Several years ago, I came across one way to easily manage this is to create a TabControl, put the controls for each settings category in the tab page during design time, because it makes it easy to switch tabs and edit the pages.

During run time, when the settings page is opened, you create Panels for each TabPage, move the controls from the TabPage to its corresponding panel and add the Text (title) of each TabPage into the ListView on the left. And then, if you want, you can destroy the TabControl to free up memory.

The problem I am having is that as my code iterates through the controls on a TabPage, it won't add some of them. In my case, they are all CheckBoxes at the moment, so I'm confused as to why some would not be moved. During debug, I can check TabPage.Controls and all CheckBoxes are there, but as it iterates, it just doesn't add some of the controls to the Panel.

I have an image of how I have this setup during DesignTime, what it looks like at RunTime, and what my code is that is handling the move from TabPages to Panels.

Does anyone have any ideas why this may be happening? I'm stumped.

DesignTime: http://postimg.org/image/h6ssw1chp/

RunTime: http://postimg.org/image/4i7f6uv05/

public void setPanels()
{
    foreach (TabPage tab in tabSettingGroups.TabPages)
    {
        Panel panel = new Panel()
        {
            Dock = DockStyle.Fill,
            Visible = true
        };

        ListViewItem lvi = new ListViewItem(tab.Text)
        {
            Tag = panel
        };
        lvwOptions.Items.Add(lvi);

        foreach (Control ctrl in tab.Controls)
        {
            panel.Controls.Add(ctrl);
        }
    }

    //Destroy TabControl to free up memory
    tabSettingGroups.Dispose();
}

If you would like to recreate everything, you need at least a SplitContainer, with the ListView in SplitContainer.Panel1 and the TabControl in SplitContainer.Panel2.

As you can see, I have added each built Panel that was created for each TabPage directly into the Tag property of the ListViewItem. When the ListViewItem is clicked, SplitContainer.Panel2 is emptied and the Panel from ListViewItem.Tag is added to SplitContainer.Panel2

private void lvwOptions_SelectedIndexChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
    pnlSettings.Panel1.Controls.Clear();
    Panel pnl = (Panel)e.Item.Tag;
    pnlSettings.Panel1.Controls.Add(pnl);
}

NOTE: I added a second SplitContainer to house the TabControl and the Save/Cancel buttons so that the buttons were inline with the Parent SplitContainer so that I didn't create even more unused "whitespace" to the left of the buttons. In the _Click method above, just do .Panel2 (basically, the same Panel that you put the TabControl).

Upvotes: 1

Views: 1466

Answers (1)

LarsTech
LarsTech

Reputation: 81675

The collection is changing while you iterate them, so a simple trick is to go in reverse:

for (int i = tab.Controls.Count - 1; i >= 0; --i) {
  panel.Controls.Add(tab.Controls[i]);
}

or the one-liner:

panel.Controls.AddRange(tab.Controls.Cast<Control>().ToArray());

As other users have commented, probably better to just house each view in a separate UserControl instead of trying to move these controls — it will lead to spaghetti code trying to manage all those changes.

Upvotes: 2

Related Questions