Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Empty Datagridview cell with bound datasourse

I have a DataGridView with "Type" and "Value" columns. The user selects a data type, and then enters a value compatible with that type, some types (e.g. "Text") accept any string. Other types (e.g. "Yes/No") are restricted to a list of possible values. For each row, I set the cell in the "Value" column to be either a Textbox for freeform types, or a combobox for list types. The DataGridView is bound to a DataTable.

The problem comes in if the user enters a value for one type, but then switches the row to a different type for which the current value is not allowed. No matter what I try, I cannot clear the Value cell. Then when I assign a combobox to the cell, I get a DataError, because the current value of the cell is incompatible. How can I clear the value before changing the cell from a textbox to a combobox?

public enum DataType 
{
    Text,
    YesNo
}

public class IndexedItem 
{
    public string Name { get; set; }
    public int ID {get; set; }

    public string strID 
    {
        get { return ID.ToString(); }
    }       

    //constructors & other methods;
}

public static DataTable ParameterTable;
public List<IndexedItem> YesNoList;

In the form constructor (dgvInputs is the DataGridView):

ParameterTable = new DataTable("ParameterTable");
ParameterTable.Columns.Add("Type", typeof(DataType));
ParameterTable.Columns.Add("Value", typeof(string));

YesNoList = new List<IndexedItem>();
YesNoList.Add(new IndexedItem("Yes", 1));
YesNoList.Add(new IndexedItem("No", 0));

var D = (DataGridViewComboBoxColumn)dgvInputs.Columns[0];
D.ValueMember = "Value";
D.DisplayMember = "Display";
D.DataSource = new DataType[] { 
        DataType.Text,
        DataType.YesNo
}.Select(x => new { Display = x.ToString(), Value = (int)x }).ToList();

BindingSource ParamSource = new BindingSource();
ParamSource.DataSource = ParameterTable;
dgvInputs.AutoGenerateColumns = false;
dgvInputs.DataSource = ParamSource;
dgvInputs.Columns[0].DataPropertyName = "Type";
dgvInputs.Columns[1].DataPropertyName = "Value";

And Events:

private void dgvInputs_CurrentCellDirtyStateChanged(object sender, EventArgs e) {
    if (dgvInputs.IsCurrentCellDirty) {
        dgvInputs.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }
}

private void dgvInputs_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
   if (e.RowIndex >= 0 && e.ColumnIndex == 0) {
      var cb = (DataGridViewComboBoxCell)dgvInputs[0, e.RowIndex];
      if (cb.Value != null && cb.Value != DBNull.Value) {
         DataType Type = (DataType)cb.Value;
         dgvInputs[1, e.RowIndex].Value = string.Empty;
         dgvInputs.CommitEdit(DataGridViewDataErrorContexts.Commit);
         switch (Type) {
            case DataType.YesNo:
               dgvInputs[1, e.RowIndex].Dispose();
               var newBox = new DataGridViewComboBoxCell();
               newBox.DisplayMember = "Name";
               newBox.ValueMember = "strID";
               newBox.DataSource = YesNoList;
               dgvInputs[1, e.RowIndex] = newBox;
               break;
            default:
               dgvInputs[1, e.RowIndex] = new DataGridViewTextBoxCell();
               break;
         }
      }
   }
}

If you have it set to "text" and enter something arbitrary, then switch to "YesNo", it gives an error "System.ArgumentException: DataGridViewComboBoxCell value is not valid.", that will reappear any time the cursor is over the cell. Changing it back to a text row causes the original value to reappear.

I am assuming that the problem is that the value is saved in ParameterTable, but I can't get it to propagate my clearing of the original value to ParameterTable. I've tried null and DBNull.Value instead of string.Empty, but neither one made any difference. I added the "CommitEdit" line in hopes of getting it to make the change, but that made no difference either.

Edit: As it turns out, the problem was this code that I had in the cell change event:

string Default = dgvInputs[4, e.RowIndex].Value as string;
// code switching out text box and combo box above
try 
{
    dgvInputs[4, e.RowIndex].Value = Default;
} catch (Exception e2) {
    MessageBox.Show(e2.GetType().ToString());
}

The idea had been to preserve the value if possible, and I had the messagebox to show me the specific exception I needed to catch, as I was not sure. But apparently this assignment does not immediately induce the exception. That only occurs later, apparently during some other event I am not handling.

It is obvious in hindsight that I should have included this code in the sample. I have no idea now how I overlooked it. My apologies to everybody I led on a wild goose chase by leaving out the critical information. I do appreciate all of your assistance.

like image 815
Paul Sinclair Avatar asked Dec 08 '15 17:12

Paul Sinclair


1 Answers

You problem is not with clearing the value but with the YesNoList.

The grid compbobox tries to find the value for the current record and there is no empty neither null value in your YesNoList.

You will even get an error if you try to add a new record and first set the DataType without setting the Value.

You can solve this by either adding an empty item to your YesNoList or by setting a default value to the existing record when switching DataType.

like image 178
Michael Kanios Avatar answered Oct 17 '22 07:10

Michael Kanios