Home > Back-end >  How to exclusively set the value of a DataGridViewCheckBoxCell?
How to exclusively set the value of a DataGridViewCheckBoxCell?

Time:02-20

I have a List<Car> objects that have a bool property named Marked.
I want to check / uncheck the Cell corresponding to this property, in a way that only one Car can be selected at the same time.
I want that the value of this property is updated in the bank.

Sample table:

Car Name Marked
a  
b  

The problem is I can't check the state of CheckBox Cells.
This is what I tried, but it's not working:

Example 1:

DataGridViewCheckBoxCell dataGridViewCheckBoxCell = DataGridView1.Rows[e.RowIndex].Cells["Marked"] as DataGridViewCheckBoxCell;

if(Convert.ToBoolean(dataGridViewCheckBoxCell.Value) == true)
{
        //some code
}
else if(Convert.ToBoolean(dataGridViewCheckBoxCell.Value) == false)
{
        //some code
}

Example 2:

foreach (DataGridViewRow row in DataGridView1.Rows)
{
    DataGridViewCheckBoxCell chk =(DataGridViewCheckBoxCell)row.Cells["Marked"];

    if (chk.Value == chk.TrueValue)
    {
        chk.Value = chk.FalseValue;
    }
    else
    {
        chk.Value = chk.TrueValue;
    }
}

how can I do it?

CodePudding user response:

It is unclear “where” the first code snippet is called from so I will focus on the second snippet of code.

One of the problems you will have comes from the if statement…

if (chk.Value == chk.TrueValue) …

This condition chk.Value == chk.TrueValue may not throw an error, HOWEVER… this is checking two different OBJECTS… chk.Value is an OBJECT as is chk.TrueValue … so it makes sense that the two “different” OBJECTS would NEVER be equal.

One way to solve this is to simply “cast” those OBJECTS to bool values like…

if ((bool)chk.Value == (bool)chk.TrueValue) {…

HOWEVER the above line of code will ONLY work “IF”… the check box columns TrueValue AND FalseValue properties have been SET like…

CheckBoxColumn.TrueValue = true;
CheckBoxColumn.FalseValue = false;

IF you have NOT set the Check box column’s two properties TrueValue AND FalseValue like above… then the Check box columns TrueValue and FalseValue will be null and this will cause the line of code … if ((bool)chk.Value == (bool)chk.TrueValue) … to throw an exception since chk.TrueValue is null and the cast to a bool will throw a null exception.

Therefore, if you DO SET the Check box columns TrueValue and FalseValue then you will have to “cast” the objects to bool values in order for the comparison to work as shown above.

Given all this… you may want to re-consider using the Check box columns TrueValue and FalseValue as the intended purpose of those properties is to allow you to “change” the actual true and false values to something else that is not necessarily a true or false value.

It is unimportant how you would use these properties in that context as it appears very clear that in this context… setting the Check box columns TrueValue and FalseValue properties to true and false is somewhat superfluous and creates more work for you.

So in this case, I suggest you completely drop using the Check box columns TrueValue and FalseValue properties.

If you want to ensure that only ONE check box is checked in the column… then you could wire up the grids CellContentClick event. If the check box value changed, then simply “uncheck” all the cells in that column. Crude yes, but it should work.

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) {
  if (dataGridView1.Columns[e.ColumnIndex].Name == "Marked") {
    foreach (DataGridViewRow row in dataGridView1.Rows) {
      if (!row.IsNewRow) {
        row.Cells["Marked"].Value = false;
      }
    }
  }
}

I hope this makes sense and helps.

CodePudding user response:

You can handle the CellContentClick (or CellClick) events of your DataGridView to handle the state of a DataGridViewCheckBoxCell that should be a single choice (hence behaving as a RadioButton).

Store the Cell object currently selected when the Cell meets the criteria (its OwningColumn is a DataGridViewCheckBoxColumn named Marked).
Change the state of this Cell if it's the one currently selected, or reset it back to false if it's not.
In this case, set the current Cell to the one just selected and set its state to true.

Then you don't need to loop all the Rows each time a CheckBox changes value.

If you need to, call [DataGridView].EndEdit() to update the value immediately.

For example:

DataGridViewCheckBoxCell currentCheckBoxCell = null;

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex < 0 || e.RowIndex < 0) return;
    var dgv = sender as DataGridView;

    if (dgv[e.ColumnIndex, e.RowIndex] is DataGridViewCheckBoxCell cell && 
        cell.OwningColumn.Name == "Marked")
    {
        if (currentCheckBoxCell is null) currentCheckBoxCell = cell;
        if (cell == currentCheckBoxCell) {
            cell.Value = !(bool)cell.Value;
        }
        else {
            currentCheckBoxCell.Value = false;
            currentCheckBoxCell = cell;
        }
        // Affects CellValueChanged
        // dgv.EndEdit();
    }
}

This is how it works:

DataGridCheckBoxCell Single Selection

See also DataGridView CheckBox selection bug to select a CheckBox Cell clicking anywhere in a Row.

  • Related