Checkbox in DataGrid issue?

J

James Radke

Hello,

I have a checkbox contained in a datagrid by using the DataGridBoolColumn
type. My problem is that when you first click on the checkbox, it looks
like it selects it (i.e. changes the column background to the selected
color), and doesn't change the value in the checkbox. Then, if you click it
again, it changes the checkbox value as you would expect.

My question is; how can you eliminate the 'selection' of the datagrid
element, so the background color doesn't change AND so the first click is
applied to the checkbox in the datagrid?

Thanks!

Jim
 
Y

Ying-Shen Yu[MSFT]

Hi James,

Thanks for choosing MSDN Newsgroup!

From your description, my understanding to your question now is:
you want to eleminate the select operation on the bool column style ,then a
click on the bool column cell will change the bool state of that cell, also
you want to hide the selection back color.

Based on my research, for your first question, we can archieve it by
deriving the DataGridBoolColumn class and override the Edit method like
below:
<code>
protected override void Edit(CurrencyManager source, int rowNum, Rectangle
bounds,
bool readOnly, string instantText, bool cellIsVisible)
{
object obj = this.GetColumnValueAtRow(source,rowNum);

//check if the value is DBNull,if it is, according to the
default behavior set it to false
if ( !(obj is System.DBNull) )
{
this.SetColumnValueAtRow (source,rowNum,!(Boolean) obj);
}
else this.SetColumnValueAtRow(source,rowNum,false);
base.Edit(source,rowNum,bounds,readOnly, instantText, cellIsVisible);
}
</code>

For eleminating the back color, you may try setting the
"SelectionBackColor" of the corresponding Table Style to same as the
"SelectionForeColor".
Does it solve your problem?

If you still have questions on this issue, please feel free to reply this
thread.

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 
K

kcd2f

Hi Ying-Shen Yu,
I tried your suggested code below and although it works, the first
checkbox in the datagrid will always be checked along with the
checkbox that I've actually checked. This only occurs when the grid
is first loaded and no checkboxes have been checked. Any other
suggestions? Thanks,
Kim
 
K

kcd2f

Hi Ying-Shen,
I tried out your sample code below and it works ok but sometimes when
I check a checkbox, it'll ALSO check a checkbox I had previously
unchecked (cell previously had focus). The edit event is then fired
twice, once for the checkbox I checked, and then again for the
previous checkbox. Any idea why this is happening? Thanks,
Kim
 
Y

Ying-Shen Yu[MSFT]

Hi,

After some investigation, I found it's not properly to put these codes in
the Edit method, because in Edit method, we can not know if the method is
called by a mouse click or a keyboard navigation. The behavior that
checking a cell when navigating to it by keyboard is a bit annoying.

To avoid this unwanted behavior, I'm trying to implement this feature by
deriving the DataGrid and overriding the OnMouseDown method.
We need tell DataGridBoolColumn enter "edit" mode, so the Abort/Commit can
work correctly. However, We can't use ColumnStartEditing method since there
are
actually no control in DataGridBoolColumn class, as a workaround a private
method reflection is used here. The code works now on current version of
..NET Framework, but since there is a private reflection, it might be
changed in the furture version, use it at your own risk.
Hope this helpful.

Thanks!

<code>
class MyGrid : DataGrid
{
delegate void MouseDownDelegate(MouseEventArgs e);
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown (e);
DataGrid.HitTestInfo ht = this.HitTest(e.X,e.Y);
System.Diagnostics.Debug.WriteLine (ht.ToString());

//only handle mouse in cell
if (ht.Type.ToString() == "Cell")
{
MyBoolColumn col = this.TableStyles[0].GridColumnStyles[ht.Column] as
MyBoolColumn;
if (col != null)
col.ToggleValue ();
}
}
}
public class MyBoolColumn : DataGridBoolColumn
{
public void ToggleValue()
{
Type t = typeof(DataGridBoolColumn);

t.InvokeMember("ToggleValue",BindingFlags.NonPublic|BindingFlags.Instance|Bi
ndingFlags.InvokeMethod,
null,this,null);
}
}
</code>

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 
J

James Radke

Hello!

I am trying to get your sample working, but in VB, not C#... and it doesn't
work.. the code I have is (I am also always showing the vertical scroll bars
in it). Everything is working fine except for the ToggleValue routine in
the MyBoolColumn class. Can you tell me why this doesn't work?

=================================== code follows
================================================================

