简体   繁体   中英

How can I to manipulate dynamically created controls?

Lets say I have a form where someone can catalog a multiple people's Name and their State and City?

Assume I already have all the State/Cities in database. (a table for each state, with cities listed in each table)

The Name field will be a TextBox. And the State & City fields will be ComboBox (DropDownLists).

One row (for the entry of one person) already exists in the form. But I want the user to be able to dynamically add rows of entries by pressing an "Add Person" button.

The next step is where I'm struggling. In each dynamically added row of fields, I would like the second ComboBox (Cities) to be populated depending on which State is chosen in the first Combo Box. Also, the Cities ComboBox will remain disabled until the State ComboBox is chosen.

My code looks something like this:

    public ComboBox cbState;
    public ComboBox cbCities;
    public static int NumberOfPeople = 1;


    private void btnAddNewPerson_Click(object sender, EventArgs e)
    {

        NumberOfPeople++;

        TextBox txtPerson = new TextBox();
        txtPerson.Name = "Person" + NumberOfPeople;
        Panel.Controls.Add(txtPerson);

        //  ADD State ComboBox
        cbState = new ComboBox();
        cbState.Name = "State" + NumberOfPeople;
        cbState.Enabled = true;
        cbState.DropDownStyle = ComboBoxStyle.DropDownList;
        Panel.Controls.Add(cbState);

        //  ADD City ComboBox
        cbCity = new ComboBox();
        cbCity.Name = "City" + NumberOfPeople;
        cbCity.DropDownStyle = ComboBoxStyle.DropDownList;
        cbCity.Enabled = false;
        cbCity.SelectedValueChanged += new System.EventHandler(this.ChangeState);
        Panel.Controls.Add(cbCity);

    }

    private void ChangeState(object sender, EventArgs e)
    {

       ..... Don't know how to properly identify the City ComboBox that is in the same row as the State ComboBox that was just changed, and manipulate/populate it.....

    }

Anyone able to help me solve this issue??

I'd greatly appreciate it!!

First of all you should find the name of the comboBox you want to manipulate.

then you can search a control in the panel which has the name we just found, then you can do what ever you want.

here is the code for that

    private void ChangeState(object sender,EventArgs e){
        ComboBox stateComboBox= (ComboBox)sender;
        //find the name of target City ComboBox
        string cityComboName = "City"+stateComboBox.Name.Substring(5); // 5 is the Length of 'State'
        ComboBox cityComboBox=null;
        foreach(Control cntrl in panel1.Controls){
            if (cntrl.Name == cityComboName) {
                cityComboBox= (ComboBox)cntrl;
                break;
            }
        }
        if (cityComboBox!= null) {
            cityComboBox.Enabled = true;
            // now you have the both cityComboBox and stateComboBox Of the same Row
        }
    }

You could use a dictionary

Dictionary<ComboBox,ComboBox> CityToStateMap = new Dictionary<ComboBox,ComboBox>();

then when you add a row

CityToStateMap[cbState] = cbCity;

then when you changestate

ComboBox city = CityToStateMap[(ComboBox)sender];

First of all I would create an additional class (eg with name Row) that contains all controls of one row. So you can encapsulate controls of one person in one object.
Your Form class gets a list member of such row objects like
List<Row> _rows = new List<Row>(); .

In constructor of that class Row you create the controls of one row and assign the event handlers to the SelectedValueChanged event of the combobox controls.

You could use the Control.Tag in order to attach a data object to your controls. See how the controls are introduced to each other in the example.

private void btnAddNewPerson_Click( object sender, EventArgs e )
{
    AddPersonRow();
}

private void AddPersonRow()
{
    // Create combo boxes
    ComboBox cbCity = new ComboBox();
    ComboBox cbState = new ComboBox();

    // Introduce them to each other
    cbCity.Tag = cbState;
    cbState.Tag = cbCity;

    //  ADD State ComboBox
    cbState.Name = "State" + NumberOfPeople;
    cbState.Enabled = true;
    cbState.DropDownStyle = ComboBoxStyle.DropDownList;
    cbState.SelectedValueChanged += new EventHandler( cbState_SelectedValueChanged );
    panel.Controls.Add( cbState );

    // Populate the states sombo
    PopulateStateCombo( cbState );

    //  ADD City ComboBox
    cbCity.Name = "City" + NumberOfPeople;
    cbCity.DropDownStyle = ComboBoxStyle.DropDownList;
    cbCity.Enabled = false;
    cbCity.SelectedValueChanged += new EventHandler(cbCity_SelectedValueChanged);
    panel.Controls.Add( cbCity );
}

void cbState_SelectedValueChanged( object sender, EventArgs e )
{
    ComboBox cbState = sender as ComboBox;
    ComboBox cbCity = cbState.Tag as ComboBox;

    cbCity.Enabled = true;

    // .. Go ahead and populate cbCity by cbState's selected value ..
}

void cbCity_SelectedValueChanged( object sender, EventArgs e )
{
    // Up to you...
}

Note that instead of shaking hands with each other ComboBox, you could create a class that will hold both ComboBoxes, your TextBox control, the row number, etc. and then set the Tag of all these controls to the class itself.

public class PersonRow
{
    public int RowNum { get; private set; }
    public TextBox NameTextBox { get; private set; }
    public ComboBox CityCombo { get; private set; }
    public ComboBox StateCombo { get; private set; }

    public PersonRow( int rowNum )
    {
        RowNum = rowNum;

        // Create the controls
        NameTextBox = new TextBox();
        CityCombo = new ComboBox();
        StateCombo = new ComboBox();

        // Bind them to this instance
        NameTextBox.Tag = this;
        CityCombo.Tag = this;
        StateCombo.Tag = this;

        //.. continue as in the prev. example..
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM