Why do Items from one comboBox not copy to another

2019-09-02 10:35发布

问题:

I have multiple comboboxes on a tabpage on a tabcontrol on a form. Trying to loop through the controls has not worked (see this).

So, I tried to go at it from another angle: finding the controls based on their name. As an initial POC, I just wanted to brute force it by providing the name of one of the combo boxes that is empty at design time ("cmbxRow0Element1") and assign the items from cmbxRow0Element0 to it. But both this attempt:

Control ctrl = this.Controls["cmbxRow0Element1"];
ComboBox cmbx = ctrl as ComboBox;
var items = cmbxRow0Element0.Items.OfType<object>().ToArray();
cmbx.Items.Add(items);

...and this one:

Control ctrl = this.Controls["cmbxRow0Element1"];
ComboBox cmbx = ctrl as ComboBox;
foreach (Object item in cmbxRow0Element0.Items)
{
    cmbx.Items.Add(item);
}

...result in "System.NullReferenceException was unhandled _HResult=-2147467261 _message=Object reference not set to an instance of an object."

...on the call to cmbx.Items.Add()

Why???

I want it to eventually be something like:

string cmbxName;
int cmbxCount = getCountOfComboBoxes();
for (int i = 0; i < cmbxCount; i++)
{
    cmbxName = string.Format("cmbxRow0Element{0}", i);
    Control ctrl = this.Controls[cmbxName];
    ComboBox cmbx = ctrl as ComboBox;
    cmbx.Items.Add("Twain");
    cmbx.Items.Add("Steinbeck");
    cmbx.Items.Add("Saroyan");
    cmbx.Items.Add("Frost");
    cmbx.Items.Add("Hardy");
    cmbx.Items.Add("Stegner");
}

回答1:

Because cmbxRow0Element1 is not direct child element of your Form. Use NameOfYourTabControl.Controls["cmbxRow0Element1"], or more generally:

this.Controls.SelectMany(x => x.Controls).First(x => x.Name == "cmbxRow0Element1");


回答2:

This is a work-in-progress, but it is functional:

string cmbxName;
int cmbxCount = getCountOfComboBoxes();
for (int i = 0; i < cmbxCount; i++)
{
    cmbxName = string.Format("cmbxRow0Element{0}", i);
    Control ctrl = this.tabPage1.Controls[cmbxName];
    ComboBox cmbx = ctrl as ComboBox;
    cmbx.Items.Add("Christopher Robbin");
    cmbx.Items.Add("Eeyore");
    cmbx.Items.Add("Kanga");
    cmbx.Items.Add("Owl");
    cmbx.Items.Add("Piglet");
    cmbx.Items.Add("Rabbit");
    cmbx.Items.Add("Roo");
    cmbx.Items.Add("Tigger (T-I-Double Guh-Er)");
    cmbx.Items.Add("Winnie-the-Pooh");
}

The initial problem was that this/the form could not see what was on the tab pages; even the tab Control did not. I had to get specific with a particular tab*Page* for it to work.

UPDATE

Here is a better version - still could use null-checking and other niceties:

// Names of comboboxes are of the pattern "cmbxRowNElementN" the first N runs from 0..11, the second from 0..5
// This assume that you really do have twelve tabPages named tabPageRow0...tabPageRow11, and that there are six comboboxes on each tabpage 
const int TABPAGE_COUNT = 12;
const int COMBOXES_PER_TABPAGE = 6;
string tabPageBaseName = "tabPageRow";
List<String> MilneMilieu = new List<string>() { "Christopher Robin", "Eeyore", "Kanga", "Owl", "Piglet", "Rabbit", "Roo", "Tigger (T, I, Double-Guh, Er)", "Winnie-the-Pooh" };
string tabPageName;
string cmbxName;

try
{
    for (int i = 0; i < TABPAGE_COUNT; i++)
    {
        tabPageName = string.Format("{0}{1}", tabPageBaseName, i);
        Control tabpageCtrl = this.tabControl1.Controls[tabPageName];
        TabPage tp = tabpageCtrl as TabPage;

        for (int j = 0; j < COMBOXES_PER_TABPAGE; j++)
        {
            cmbxName = string.Format("cmbxRow{0}Element{1}", i, j);
            Control cmbxCtrl = tp.Controls[cmbxName];
            ComboBox cmbx = cmbxCtrl as ComboBox;
            // While we're at it, hook it to the shared event handler (although doing this violates the "S" in SOLID)
            cmbx.SelectionChangeCommitted += cmbxRow0Element0_SelectionChangeCommitted;
            foreach (var imaginaryFriend in MilneMilieu)
            {
                cmbx.Items.Add(imaginaryFriend);
            }
        }
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.ToString());
}