7

I'm struggling with DataGridViewComboBoxCell. On some cases (let's say, events) I must preselect a value of ComboBox in my Form's DataGridView. When user changes one box, I am able to change another programatically like this:

var item = ItemName.Items.GetListItem(name);
if (item != null)
{
    _loading = true; // that's needed to come around another CellValueChanged events
    itemView.Rows[e.RowIndex].Cells["ItemName"].Value = item;
    _loading = false;
}

I'm populating ItemName.Items like this:

foreach (var item in _model.DefaultData.ItemList)
{
    if (item.Value.Code.HasValue()) ItemCode.Items.Add(new ListItem(item.Key, item.Value.Code));
    ItemName.Items.Add(new ListItem(item.Key, item.Value.Name));
}

GetListItem method:

public static ListItem GetListItem(this DataGridViewComboBoxCell.ObjectCollection col, string name)
{
    ListItem retItem = null;
    foreach (ListItem item in col)
    {
        if (item.Name == name) { retItem = item; break; }
    }
    return retItem;
}

That works fine, BUT...

Now I want to add rows to DataGridView on form load like that:

foreach (var item in _model.SelectedItems)
{
    var row = new DataGridViewRow();
    row.Cells.Add(new DataGridViewTextBoxCell { Value = item.Id });
    row.Cells.Add(new DataGridViewComboBoxCell { Value = ItemCode.Items.GetListItem(item.Code) });
    row.Cells.Add(new DataGridViewComboBoxCell { Value = ItemName.Items.GetListItem(item.Name) });
    row.Cells.Add(new DataGridViewTextBoxCell { Value = item.Units });
    ...
    itemView.Rows.Add(row);
}

and that throws beloved DataGridViewComboBox value is not valid exception. Please help, I'm out of thoughts on that. I don't want to use DataSource or something like that. ItemCode and ItemName column items are populated and returned properly through GetListItem(). I don't understand why it works normally, but on form load it doesn't work (on shown it doesn't work either).

EDIT: sorry, forgot to add.

My ListItem class:

public class ListItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ListItem(int sid, string sname)
    {
        Id = sid;
        Name = sname;
    }
    public override string ToString()
    {
        return Name;
    }
}

I already put that too on form load:

ItemName.ValueMember = "Id";
ItemName.DisplayMember = "Name";
ItemCode.ValueMember = "Id";
ItemCode.DisplayMember = "Name";
abatishchev
  • 98,240
  • 88
  • 296
  • 433
YOhan
  • 505
  • 3
  • 6
  • 17
  • What do you mean by "I don't want to use DataSource or something like that"? How would the `ComboBox` know the items to select if you do not set them? It will know only currently selected value. Also, make sure that your manually added cells are in appropriate order with DataGrid columns. – Eugene Podskal Aug 22 '14 at 17:28
  • I add items to `ComboBox` by `ItemName.Items.Add(...)` where `ItemName` is `ComboBox`. Like I said, it works when I change values on grid cell change, but not when I add rows programatically on load. – YOhan Aug 23 '14 at 05:59
  • Well, I don't know what can cause it. You have posted a lot of snippets, but it is difficult to correlate them, and I'm sure that half of them have nothing to do with the problem. Try to create [short self contained example](http://sscce.org/). Begin with new project that just have datagrid with combobox columns, and add dummy items on load event. If it succeeds, include cellchanged event. Increase the code incrementally and test for the issue until it appears in the shortest self-contained example. Then you will either understand the issue or at least pinpoint it, allowing others to fix it. – Eugene Podskal Aug 23 '14 at 06:37
  • Ok, I'll try my best... – YOhan Aug 23 '14 at 06:39

3 Answers3

6

Ok, I managed to solve it myself.

Apparently, it's not enough for DataGridViewComboBoxColumn.Items to contain possible items. You must also add items to DataGridViewComboBoxCell.Items if you're adding a new row programatically.

So if someone else tries to use my approach of not having data bindings like DataTable etc., here's my solution:

foreach (var item in _model.SelectedItems)
{
    var row = new DataGridViewRow();
    var codeCell = new DataGridViewComboBoxCell();
    codeCell.Items.AddRange(ItemCode.Items);
    codeCell.Value = ItemCode.Items.GetListItem(item.Code);
    var nameCell = new DataGridViewComboBoxCell();
    nameCell.Items.AddRange(ItemName.Items);
    nameCell.Value = ItemName.Items.GetListItem(item.Name);
    row.Cells.Add(new DataGridViewTextBoxCell { Value = item.Id });
    row.Cells.Add(codeCell);
    row.Cells.Add(nameCell);
    row.Cells.Add(new DataGridViewTextBoxCell { Value = item.Units });
    row.Cells.Add(new DataGridViewTextBoxCell { Value = item.Quantity });
    row.Cells.Add(new DataGridViewTextBoxCell { Value = item.PriceLt });
    row.Cells.Add(new DataGridViewTextBoxCell { Value = item.PriceEu });
    itemView.Rows.Add(row);
}
YOhan
  • 505
  • 3
  • 6
  • 17
0
        DataGridViewColumn[] dgCol = 
        {
          new DataGridViewTextBoxColumn() 
          {
              HeaderText = "Conviction", 
              SortMode = DataGridViewColumnSortMode.NotSortable,
              Width = Convert.ToInt32(0.25f * grdConvictions.Width - 19)
          },
          new DataGridViewTextBoxColumn() 
          {
              HeaderText = "Points"    , 
              SortMode = DataGridViewColumnSortMode.NotSortable,
              Width = Convert.ToInt32(0.125f * grdConvictions.Width - 19)
          },
          new DataGridViewTextBoxColumn() 
          {
              HeaderText = "Date", 
              SortMode = DataGridViewColumnSortMode.NotSortable,
              Width = Convert.ToInt32(0.125f * grdConvictions.Width - 19),
          },
          new DataGridViewComboBoxColumn () 
          {

              HeaderText = "Galletas", 
              Width = Convert.ToInt32(0.25 * grdConvictions.Width - 19),          
              DataPropertyName  = "Galletas",
              DataSource = new List<String>{"",
                                          "Maiz",
                                          "Pera",
                                          "Manzana",
                                          "Sandia",
                                          "Fresa",
                                          "Melon",
                                          "Melocoton",
                                          "Maracuya",
                                          "Cereza",
                                          "Frambuesa",
                                          "Mora",
                                          "Kiwi",
                                          "Anona",
                                          "Guayaba"
                                        },
              SortMode = DataGridViewColumnSortMode.NotSortable,
              MaxDropDownItems = 10,

              DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing,
              ReadOnly = false
          }
        };

YourDataGridView.Columns.AddRange(dgCol);

elpezganzo
  • 349
  • 4
  • 7
0

Note: The DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox in order to see the combo. I use as "nothing", and...:

    private void grdConvictions_CellEnter(object sender, DataGridViewCellEventArgs e)
    {
        int colIndex = e.ColumnIndex;
        int rowIndex = e.RowIndex;

        if (rowIndex < 0 || colIndex < 0)
        {
            return;
        }

        DataGridView grd = (DataGridView)sender;

        if (grd[e.ColumnIndex, e.RowIndex].GetType().Name != "DataGridViewComboBoxCell")
        {
            ((DataGridViewComboBoxCell)grd.CurrentCell).DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton;
        }

}

    private void grdConvictions_CellLeave(object sender, DataGridViewCellEventArgs e)
    {
        int colIndex = e.ColumnIndex;
        int rowIndex = e.RowIndex;

        if (rowIndex < 0 || colIndex < 0)
        {
            return;
        }

        DataGridView grd = (DataGridView)sender;

        if (grd[e.ColumnIndex, e.RowIndex].GetType().Name != "DataGridViewComboBoxCell")
        {
            ((DataGridViewComboBoxCell)grd.CurrentCell).DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
        }

    }
elpezganzo
  • 349
  • 4
  • 7