null values in DataGridViewCheckBoxColumns

G

Guest

I have a TabControl on a Windows form in which I have various tab pages each
with a DataGridView, the first column of which is a
DataGridViewCheckBoxColumn and subsequent columns being
DataGridViewtextBoxColumns.

In each case the properties of the CheckBoxcolumn have been set to not allow
nulls, so presumably only explicit true or false values should be possible.

I run the application and set check boxes for DataGridView rows I am
interested in, in the DataGridViews on any or all of the tab pages.

In code, I use the following in turn on each DataGridView.

foreach (DataGridViewRow r in dgvRange.Rows)
{
if((bool)(r.Cells[0] as DataGridViewCheckBoxCell).Value )
{
//do something
}
}

for the second grid the name changes obviously.

So processing goes from the first, to the second, then the third grid.

Problem is that (bool)(r.Cells[0] as DataGridViewCheckBoxCell).Value part
works on the first grid but not on any subsequent grids even though they are
set identically. The subsequent ones throw an exception as the cast is
invalid.

Despite the DataGridViewCheckBoxColumns being set to not allow nulls for all
the grids, with the exception of the first, the others all evaluate
(r.Cells[0] as DataGridViewCheckBoxCell).Value to null, whilst the first
evaluates to true or false as it should. I do not understand why there
should be any difference. They are unique instances in unique DataGridViews,
and each is configured to not allow nulls so only boolean values should be
possible.

Any ideas would be appreciated.
 
G

Guest

I tried to set TrueValue, IndeterminateValue and FalseValue to true, false
and false respectively and now find that the column checkBox value is
evaluated to the string boolean values and all works just fine.
 
L

Linda Liu [MSFT]

Hi Peter,

Based on my understanding, you have a TabControl on a form, which contains
various tab pages. Each tab page has a DataGridView and the first column of
the DataGridView is a DataGridViewCheckBoxColumn. You set value to the
first column of each DataGridView and then get the value of the first
column for each DataGridView. The problem is that only the first
DataGridView returns a valid value for each row in it, and the others
sometimes return null for the first column. If I'm off base, please feel
free to let me know.

Do you set the DataGridViewCheckBoxCell's value manually or bind the
DataGridViewCheckBoxColumn to a data source?

I performed tests on both of the scenarioes, but didn't reproduce the
problem. All the DataGridViews in my test application return valid values.

The following is the steps of my test.

1. Create a WinForms application project.
2. Add a TabControl on the form. By default, the TabControl has two tab
pages.
3. Add a DataGridView to each tab page in the TabControl.
4. Add a DataGridViewCheckBoxColumn in each DataGridView.
5. Add the following code in the Form's Load event handler.
private void Form1_Load(object sender, EventArgs e)
{
DataTable dt1 = new DataTable();
dt1.Columns.Add(new DataColumn("id",typeof(bool)));
DataRow row1 = dt1.NewRow();
row1[0]=true;
dt1.Rows.Add(row1);

DataTable dt2 = new DataTable();
dt2.Columns.Add(new DataColumn("id", typeof(bool)));
DataRow row2 = dt2.NewRow();
row2[0]=true;
dt2.Rows.Add(row2);

this.dataGridView1.AutoGenerateColumns = false;
this.dataGridView2.AutoGenerateColumns = false;
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView2.AllowUserToAddRows = false;

this.Column1.DataPropertyName = "id";
this.dataGridViewCheckBoxColumn1.DataPropertyName = "id";
this.dataGridView1.DataSource = dt1;
this.dataGridView2.DataSource = dt2;

// the following code set the value to the first column of
each DataGridView manually
//this.dataGridView1.Rows[0].Cells[0].Value = true;
//this.dataGridView2.Rows[0].Cells[0].Value = true;
}
6. Add a Button on the form and copy the following code to its Click event
handler.
private void button1_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow r in this.dataGridView1.Rows)
{
Console.WriteLine(r.Cells[0].Value.ToString());
}
foreach (DataGridViewRow r in this.dataGridView2.Rows)
{
Console.WriteLine(r.Cells[0].Value.ToString());
}
}

