Different ComboBox in Each Row of DataGridView

Hi,

Can I have a ComboBoxColumn in a DataGridView with different items in the ComboBox of each row?

For instance, suppose there’s a DataGridView in a Windows Form with rows of customer info. There’s a column that shows the gender and a ComboBoxColumn to set the title. If the customer is male, the ComboBox will contain “Mr”, “Dr” etc, otherwise, it will have “Miss”, “Mrs” etc.

How can this be done?

I saw this post but can’t quite understand what it means.

http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3311173&SiteID=1

Thanks,

Your Ad Here

8 Solutions Found

Solution 1

Perhaps http://www.timvw.be/exploring-datagridviewcomboboxcolumn-databinding/  and http://www.timvw.be/exploring-datagridviewcomboboxcolumn-databinding-part2/ can inspire you…

Solution 2

Hi Ywb,

The function you want can be called “cascade combo boxes”, i.e. there’re two combo boxes and the items of the second combo box depend on the selected item of the first combo box.

The basic way to implement cascade combo boxes in a data grid view is to handle the EditingControlShowing and CellValueChanged event of the DataGridView.

In the EditingControlShowing event handler, if the column in question is the second DataGridView Combobox column, change the data source of the editing control (DataGridViewComboBoxEditingControl) to another data source and filter the new data source.

In the CellValueChanged event handler, if the cell value under the first DataGridView Combobox column is changed, clear the cell value under the second DataGridView Combobox column in the same row.

The following is a sample. It requires that you add a DataGridView on the form and add two DataGridViewComboBoxColumns into the DataGridView named “regionComboBoxColumn” and “territoryComboBoxColumn” respectively.

public class ViewData     {         private int m_Region;         private int m_Territory;

        public ViewData(int Region, int Territory)         {             m_Region = Region;             m_Territory = Territory;         }

        public int RegionID         {             get { return m_Region; }             set  { m_Region = value; }         }

        public int TerritoryID         {             get { return m_Territory; }             set { m_Territory = value; }         }     }

// code in Form1.cs

public partial class Form1: Form     {         public List<ViewData> m_DataList;

