none
DataGridViewComboBoxCell Data Binding

    Question

  • I am binding a datagridview to a SortedDictionary<int,vField>

    where vfield has a number of string and int properties.

     

    One of the colums in the grid corresponding to the Control_type property needs to be a

    DataGridViewComboBoxCell that is populated differently on every row based on the value of a different property in that row. I do this in the datagrid_databindingComplete handler as follows.

     

    void dgFields_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)

    {

    for (int i = 0; i < dgFields.Rows.Count; i++)

    {

    DataGridViewComboBoxCell comboCell = (DataGridViewComboBoxCell)dgFields.RowsIdea.Cells["controlTypeDataGridViewTextBoxColumn"];

    DataGridViewTextBoxCell TextCell = (DataGridViewTextBoxCell)dgFields.RowsIdea.Cells["FieldTypeDataGridViewTextBoxColumn"];

    comboCell.DataSource = getControlTemplateList(Control_Templates_ByType[(int)TextCell.Value]);

    comboCell.ValueMember = "Key";

    comboCell.DisplayMember = "Value";

     

    }

    }

     

    This works well as the grid shows the correct comboboxes one each of the rows with the appropriate values selected.

    The problem is that if you change the value of the combo box the new value is not reflected in the underlying datasource. All of the other changes to field values are properly reflected in the underlying datasource.

     

    can anyone tell me how to get the datasource to reflect the changes.

     

    thanks

     

    Randy

    Tuesday, July 22, 2008 9:18 PM

All replies

  • Hi Randy,

     

    I performed a test on this issue but didn't reproduce the problem on my side. The following is the walkthrough of my test.

    1. Create a WinForm application project and add a DataGridView on the Form1.

    2. Add a DataGridViewTextBoxColumn and a DataGridViewComboBoxColumn into the DataGridView. Add a Button on the Form1.

    3. Add the following code in the Form1's code file.

     

    public partial class Form1 : Form
        {
            DataTable table = new DataTable();
            SortedDictionary<int,List<Category>> dictionary;

            public Form1()
            {
                InitializeComponent();
                this.dataGridView1.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(dataGridView1_DataBindingComplete);
            }      
           
            void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
            {
                for (int i = 0; i < this.dataGridView1.Rows.Count; i++)
                {
                    DataGridViewComboBoxCell cboCell = this.dataGridView1.RowsIdea.Cells[1] as DataGridViewComboBoxCell;
                    DataGridViewTextBoxCell txtCell = this.dataGridView1.RowsIdea.Cells[0] as DataGridViewTextBoxCell;
                    if (txtCell.Value != null)
                    {
                        cboCell.DataSource = dictionary[(int)txtCell.Value];
                        cboCell.ValueMember = "ID";
                        cboCell.DisplayMember = "Name";
                    }
                }
            }
          
            private void Form1_Load(object sender, EventArgs e)
            {
                // populate dictionary
                dictionary = new SortedDictionary<int, List<Category>>();
                dictionary.Add(1,new List<Category>(new Category[] {new Category(11,"aa"),new Category(12,"bb")}));
                dictionary.Add(2,new List<Category>(new Category[]{new Category(21,"cc"),new Category(22,"dd")}));
                dictionary.Add(3,new List<Category>(new Category[]{new Category(31,"ee"),new Category(32,"ff")}));
               
                // add columns into the table
                DataColumn col = new DataColumn("ID", typeof(int));
                table.Columns.Add(col);
                col = new DataColumn("type", typeof(int));
                table.Columns.Add(col);

                // populate the table
                DataRow row = table.NewRow();
                row[0] = 1;
                table.Rows.Add(row);

                row = table.NewRow();
                row[0] = 2;
                table.Rows.Add(row);

                row = table.NewRow();
                row[0] = 3;
                table.Rows.Add(row);

                table.AcceptChanges();
               
                // bind the dataGridView1 to the table
                this.dataGridView1.AutoGenerateColumns = false;
                this.dataGridView1.Columns[0].DataPropertyName = "ID";
                this.dataGridView1.Columns[1].DataPropertyName = "type";
                this.dataGridView1.DataSource = table;
            }
            // print out the values of the second column in the table
            private void button1_Click(object sender, EventArgs e)
            {

                BindingContext[table].EndCurrentEdit();
                for (int i = 0; i < this.table.Rows.Count; i++)
                {
                    Console.WriteLine("row" + i.ToString() + " " + table.RowsIdea[1].ToString());
                }
            }
        }

        class Category
        {
            private int id;
            private string name;
            public int ID
            {
                get { return id; }
                set { id = value; }
            }
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
            public Category(int id, string name)
            {
                this.id = id;
                this.name = name;
            }
        }

     

    Build and run the application. Select a value from the DataGridViewComboBoxColumn and click the button.The values in the second column within the table will be printed to the Output window. On my side, the values selected from the DataGridViewComboBoxColumn are reflected to the table.

     

    Please try my sample code to see if you get the same result.

     

    Thanks,

    Linda

    Friday, July 25, 2008 4:18 AM
  • Thanks Linda,

    Your code does work. The only difference between your code and mine is that you use a datatable as the datasource of the grid. I am using a sorted dictionary of a custom class as the datasource for my grid. something like this:

     

    The class looks something like this:

    public class FormField{

     

    private int _Field_ID;

    private int _sublistingid;

    private int _Field_Type;

    private string _Field_DB_Name;

    private string _Title;

    private string _Description;

    ...

     

    public int Field_ID

    {

    get { return _Field_ID; }

    set { _Field_ID = value; }

    }

    public int sublistingid

    {

    get { return _sublistingid; }

    set { _sublistingid = value; }

    }

    public int Field_Type

    {

    get { return _Field_Type; }

    set { _Field_Type = value; }

    }

    public string Field_DB_Name

    {

    get { return _Field_DB_Name; }

    set { _Field_DB_Name = value; }

    }

    public string Title

    {

    get { return _Title; }

    set { _Title = value; }

    }

    public string Description

    {

    get { return _Description; }

    set { _Description = value; }

    }

    }

     

    and the datasource is a

     

    SortedDictionary<int,FormField>

     

    all other fields are updated except the field with the combobox.

     

     

    thanks

    again

     

    Friday, July 25, 2008 12:09 PM
  •  

    Hi Randy,

    Thanks for your feedback. I am a little confused about your problem. Usually we bind the DataGridView to a IList object, since SortedDictionary Generic Class does not implement the IList interface, we cannot bind DataGridView to SortedDictionary instance directly. Generally, we use a BindingSource to bind a SortedDictionary object to the DataGridView control, but it doesn’t allow us to change the values in the DataGridView control. I think the problem might relate to how you bind the SortedDictionary instance to DataGridView control. Could you please show us how you bind SortedDictionary instance to DataGridView control?

    Thanks.
    Rong-Chun Zhang

    Windows Forms General FAQs
    Windows Forms Data Controls and Databinding FAQs

    Monday, July 28, 2008 11:09 AM
  • Sorry about that I oversimplified my description. here is how I databind the sorted dictionary.

     

    dgFields.DataSource = new BindingSource(Form_Fields.Values,null);

     

    where Form_Fields is defined as:

    SortedDictionary<int,Form_Field> Form_Fields;

     

    which works and produces the expected results as far as showing the grid.

    in fact the changed values in the grid are reflected back into the Form_Fields except for the combobox field.

     

    Thanks

    Randy

    Monday, July 28, 2008 12:42 PM
  •  

    Hi Randy,

    Thanks for your feedback, and I performed a test which binding the DataGridView control to a SortedDictionary object. The testing code is similar to Linda’s sample; I just replace the DataTable with a SortedDictionary instance and add three columns (the third column is DataGridViewComboBoxColumn) to DataGridView control.  When I ran the application, it worked well on my machine.

    Code Snippet

        public partial class Form27 : Form

        {

            public Form27()

            {

                InitializeComponent();

                this.dataGridView1.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(dataGridView1_DataBindingComplete);

            }

     

            SortedDictionary<int, Product> list;

            SortedDictionary<int, List<Category>> dictionary;

            BindingSource bs;

     

            void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)

            {

                for (int i = 0; i < this.dataGridView1.Rows.Count; i++)

                {

                    DataGridViewComboBoxCell cboCell = this.dataGridView1.Rows[i].Cells[2] as DataGridViewComboBoxCell;

                    DataGridViewTextBoxCell txtCell = this.dataGridView1.Rows[i].Cells[0] as DataGridViewTextBoxCell;

                    if (txtCell.Value != null)

                    {

                        cboCell.DataSource = dictionary[(int)txtCell.Value];

                        cboCell.ValueMember = "ID";

                        cboCell.DisplayMember = "Name";

                    }

                }

            }

     

            private void Form27_Load(object sender, EventArgs e)

            {

                // populate dictionary

                dictionary = new SortedDictionary<int, List<Category>>();

                dictionary.Add(1, new List<Category>(new Category[] { new Category(11, "aa"), new Category(12, "bb") }));

                dictionary.Add(2, new List<Category>(new Category[] { new Category(21, "cc"), new Category(22, "dd") }));

                dictionary.Add(3, new List<Category>(new Category[] { new Category(31, "ee"), new Category(32, "ff") }));

     

                // populate the list

                list = new SortedDictionary<int, Product>();

                Product prod = new Product();

                prod.Id = 1;

                prod.Name = "Name1";

                prod.Category = 11;

                list.Add(1, prod);

     

                prod = new Product();

                prod.Id = 2;

                prod.Name = "Name2";

                prod.Category = 21;

                list.Add(2, prod);

     

                prod = new Product();

                prod.Id = 3;

                prod.Name = "Name3";

                prod.Category = 32;

                list.Add(3, prod);

     

                bs = new BindingSource(list.Values,null);

     

                // bind the dataGridView1 to the table

                this.dataGridView1.AutoGenerateColumns = false;

                this.dataGridView1.Columns[0].DataPropertyName = "Id";

                this.dataGridView1.Columns[1].DataPropertyName = "Name";

                this.dataGridView1.Columns[2].DataPropertyName = "Category";

                this.dataGridView1.DataSource = bs;

            }

     

            private void button1_Click(object sender, EventArgs e)

            {

                BindingContext[bs].EndCurrentEdit();

                for (int i = 1; i <= this.bs.Count; i++)

                {

                    Console.WriteLine("Product:" + list[i].Id + " " + list[i].Name + " " + list[i].Category.ToString());

                }

            }

        }

     

        class Category

        {

           // Category is the same as Linda's

        }

     

        class Product

        {

            int id;

            public int Id

            {

                get { return id; }

                set { id = value; }

            }

     

            string name;

            public string Name

            {

                get { return name; }

                set { name = value; }

            }

     

            int category;

            public int Category

            {

                get { return category; }

                set { category = value; }

            }

        }

     

    Let me know if this helps, if not, could you please show how you bind DataGridViewComboBoxCell in the DataBindingComplete event handler?

    Best regards.
    Rong-Chun Zhang

    Windows Forms General FAQs
    Windows Forms Data Controls and Databinding FAQs

    Tuesday, July 29, 2008 8:04 AM
  • Thanks Linda,

    It works for me.


    ~Vivek
    Tuesday, January 25, 2011 9:56 AM