Is there any difference between your application and mine?

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Linda

The first column is unbound, the others are bound to a strongly typed
Generics List of type depending on the grid. The class of the object is
responsible for populating its properties and has a GetList method which
calls a stored procedure, creates a strongly typed Generics List and
populates and returns its values to the calling routine.

There are 5 tab pages in the tabControl. The first four are used for
DataGridViews to filter data. The fifth contains a nested TabControl with
another 4 DataGridViews.

All DataGridViews are bound to Generics Lists of various types of object.
All the bound columns work appropriately.

The DataGridViewCheckBoxColumns ThreeState property is set to False which I
would have thought would have resulted in behaviour the same as for a normal
CheckBox where checked/unchecked is a boolean value. Not so, The behaviour
is this for the first DataGridView but not for the others. Yet they are all
set up absolutely identically. I do not understand the inconsistency.

When I set the values of the Data FalseValue, IndeterminateValue and
TrueValue properties to false, false and true, I can check for a string of
"true" or "false" but I would have thought that with ThreeState set to False,
nulls would not be possible and a (bool) cast or accessing a boolean value
directly would be appropriate and setting FalseValue, IndeterminateValue and
TrueValue properteis would be unnecessary. With the values of FalseValue,
IndeterminateValue and TrueValue set, the behaviour of the column is
predictable and consistent again and can be used.

Thanks for your help.

cheers
--
PeterW


Linda Liu said:
Hi Peter,

Based on my understanding, you have a TabControl on a form, which contains
various tab pages. Each tab page has a DataGridView and the first column of
the DataGridView is a DataGridViewCheckBoxColumn. You set value to the
first column of each DataGridView and then get the value of the first
column for each DataGridView. The problem is that only the first
DataGridView returns a valid value for each row in it, and the others
sometimes return null for the first column. If I'm off base, please feel
free to let me know.

Do you set the DataGridViewCheckBoxCell's value manually or bind the
DataGridViewCheckBoxColumn to a data source?

I performed tests on both of the scenarioes, but didn't reproduce the
problem. All the DataGridViews in my test application return valid values.

The following is the steps of my test.

1. Create a WinForms application project.
2. Add a TabControl on the form. By default, the TabControl has two tab
pages.
3. Add a DataGridView to each tab page in the TabControl.
4. Add a DataGridViewCheckBoxColumn in each DataGridView.
5. Add the following code in the Form's Load event handler.
private void Form1_Load(object sender, EventArgs e)
{
DataTable dt1 = new DataTable();
dt1.Columns.Add(new DataColumn("id",typeof(bool)));
DataRow row1 = dt1.NewRow();
row1[0]=true;
dt1.Rows.Add(row1);

DataTable dt2 = new DataTable();
dt2.Columns.Add(new DataColumn("id", typeof(bool)));
DataRow row2 = dt2.NewRow();
row2[0]=true;
dt2.Rows.Add(row2);

this.dataGridView1.AutoGenerateColumns = false;
this.dataGridView2.AutoGenerateColumns = false;
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView2.AllowUserToAddRows = false;

this.Column1.DataPropertyName = "id";
this.dataGridViewCheckBoxColumn1.DataPropertyName = "id";
this.dataGridView1.DataSource = dt1;
this.dataGridView2.DataSource = dt2;

// the following code set the value to the first column of
each DataGridView manually
//this.dataGridView1.Rows[0].Cells[0].Value = true;
//this.dataGridView2.Rows[0].Cells[0].Value = true;
}
6. Add a Button on the form and copy the following code to its Click event
handler.
private void button1_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow r in this.dataGridView1.Rows)
{
Console.WriteLine(r.Cells[0].Value.ToString());
}
foreach (DataGridViewRow r in this.dataGridView2.Rows)
{
Console.WriteLine(r.Cells[0].Value.ToString());
}
}

Is there any difference between your application and mine?

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
L

Linda Liu [MSFT]

Hi Peter,

Thank you for your prompt response.
The DataGridViewCheckBoxColumns ThreeState property is set to False which
I would have thought would have resulted in behaviour the same as for a
normal CheckBox where checked/unchecked is a boolean value.

Yes, you're right. When the ThreeState property of the
DataGridViewCheckBoxColumn is set to false, the hosted checkbox editing
control can only have two states, i.e. checked/unchecked. In this case, the
DataGridViewCheckBoxColumn.CellTemplate.ValueType is of type System.Boolean
by default.
The behaviour is this for the first DataGridView but not for the others.
Yet they are all set up absolutely identically. I do not understand the
inconsistency.

Do you mean that only the checkbox column in the first DataGridView
supports two states of values, and the checkbox columns in other
DataGridViews support three states of values? I didn't see it in my test.
but I would have thought that with ThreeState set to False, nulls would
not be possible and a (bool) cast or accessing a boolean value directly
would be appropriate and setting FalseValue, IndeterminateValue and
TrueValue properteis would be unnecessary.

Setting the ThreeState property to false doesn't mean that null value is
not allowed in that DataGridViewCheckBoxColumn.

If the NullValue property of the object returned by the DefaultCellStyle
property has a value of false, changing the ThreeState property value to
true automatically sets NullValue to Indeterminate. If NullValue has a
value of Indeterminate, changing the ThreeState property value to false
automatically sets NullValue to false.

As I have mentioned above, if the ThreeState property is set to false, the
DataGridViewCheckBoxColumn.CellTemplate.ValueType is of type System.Boolean
by default. If the ThreeState property is set to true, the ValueType is of
type CheckState by default. Of course, we could set the checkbox column's
ValueType to any type we want.

Whenever we use DataGridViewCheckBoxColumn, we should set its TrueValue,
FalseValue property and also the IndeterminateValue property if the
ThreeState property is true. The TrueValue, FalseValue and
IndeterminateValue properties are used to save the update in the hosted
checkbox into the cell's value. Note that the values of the TrueValue,
FalseValue and IndeterminateValue properties should be of the checkbox
column's ValueType.

Let me illuminate this with a simple example. Say I have a DataGridView
with a DataGridViewCheckBoxColumn in it and the checkbox column's
ThreeState property is set to false. Add the following code in the form's
Load event handler:
private void Form1_Load(object sender, EventArgs e)
{
this.dataGridView1.RowCount = 1;
this.Column1.TrueValue = true;
this.Column1.FalseValue = false;
}

Run the application. You should see the checkbox in the DataGridView is
unchecked, because the NullValue property of the object returned by the
DefaultCellStyle property has a value of false. The value of the first cell
in DataGridView is null.

Click to select the checkbox in the DataGridView and watch the value of the
first cell. You should see the value becomes true.

You may read the following MSDN document for another example of using
DataGidViewCheckBoxColumn:
'DataGridViewCheckBoxColumn.ThreeState Property'
http://msdn2.microsoft.com/en-us/library/system.windows.forms.datagridviewch
eckboxcolumn.threestate.aspx

Hope it helps.
If you have anything unclear, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Hi Linda

Thanks for your reply.

The UI uses a TabContol and on each tab page the first object dropped is a
Split Container set to Horizontal, the top part holding a toobar for a
Navigator and the bottom, a checkBox for select all and immediately below
that the DataGridView. At the tab page level, the first 4 tab pages hold
CheckBoxes and then DataGridViews which are configured identically with
ThreeState set to false and values supplied for TrueValue, FalseValue and
IndeterminateValue in the designer. The fifth tab page contains a TabControl
with 4 tab pages with a further 4 checkboxes for select all DataGridViews.