        DataSet RegionsTerritories = new DataSet();         DataTable regiontable = new DataTable("RegionTable");         DataTable territorytable = new DataTable("TerritoryTable");         BindingSource parentBS = new BindingSource();         BindingSource childBS = new BindingSource();         BindingSource filteredChildBS = new BindingSource();         public FilterByCell()         {             InitializeComponent();                        this.Load += new EventHandler(FilterByCell_Load);             this.dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);             this.dataGridView1.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing);             this.dataGridView1.DataError += new DataGridViewDataErrorEventHandler(dataGridView1_DataError);         }

        void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)         {             if (e.ColumnIndex != territoryComboBoxColumn.Index)             {                 MessageBox.Show("Data error occurs:" + e.Exception.Message);             }         }      

        void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)         {                       if (this.dataGridView1.CurrentCell.ColumnIndex == territoryComboBoxColumn.Index)             {                 DataGridViewComboBoxEditingControl control = e.Control as DataGridViewComboBoxEditingControl;                 BindingSource bs = control.DataSource as BindingSource;                 if (bs != null)                 {                                       // set the filteredChildBS as the DataSource of the editing control                     (e.Control as ComboBox).DataSource = filteredChildBS;                   

                    object regionvalue = this.dataGridView1.Rows[this.dataGridView1.CurrentCell.RowIndex].Cells[regionComboBoxColumn.Index].Value;                     if (regionvalue DBNull.Value || regionvalue null)                     {                         filteredChildBS.Filter = "RegionID=-1";                     }                     else                     {                         filteredChildBS.Filter = "RegionID=" + regionvalue.ToString();                     }                     // set the SelectedValue property of the editing control                     if (this.dataGridView1.CurrentCell.Value != DBNull.Value && this.dataGridView1.CurrentCell.Value != null)                     {                                               control.SelectedValue = this.dataGridView1.CurrentCell.Value;                                                        }                 }             }         }

        void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)         {             if (e.ColumnIndex regionComboBoxColumn.Index)             {                 // clear the cell value of the territory column in the same row                 if (this.dataGridView1.DataSource.GetType() typeof(DataTable))                 {                     this.dataGridView1.Rows[e.RowIndex].Cells[territoryComboBoxColumn.Index].Value = DBNull.Value;                 }                 else                 {                     this.dataGridView1.Rows[e.RowIndex].Cells[territoryComboBoxColumn.Index].Value = null;                 }             }         }         void FilterByCell_Load(object sender, EventArgs e)         {             // add columns in the Region table                      DataColumn col = new DataColumn("RegionID", typeof(int));             regiontable.Columns.Add(col);             col = new DataColumn("RegionDescription");             regiontable.Columns.Add(col);

            // add columns in the Territory table             col = new DataColumn("TerritoryID", typeof(int));             territorytable.Columns.Add(col);             col = new DataColumn("TerritoryDescription");             territorytable.Columns.Add(col);             col = new DataColumn("RegionID", typeof(int));             territorytable.Columns.Add(col);

            // add the two tables to the dataset             RegionsTerritories.Tables.Add(regiontable);             RegionsTerritories.Tables.Add(territorytable);

            // add some rows  in the region table             DataRow row  = RegionsTerritories.Tables["RegionTable"].NewRow();             row[0] = 3;             row[1] = "region 3";             RegionsTerritories.Tables["RegionTable"].Rows.Add(row);

            row = RegionsTerritories.Tables["RegionTable"].NewRow();             row[0] = 2;             row[1] = "region 2";             RegionsTerritories.Tables["RegionTable"].Rows.Add(row);

            // add some rows in the Territory table             row = RegionsTerritories.Tables["TerritoryTable"].NewRow();             row[0] = 44122;             row[1] = "terri 44122";             row[2] = 3;             RegionsTerritories.Tables["TerritoryTable"].Rows.Add(row);

            row = RegionsTerritories.Tables["TerritoryTable"].NewRow();             row[0] = 53404;             row[1] = "terri 53404";             row[2] = 3;             RegionsTerritories.Tables["TerritoryTable"].Rows.Add(row);

            row = RegionsTerritories.Tables["TerritoryTable"].NewRow();             row[1] = "terri 60601";             row[2] = 2;             row[0] = 60601;             RegionsTerritories.Tables["TerritoryTable"].Rows.Add(row);

            row = RegionsTerritories.Tables["TerritoryTable"].NewRow();             row[0] = 94105;             row[1] = "terri 94105";             row[2] = 2;             RegionsTerritories.Tables["TerritoryTable"].Rows.Add(row);          

            // set up ParentBS and ChildBS and filteredChildBS             parentBS.DataSource = RegionsTerritories;             parentBS.DataMember = "RegionTable";

            childBS.DataSource = RegionsTerritories;             childBS.DataMember = "TerritoryTable";

            filteredChildBS.DataSource = RegionsTerritories;             filteredChildBS.DataMember = "TerritoryTable";

            // bind the regionComboBoxColumn to the parentBS             this.regionComboBoxColumn.DataSource = parentBS;             this.regionComboBoxColumn.DisplayMember = "RegionDescription";             this.regionComboBoxColumn.ValueMember = "RegionID";

            // bind the territoryComboBoxColumn to the childBS             this.territoryComboBoxColumn.DataSource = childBS;             this.territoryComboBoxColumn.DisplayMember = "TerritoryDescription";             this.territoryComboBoxColumn.ValueMember = "TerritoryID";

            // Bound to a datatable             DataTable dtViewData = new DataTable("ViewData");             dtViewData.Columns.Add("RegionID", typeof(Int32));             dtViewData.Columns.Add("TerritoryID", typeof(Int32));             DataRow dr = dtViewData.NewRow();             dr["RegionID"] = 3;             dr["TerritoryID"] = 44122;             dtViewData.Rows.Add(dr);             dr = dtViewData.NewRow();             dr["RegionID"] = 2;             dr["TerritoryID"] = 60601;             dtViewData.Rows.Add(dr);

            dataGridView1.AutoGenerateColumns = false;             dataGridView1.DataSource = dtViewData;             dataGridView1.Columns[0].DataPropertyName = "RegionID";             dataGridView1.Columns[1].DataPropertyName = "TerritoryID";

         }          }

Hope this helps.

If you have any question, please feel free to let me know.

Thanks,

Linda

Solution 3

Thanks Linda, it works perfect. Daniyal

Solution 4

I have a datagridview  with some columns editable and others non editable. I have a state column  and Country column. Country column is non editable. Based on the country name its states should be populated in States Comboboxcolumn. How can that be implemented?

Solution 5

i read your code about Cascade combobox  in DatagridView  in here. I Configure the code in VB.net according to My Project… I Give You Exactly My Code As it is.. DATAGRIDVIE = Flights_PrsonnelDatagridView Two ComboBoxes (First In Column2 and Second In column  3) The Code Works Properly and  i have a button Save that update the Flights_PersonnelTableAdapter.. The Data Saved Succesfully… The Problem is that After Update Some Values Of the Filtered COmbobox dissapears although they were Stored in my SQL Table.. When I close the form  and open it again the data of the filtered combobox are dislplayed Correctly..What is going on? Please if can help me guide me, to solve my problem..thank you Private Sub Flights_PersonnelDataGridView_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles Flights_PersonnelDataGridView.CellValueChanged If e.ColumnIndex = FLPComboBoxColumn.Index Then ‘ clear the cell value of the territory column in the same row If Me.Flights_PersonnelDataGridView.DataSource.[GetType]() Is GetType(DataTable) Then Me.Flights_PersonnelDataGridView.Rows(e.RowIndex).Cells(CrewComboBoxColumn.Index).Value = DBNull.Value ‘ Else ‘ Me.Flights_PersonnelDataGridView.Rows(e.RowIndex).Cells(3).Value = Nothing End If End If End Sub Private Sub Flights_PersonnelDataGridView_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles Flights_PersonnelDataGridView.EditingControlShowing If Me.Flights_PersonnelDataGridView.CurrentCell.ColumnIndex = CrewComboBoxColumn.Index Then Dim control As DataGridViewComboBoxEditingControl = TryCast(e.Control, DataGridViewComboBoxEditingControl) Dim bs As BindingSource = TryCast(control.DataSource, BindingSource) If bs IsNot Nothing Then ‘ set  the filteredChildBS as the DataSource of the editing control TryCast(e.Control, ComboBox).DataSource = SelectAllPersonnel4CrewBindingSource Dim Positionnvalue As Object = Me.Flights_PersonnelDataGridView.Rows(Me.Flights_PersonnelDataGridView.CurrentCell.RowIndex).Cells(FLPComboBoxColumn.Index).Value If IsDBNull(Positionnvalue) OrElse Positionnvalue Is Nothing Then SelectAllPersonnel4CrewBindingSource.Filter = “Key_positions=-1” Else SelectAllPersonnel4CrewBindingSource.Filter = “Key_positions=” & Positionnvalue.ToString() End If ‘ set the SelectedValue property of the editing control If Not IsDBNull(Me.Flights_PersonnelDataGridView.CurrentCell.Value) AndAlso Me.Flights_PersonnelDataGridView.CurrentCell.Value IsNot Nothing Then control.SelectedValue = Me.Flights_PersonnelDataGridView.CurrentCell.Value End If End If End If End Sub Private Sub Flights_PersonnelDataGridView_DataError(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewDataErrorEventArgs) Handles Flights_PersonnelDataGridView.DataError If e.ColumnIndex <> CrewComboBoxColumn.Index Then MessageBox.Show(“Data error occurs:” & e.Exception.Message) End If End Sub

Solution 6

Hi Linda, Your cascade combo code is nice solution. I tried to run it but I found the bs null after using control.DataSource as BindingSource. void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)         {                       if (this.dataGridView1.CurrentCell.ColumnIndex territoryComboBoxColumn.Index)             {                 DataGridViewComboBoxEditingControl control = e.Control as DataGridViewComboBoxEditingControl;                 BindingSource bs = control.DataSource as BindingSource; <===== problem found there                 if (bs != null)                 {                            //doing important things                 } Can you help me out? Thanks, Wilson

Solution 7

Hi Linda, Your cascade combo code is a nice solution. I tried to run it but I found the bs null after using control.DataSource as BindingSource. void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)         {                       if (this.dataGridView1.CurrentCell.ColumnIndex territoryComboBoxColumn.Index)             {                 DataGridViewComboBoxEditingControl control = e.Control as DataGridViewComboBoxEditingControl;                 BindingSource bs = control.DataSource as BindingSource; <===== problem found there                 if (bs != null)                 {                            //doing important things                 } Can you help me out? Thanks, Wilson

Hi Wilson,

I know your post  is old, but if anyone else gets your problem the solution is to:

1. Open the form

2. Right-click on the DataGridView

3. choose Edit Columns

4. Under the Region/Territory columns you need to specify ComboBox type columns (and set  the data source)

Hi Linda,

The class ViewData and the public List<ViewData> m_DataList are not needed, please do show how you use this.

Solution 8

Your problem I think is you don’t have a unique ID in your ChildBS. So when the line: control.SelectedValue = Me.Flights_PersonnelDataGridView.CurrentCell.Value is the test, the control.SelectedValue checks the first ID that equals the CurrentCell.Value from the filtered BindingSource.