title: Automatically create DataGridViewComboBoxCell from object's collection property
body: <p>Using WinForms, I'm trying to write a method that checks if the data item bound to a row in a DataGridView contains an <code>IList</code> as a property and then automatically transforms the <code>DataGridViewTextBoxCell</code> into a <code>DataGridViewComboBoxCell</code> binding that list as a datasource. The objective is to have a dropdown menu with different values for each row depending on the elements in the list property of the object found. So for example in the first row the dropdown could have 3 objects of type <code>ObjA</code> as options, the second row could have 5 objects of type <code>ObjC</code>, and so on. </p>
  
  <p>This is what I have:</p>
  
  <pre><code>private void dgv_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
  {
      foreach (DataGridViewRow row in dgv.Rows)
      {
          object obj = row.DataBoundItem;
          if (obj != null)
          {
              IEnumerable listProperties = obj.GetType().GetProperties().Where(p =&gt; p.GetValue(obj) is IList);
              foreach (PropertyInfo list in listProperties)
              {
                  DataGridViewComboBoxCell cell = new DataGridViewComboBoxCell();
                  IList source = (IList)list.GetValue(obj, null);
                  cell.DataSource = source;
                  cell.ValueMember = "id";
                  cell.DisplayMember = "name";
                  cell.ValueType = source.GetType().GetProperty("Item").PropertyType;
                  cell.Value = source[0].GetType().GetProperty("id").GetValue(source[0]);
                  (row.Cells[list.Name]) = cell;
              }
          }
      }
  }
  </code></pre>
  
  <p>And this is the code that binds the initial data to the <code>DataGridView</code>:</p>
  
  <pre><code>        IBindingList source = new BindingList&lt;Models.InputValue&gt;(datasource);
          inputsDgv.AutoGenerateColumns = true;
          inputsDgv.AllowUserToAddRows = false;
          inputsDgv.AllowUserToDeleteRows = false;
          inputsDgv.DataSource = source;
  </code></pre>
  
  <p><strong>Problem:</strong> I'm getting a "DataGridViewComboBoxCell value is not valid" error when loading the DataGridView. I noticed that after running the line <code>(row.Cells[list.Name]) = cell;</code>, the <code>cell.ValueType</code> changes from <code>System.Collections.Generic.IList1[[roco.Models.ISnapshots]]</code> to <code>System.Int32</code>. I figured that must the the problem.</p>
  
  <p>Does any one know how I can go around this error?</p>
  
  <p>Thanks!</p>
  
  <p>P.S.: The <code>row.DataBoundItem</code> is of type <code>InputValue</code> and the list property is a collection of <code>ProjectionSnapshot</code> objects</p>
  
  <pre><code>public class InputValue : IValues
  {
      private int _id;
      public int id { get { return _id; } }
  
      private IList&lt;ISnapshots&gt; _snapshots;
      public IList&lt;ISnapshots&gt; snapshots
      {
          get { return _snapshots; }
          set { _snapshots = value; }
      }
  }
  
  public class ProjectionSnapshot : ISnapshots
  {
      private int _id;
      public int id { get { return _id; } }
  
      private string _name;
      public string name
      {
          get { return _name; }
          set
          {
              if (value.Length &gt; 255)
                  Console.WriteLine("Error! SKU snapshot name must be less than 256 characters!");
              else
                  _name = value;
          }
      }
  }
  
  public interface ISnapshots
  {
      int id { get; }
      string name { get; set; }
  }
  </code></pre>