Public Class MyDataGrid
Inherits DataGrid

Private Delegate Sub MouseDownDelegate(ByVal e As MouseEventArgs)

Public Sub New()
'make scrollbar visible & hook up handler
Me.VertScrollBar.Visible = True
AddHandler Me.VertScrollBar.VisibleChanged, AddressOf ShowScrollBars
End Sub 'New

Private CAPTIONHEIGHT As Integer = 21
Private BORDERWIDTH As Integer = 2

Private Sub ShowScrollBars(ByVal sender As Object, ByVal e As EventArgs)
If Not Me.VertScrollBar.Visible Then
Dim width As Integer = Me.VertScrollBar.Width
Me.VertScrollBar.Location = New Point(Me.ClientRectangle.Width -
width - BORDERWIDTH, CAPTIONHEIGHT)
Me.VertScrollBar.Size = New Size(width,
Me.ClientRectangle.Height - CAPTIONHEIGHT - BORDERWIDTH)
Me.VertScrollBar.Show()
End If
End Sub 'ShowScrollBars

Protected Overrides Sub OnMouseDown(ByVal e As
System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseDown(e)

Dim ht As HitTestInfo = Me.HitTest(e.X, e.Y)

If ht.Type.ToString = "Cell" Then
If
Me.TableStyles(0).GridColumnStyles(ht.Column).GetType.ToString =
"OrderEntry.MyDataGrid+MyBoolColumn" Then
Dim col As MyBoolColumn =
Me.TableStyles(0).GridColumnStyles(ht.Column)
If Not IsDBNull(col) Then
col.ToggleValue()
End If
End If
End If
End Sub

Public Class MyBoolColumn
Inherits DataGridBoolColumn

Public Sub ToggleValue()
Dim t As DataGridBoolColumn
t.GetType.InvokeMember("ToggleValue",
Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance Or
Reflection.BindingFlags.InvokeMethod, Nothing, Me, Nothing)
End Sub
End Class
End Class 'MyDataGrid

================================= end code
===========================================================================

"Ying-Shen Yu[MSFT]" said:
Hi,

After some investigation, I found it's not properly to put these codes in
the Edit method, because in Edit method, we can not know if the method is
called by a mouse click or a keyboard navigation. The behavior that
checking a cell when navigating to it by keyboard is a bit annoying.

To avoid this unwanted behavior, I'm trying to implement this feature by
deriving the DataGrid and overriding the OnMouseDown method.
We need tell DataGridBoolColumn enter "edit" mode, so the Abort/Commit can
work correctly. However, We can't use ColumnStartEditing method since there
are
actually no control in DataGridBoolColumn class, as a workaround a private
method reflection is used here. The code works now on current version of
NET Framework, but since there is a private reflection, it might be
changed in the furture version, use it at your own risk.
Hope this helpful.

Thanks!

<code>
class MyGrid : DataGrid
{
delegate void MouseDownDelegate(MouseEventArgs e);
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown (e);
DataGrid.HitTestInfo ht = this.HitTest(e.X,e.Y);
System.Diagnostics.Debug.WriteLine (ht.ToString());

//only handle mouse in cell
if (ht.Type.ToString() == "Cell")
{
MyBoolColumn col = this.TableStyles[0].GridColumnStyles[ht.Column] as
MyBoolColumn;
if (col != null)
col.ToggleValue ();
}
}
}
public class MyBoolColumn : DataGridBoolColumn
{
public void ToggleValue()
{
Type t = typeof(DataGridBoolColumn);

t.InvokeMember("ToggleValue",BindingFlags.NonPublic|BindingFlags.Instance|Bi
ndingFlags.InvokeMethod,
null,this,null);
}
}
</code>

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 
J

James Radke

Ying-Shen Yu

I have it working now, but, it seems that If I click on a cell to change the
checkbox, and then immediately click on the same cell to change it back -
that doesn't work. I have to click on a different cell in the table first,
then click back on the checkbox.. Why would this be happening?

Thanks!

Jim

James Radke said:
Hello!

I am trying to get your sample working, but in VB, not C#... and it doesn't
work.. the code I have is (I am also always showing the vertical scroll bars
in it). Everything is working fine except for the ToggleValue routine in
the MyBoolColumn class. Can you tell me why this doesn't work?

=================================== code follows
================================================================

Public Class MyDataGrid
Inherits DataGrid

Private Delegate Sub MouseDownDelegate(ByVal e As MouseEventArgs)

Public Sub New()
'make scrollbar visible & hook up handler
Me.VertScrollBar.Visible = True
AddHandler Me.VertScrollBar.VisibleChanged, AddressOf ShowScrollBars
End Sub 'New

Private CAPTIONHEIGHT As Integer = 21
Private BORDERWIDTH As Integer = 2

Private Sub ShowScrollBars(ByVal sender As Object, ByVal e As EventArgs)
If Not Me.VertScrollBar.Visible Then
Dim width As Integer = Me.VertScrollBar.Width
Me.VertScrollBar.Location = New
Point(Me.ClientRectangle.Width -
width - BORDERWIDTH, CAPTIONHEIGHT)
Me.VertScrollBar.Size = New Size(width,
Me.ClientRectangle.Height - CAPTIONHEIGHT - BORDERWIDTH)
Me.VertScrollBar.Show()
End If
End Sub 'ShowScrollBars

Protected Overrides Sub OnMouseDown(ByVal e As
System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseDown(e)

Dim ht As HitTestInfo = Me.HitTest(e.X, e.Y)

If ht.Type.ToString = "Cell" Then
If
Me.TableStyles(0).GridColumnStyles(ht.Column).GetType.ToString =
"OrderEntry.MyDataGrid+MyBoolColumn" Then
Dim col As MyBoolColumn =
Me.TableStyles(0).GridColumnStyles(ht.Column)
If Not IsDBNull(col) Then
col.ToggleValue()
End If
End If
End If
End Sub

Public Class MyBoolColumn
Inherits DataGridBoolColumn

Public Sub ToggleValue()
Dim t As DataGridBoolColumn
t.GetType.InvokeMember("ToggleValue",
Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance Or
Reflection.BindingFlags.InvokeMethod, Nothing, Me, Nothing)
End Sub
End Class
End Class 'MyDataGrid

================================= end code
===========================================================================

"Ying-Shen Yu[MSFT]" said:
Hi,

After some investigation, I found it's not properly to put these codes in
the Edit method, because in Edit method, we can not know if the method is
called by a mouse click or a keyboard navigation. The behavior that
checking a cell when navigating to it by keyboard is a bit annoying.

To avoid this unwanted behavior, I'm trying to implement this feature by
deriving the DataGrid and overriding the OnMouseDown method.
We need tell DataGridBoolColumn enter "edit" mode, so the Abort/Commit can
work correctly. However, We can't use ColumnStartEditing method since there
are
actually no control in DataGridBoolColumn class, as a workaround a private
method reflection is used here. The code works now on current version of
NET Framework, but since there is a private reflection, it might be
changed in the furture version, use it at your own risk.
Hope this helpful.

Thanks!

<code>
class MyGrid : DataGrid
{
delegate void MouseDownDelegate(MouseEventArgs e);
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown (e);
DataGrid.HitTestInfo ht = this.HitTest(e.X,e.Y);
System.Diagnostics.Debug.WriteLine (ht.ToString());

//only handle mouse in cell
if (ht.Type.ToString() == "Cell")
{
MyBoolColumn col = this.TableStyles[0].GridColumnStyles[ht.Column] as
MyBoolColumn;
if (col != null)
col.ToggleValue ();
}
}
}
public class MyBoolColumn : DataGridBoolColumn
{
public void ToggleValue()
{
Type t = typeof(DataGridBoolColumn);
t.InvokeMember("ToggleValue",BindingFlags.NonPublic|BindingFlags.Instance|Bi
ndingFlags.InvokeMethod,
null,this,null);
}
}
</code>

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 
Y

Ying-Shen Yu[MSFT]

Hi James,

In the ToggeValue method, t was not initialized before calling GetType,
GetType is not a static method and requires an instance before calling, so
that's why you got the exception.
I modified the ToggleValue method as Below,
<code>
Public Sub ToggleValue()
Dim t As Type = GetType(DataGridBoolColumn)
t.InvokeMember("ToggleValue", Reflection.BindingFlags.NonPublic
Or _
Reflection.BindingFlags.Instance Or
Reflection.BindingFlags.InvokeMethod, Nothing, Me, Nothing)
End Sub
</code>

Do you still have the problem "it seems that If I click on a cell to change
the checkbox, and then immediately click on the same cell to change it
back" ? I'm not able to reproduce this problem on my system, if you still
have the problem, could you give me a small sample with the detail steps to
reproduce it?

Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 

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