The interesting bit is that despite the DataGridView being set identically
in the designer, and also programmatically setting the state of the select
all checkboxes and also all checkBoxes in DataGridViewCheckBoxColumns to true
or checked in the Load event of the Page, on displaying the form the
behaviour is inconsistent. On each tab page, the checkBox for select all is
exactly as set programmatically. However for the DatGridViews, only the
topmost and visible DataGridView (i.e the top tabPage) reflects what has been
set in code. The not currently selected and thus not visible tab pages when
displayed do not have the checkBoxes for the rows set at all. Yet the
checkBox for "select all" is correct and when the checkChanged event is fired
from the UI, works just fine.

This is consistent with the behaviour of the values of the
DataGridViewCheckBoxColumn values when inspected in the debugger. The
topmost DataGridView when the form was first displayed is correct and
reflects the settings set in the designer and in code. For all other tab
pages, firstly the checkboxes in the DatagridViewCheckBoxColumns are not
checked even though they should have been and secondly the values when
inspected is null (and shouldn't be, so the ThreeState property is obviously
disregarded) and also throws an exception when cast to the expected boolean.
There must be something that is suppressing the setting of values in the
DataGridvVews for all but the initially presented DataGridView in the topmost
tab page. In all cases the "select all" checkBoxes do what they should.

What beats me is why. More importantly I need to be able to rely on the
state of properties and values that have been set in the designer and in code
being exactly as intended and set or I need to be able to override the what I
consider bizarre behaviour and enforce consistency.

You mention the DataGridViewCellStyle, but when I look in the designer, for
each and every DataGridViewCheckBoxColumn this is set to
DataGridViewCellStyle { NullValue=False, Alignment=MiddleCenter } which is
quite explicit and should enforce boolean values. The actual behaviour does
not conform to this for other than the topmost tabPage and DataGridView. Any
attempt to interpret the values as boolean on all but the topmost
DataGridView and TabPage result in an exception being thrown. That should
not be the case.

Is it possible that the Split Container or TabControl components are
interfering with the DataGridView?

The behaviour you explain for the Load event is what I would expect but is
not what I am getting, hence the problem.

cheers
 
L

Linda Liu [MSFT]

Hi Peter,

Thank you for your prompt reply.
The interesting bit is that despite the DataGridView being set
identically in the designer, and also programmatically setting the state of
the select all checkboxes and also all checkBoxes in
DataGridViewCheckBoxColumns to true or checked in the Load event of the
Page, on displaying the form the
behaviour is inconsistent.

How do you set all the checkboxes in DataGridViewCheckBoxColumns checked?
What do you mean by the "Load event of the Page"? I don't see TabPage has a
Load event.

The NullValue property of the DataGridViewCellStyle being set to False
means that when the value of the cell is null, the checkbox hosted in the
cell appears unchecked.

If possible, could you please send me a simple project that could just
reproduce the problem? To get my actual email address, remove 'online' from
my displayed email address.

Sincerely,
Linda Liu
Microsoft Online Community Support
 
L

Linda Liu [MSFT]

Hi Peter,

How about the problem now?

If you need our further assistance, please feel free to let me know.

Thank you for using our MSDN Managed Newsgroup Support Service!

Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Linda

I've been away on business for a couple of days hence the lack of contuinuity.

I think that what I am going to try is to extend the data aware object to
which the columns are bound to include a boolean property that can be used
solely for the column binding so that the column gets its checked value from
a bound object property. The notion of a mixture of bound and unbound columns
is perhaps not optimal. Certainly the behaviour is not as required or
expected.

I think that should force the row to have the correct value for every cell
including the one for the checkbox. I do not need to persist the boolean,
just be able to get its value at the user interface.

I will send you the form as it is prior to doing this and you can make the
choice of whether to look at it or not. The problem exists in what I have,
not with a subset as requested by you.

Thanks for your professionalism in following up. It is appreciated.
 
G

Guest

Linda

As I mentioned in my previous post, I changed the several data aware objects
used for filtering to include a boolean property "selected" and then set the
appropriate property on the DataGridView columns collection
DataGridViewCheckBoxColumn to bind to the "selected" property.

Lo and behold, all my woes have disappeared and all is well.

I will not bother to send you the form as it was as that will now serve no
purpose.

Thanks for you "ear"!

cheers
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top