'How to exclusively set the value of a DataGridViewCheckBoxCell?
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?
Solution 1:[1]
You can handle the CellContentClick
(or CellClick
) event of your DataGridView to set 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:
See also DataGridView CheckBox selection bug to select a CheckBox Cell by clicking anywhere in a Row and while immediately update the data source.
Solution 2:[2]
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.
Fortunately, the grids CellContentClick will fire “before” it actually sets the check box cell, so unchecking them all works out fine for both checked and unchecked states. 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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |