Adding/Removing/Selecting Values of ComboBox in DatagridView

Caddy picture Caddy · Apr 25, 2012 · Viewed 8.3k times · Source

I'm attempting to automate a data processing task for files of various formats and fields. I've created a program that determines the delimiter of a delimited file, and loads a chunk of the file into a DataGridView on a form, so that the user can confirm some fields of the file before the file is bulk loaded into a SQL table. The table will be created on the fly, using some of the field names the user has selected in a combobox in the datagrid.

That's my goal, but I'm not sure I'm approaching the problem correctly.

At this point, I've created a BindingSource for the comboboxes ...

BindingSource bindingSource = new BindingSource();

Here I show the DataGridView of the selected file, adding a column for each field in the data file

    private void ShowDataGridView(string file, string delimiter, string[] fieldNames, string[] fieldLengths)
    {
        StreamReader fileReader = new StreamReader(file);
        if (bindingSource.Count == 0)
        {
            bindingSource.Add("FIRSTNAME");
            bindingSource.Add("LASTNAME");
            bindingSource.Add("ADDRESS1");
            bindingSource.Add("ADDRESS2");
            bindingSource.Add("CITY");
            bindingSource.Add("STATE");
            bindingSource.Add("ZIP");
            bindingSource.Add("COMPANY");
            bindingSource.Add("EMAIL");
            bindingSource.Add("");
        }           
        dataGridView1.Rows.Clear();
        dataGridView1.Columns.Clear();
        int count = 0;
        for (int i = 0; i < 17; i++)  //read 17 lines into datagridview for field confirmation, 17 lines just so happens to fill my datagridview nicely, last row will be combobox for field name selection
        {
            string[] fields = StringFunctions.Split(fileReader.ReadLine(), delimiter, Convert.ToString("\""));
            count = fields.Count();
            if (i == 0)
            {
               // Adding Column Header to DataGridView
                for (int x = 0; x < count; x++)
                {
                    DataGridViewTextBoxColumn columnDataGridTextBox = new DataGridViewTextBoxColumn();
                    columnDataGridTextBox.Name = fieldNames[x];
                    columnDataGridTextBox.HeaderText = fieldNames[x];
                    dataGridView1.Columns.Add(columnDataGridTextBox);
                }
            }
            dataGridView1.Rows.Add(fields);
        }

        for (int x = 0; x < count; x++)
        {
            DataGridViewComboBoxCell combobox = new DataGridViewComboBoxCell();             
            combobox.DataSource = bindingSource;
            dataGridView1[x, 16] = combobox;  //remember 17 rows added, combobox will be last row in datagridview
            combobox = null;
        }
        dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

        fileReader.Close();
        fileReader = null;
    }

Okay, so now I have a view of the data, and comboboxes for all fields of the data. Certain fields are mandatory, (the BindingSource field names) I want the user to be able to select the appropriate field name for the column of data from the combobox. When the user has selected a field from the combobox, I want to remove that field name from the BindingSource, so user can't select same field name for another column. The remaining fields will have default field names eg (FirstName,Field2,LastName,Address1, Field5, Field6,Address2 etc)

Combobox is where I'm having problems :)

I've searched for code snippets and I'm making some progress, but I could use some advice from someone who has a better grasp of datagridview events and how to handle them. I don't really know what I'm doing, just flinging stuff on the wall to see if it sticks. The following is what I've tried so far ...

InitializeComponent();
dataGridView1.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(DataGridViewEditingControlShowing);

private void DataGridViewEditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
    {
        //here we will add the combo box's selected event changed 
        ComboBox cmbBox; 
        if (dataGridView1.CurrentCell is DataGridViewComboBoxCell)
        { 
            cmbBox = e.Control as ComboBox; 
            if (cmbBox == null)
                return; 
            cmbBox.SelectedIndexChanged += cmbBox_SelectedIndexChanged; 
        }
    }

    //This will display value of Select values of Combo Box 
    //which is DataGridView
    void cmbBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        ComboBox cmbBox = (ComboBox)sender;
        if (cmbBox.SelectedValue != null)
        {
            MessageBox.Show(cmbBox.SelectedValue.ToString());  //testing
            bindingSource.Remove(cmbBox.SelectedValue);   //this removes it from the current combobox as well, no good.  Also run time error when clicking into a different combobox
        }          
    }

I hope I've been descriptive enough and posted enough code to give any possible code guru helpers a feel for what I'm trying to accomplish. If more information is needed, please let me know. Any ideas/solutions are greatly appreciated.

Thanks!

Answer

Dave Swersky picture Dave Swersky · Apr 25, 2012

You're on the right track, but for this to work I think each combobox will need its own datasource, so they can be manipulated individually. If they all share the same source, they can't have different contents, which is what you want (selecting X from combobox A should remove that from all other comboboxes.)

In your loop where you create the comboboxes, "clone" the datasource so they each have their own.