Results 1 to 13 of 13

Thread: [RESOLVED] VB.net DataGridView CellContentClick and CellValueChanged

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Resolved [RESOLVED] VB.net DataGridView CellContentClick and CellValueChanged

    I have a DataGridView with and editable textcolumn and editable checkbox. I attempting to write to the database as soon as the user edits, but the method seems to fire randomly between the two:

    Code:
            Private Sub DGVSMT_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridSMT.CellContentClick
                'This method attempts to convert the formatted, user-specified value to the underlying cell data type.
            DataGridSMT.CommitEdit(DataGridViewDataErrorContexts.Commit)
                'If the value is successfully committed, the CellValueChanged event occurs
            End Sub
    
            Private Sub DGVSMT_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridSMT.CellValueChanged
    
            If e.ColumnIndex = 8 Then
                 'do stuff if checkbox clicked
            End If
     
            If e.ColumnIndex = 7 Then
                 'do stuff if text field updated
            End If
    
        End Sub
    Sometimes when I'm editing the column 7 textbox the e.ColumnIndex = 8 checkbox IF statement will fire (but the checkbox itself in column 8 is not updated). I've tried editing the text field and hitting enter, or just clicking off the text cell to let it update. It's intermittent, sometime it works as expected, sometimes it fires the e.ColumnIndex = 8 IF statement.

    Any ideas?

  2. #2
    I'm about to be a PowerPoster! kleinma's Avatar
    Join Date
    Nov 2001
    Location
    NJ - USA (Near NYC)
    Posts
    23,373

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    Read the remarks section for CellValueChanged

    https://msdn.microsoft.com/en-us/lib...v=vs.110).aspx

    Specifically

    In the case of check box cells, however, you will typically want to handle the change immediately. To commit the change when the cell is clicked, you must handle the DataGridView.CurrentCellDirtyStateChanged event. In the handler, if the current cell is a check box cell, call the DataGridView.CommitEdit method and pass in the Commit value.

  3. #3

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    Yes, I read that already but don't understand it. Do you have an example?

    I am handling the DataGridView.CommitEdit already. How/Where do I handle the CurrentCellDirtyStateChanged event? How do I isolate a checkbox column from a text column other than by columnIndex. Why does it randomly choose between the two?

    Edit: I have been experimenting with these methods and they seem to work well and good when you only have one editable column. It's when you introduce two different types of columns that it randomly choose between the two. I tried to isolate them by identifying the columnIndex. Is there a different way to isolate the columns or edit events?
    Last edited by Fedaykin; Jan 6th, 2016 at 12:29 PM.

  4. #4

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    I continue to struggle with this and every forum out there quotes the same:


    https://msdn.microsoft.com/en-us/lib...v=vs.110).aspx

    Specifically

    In the case of check box cells, however, you will typically want to handle the change immediately. To commit the change when the cell is clicked, you must handle the DataGridView.CurrentCellDirtyStateChanged event. In the handler, if the current cell is a check box cell, call the DataGridView.CommitEdit method and pass in the Commit value.
    But this does not resolve the issue of multiple editable columns. The e.ColumnIndex remains 'stuck' on the first column integer edited. I tried setting the e.ColumnIndex to a variable and then setting that variable to -1 at the end of the method, however the CellContentClick Handler will only remember the first column. If the fist column you edit is column 0, then all subsequent columns edited will also fire 0 no matter which column is selected. Only disposing the DataGridView and recalling it will make it forget the last column fired.

    This appears to be a bug because the question has been asked many times and I've yet to see a resolution. Everyone just points to the same post quoted above.

  5. #5
    PowerPoster
    Join Date
    Oct 2010
    Posts
    2,141

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    Quote Originally Posted by Fedaykin View Post
    I continue to struggle with this and every forum out there quotes the same:
    ...
    But this does not resolve the issue of multiple editable columns.
    If the information in the link (and its linked references) that Kleinma provided does not solve the stated problem then I see only two possibilities.
    1. The problem is not as you have stated.
    2. Your implementation of the proposed solution is incorrect.

    Since you have not shown us your implementation, we have no idea what you have tried.

  6. #6

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    The implementation is the original post with code. Am I missing something?

  7. #7
    PowerPoster
    Join Date
    Oct 2010
    Posts
    2,141

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    Quote Originally Posted by Fedaykin View Post
    The implementation is the original post with code. Am I missing something?
    Are you missing something? I'd say so.

    You ask for help. Kleinma gives you a link to investigate and even directs you to the relevant part that describes how to do what you asked with an example but you claim it does not work.

    Where have you shown your implementation of that solution? It is not in the first post, because if it was I would not be making this reply nor my prior one.

  8. #8

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    Ahhh.. you'd like me to give you the code example that is listed in the link? I thought I had made it clear that I tried the code in the example in my earlier post. But here is the actual code for posterity:

    In this example 'SMTOrder' is the textbox field (column 7 in my datagridview) and 'FLY' is the checkbox field (column 8 in my datagridview).

    Code:
        Sub DataGridSMT_CurrentCellDirtyStateChanged( _
        ByVal sender As Object, ByVal e As EventArgs) _
        Handles DataGridView1.CurrentCellDirtyStateChanged
    
            If DataGridSMT.IsCurrentCellDirty Then
                DataGridSMT.CommitEdit(DataGridViewDataErrorContexts.Commit)
            End If
        End Sub
    
        ' If a check box cell is clicked, this event handler disables  
        ' or enables the button in the same row as the clicked cell.
        Public Sub DataGridSMT_CellValueChanged(ByVal sender As Object, _
            ByVal e As DataGridViewCellEventArgs) _
            Handles DataGridSMT.CellValueChanged
    
            If DataGridSMT.Columns(e.ColumnIndex).Name = "SMTOrder" Then
                'do stuff
                MessageBox.Show("You edited SMT.")
                DataGridSMT.Invalidate()
            End If
    
            If DataGridSMT.Columns(e.ColumnIndex).Name = "FLY" Then
                'do stuff
                MessageBox.Show("You edited Fly.")
                'DataGridSMT.Invalidate()
            End If
        End Sub
    Column 8 fires as the DataGridView populates for every checkbox in the grid which is fine for testing purposes, we can always remove the handler while the grid loads at a later date.

    Column 7 fires successfully when the column 7 textfield is edited. No trouble here.

    Column 8 does not fire when the checkbox is clicked by the user. <-THIS IS THE ISSUE WITH THIS METHOD

    I have tried commenting out the DataGridSMT.Invalidate() and leaving it in place, the result is the same.

    You can substitute the CurrentCellDirtyStateChanged with CellContentClick as I described above and you get the same column index firing every time you click a column regardless of what column it is.

    I am of course open to using any other method that might get the job done, or splitting this into two different methods if needed to handle the checkbox and textfield separately if they can be separated. I've tried every combination I can think of and all have similar results of not firing or firing incorrectly.

  9. #9
    PowerPoster
    Join Date
    Oct 2010
    Posts
    2,141

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    Quote Originally Posted by Fedaykin View Post
    Ahhh.. you'd like me to give you the code example that is listed in the link? I thought I had made it clear that I tried the code in the example in my earlier post. But here is the actual code for posterity:
    You may think that I'm being a jerk to not take you at your word on this, but how else am I or anyone else here to know what it is that you have done? We see it it all the time here where a poster is asked to try something and the immediate and totally useless comment of "it doesn't work" is all we receive back.

    In your case, you are claiming that a well known and documented method to achieve what you claim you want to do fails to work. That in itself raises suspicions that the implementation is faulty and hence the reason that I requested that you show your code.


    Quote Originally Posted by Fedaykin View Post
    ...
    Column 8 fires as the DataGridView populates for every checkbox in the grid which is fine for testing purposes, we can always remove the handler while the grid loads at a later date.
    This should not be happening if the DGV is databound and the underlying data source is updated.
    Is this a unbound DGV? It does not matter in the long run, but it is good information to know as you may need to add
    Code:
    If e.RowIndex = -1 Then Exit Sub
    as the first statement in the dgv.CellValueChange event handler to prevent errors on form creation.


    Quote Originally Posted by Fedaykin View Post
    ...
    Column 8 does not fire when the checkbox is clicked by the user. <-THIS IS THE ISSUE WITH THIS METHOD
    The only way that I know for this to happen is if this column is set to ReadOnly.
    When you state "does not fire" do you mean that the CellValueChanged eventhandler is not entered or that the desired "If-Then" block is not entered?

    Give this code a try and observe the the Output windows while interacting with the DGV.

    Code:
    Private Sub dgv_CellValueChanged(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.CellValueChanged
       If e.RowIndex = -1 Then Exit Sub
       Dim dgvSender As DataGridView = CType(sender, DataGridView)
       Console.WriteLine("Cell[{0},{1}] changed.  Column Name is: {2}.  Values stored in datarow are:", e.RowIndex, e.ColumnIndex, dgvSender.Columns(e.ColumnIndex).Name)
       For Each item As DataGridViewCell In dgvSender.Rows(e.RowIndex).Cells
          Console.WriteLine(vbTab & vbTab & If(item.Value, "Nothing").ToString)
       Next
    End Sub
    
    Private Sub dgv_CurrentCellDirtyStateChanged(ByVal sender As Object, ByVal e As EventArgs) Handles dgv.CurrentCellDirtyStateChanged
       Dim dgvSender As DataGridView = CType(sender, DataGridView)
       If dgvSender.IsCurrentCellDirty AndAlso TypeOf dgvSender.CurrentCell Is DataGridViewCheckBoxCell Then
          Console.WriteLine("Committing checkbox in column: {0}, row {1}", dgvSender.CurrentCell.ColumnIndex, dgvSender.CurrentCell.RowIndex)
          dgvSender.CommitEdit(DataGridViewDataErrorContexts.Commit)
       End If
    End Sub

  10. #10

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    Thank you for the detailed reply. I don't think anyone is a jerk, I'm thankful for the fact that you cared enough to get involved. Just a simple misunderstanding.


    This should not be happening if the DGV is databound and the underlying data source is updated.
    Is this a unbound DGV? It does not matter in the long run, but it is good information to know as you may need to add
    The DGV is populated by a pivot table that is created in the SQL database at form load (SELECT INTO...), the database table is then dropped after it populates the DGV. The information is so dynamic that it is 'old' as soon as it's populated. We only need to detect the user edit in the two columns of the DGV and then we have INSERT statements to handle the edited information based on the work order number captured in the DGV.

    When the DGV is created it is sorted by date ascending, then it is set to readonly and then two columns are set to readonly= false:

    Code:
                For Each DGVC As DataGridViewColumn In DGV.Columns
                    DGVC.ReadOnly = True          'Set the whole datagridview to Readyonly
                Next
                
                'Make only certain columns editable
                If MenuForm.ManChk.Checked = True Then
                    DGV.Columns("FLY").ReadOnly = False    'Now make only this column editable
                    DGV.Columns("SMTOrder").ReadOnly = False    'Now make only this column editable
                End If

    The only way that I know for this to happen is if this column is set to ReadOnly.
    When you state "does not fire" do you mean that the CellValueChanged eventhandler is not entered or that the desired "If-Then" block is not entered?
    In this case I mean the desired If-Then block is not entered. The textcolumn 'SMTOrder' is entered as coded. The 'FLY' checkboxcolumn 'FLY' is not entered as coded.


    I will try your code now and report back, although I don't see how both the checkbox column AND textbox column will be handled in your example.

  11. #11

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    I found the bug in my code! But not a complete resolution:

    Code:
        Sub DataGridSMT_CurrentCellDirtyStateChanged( _
        ByVal sender As Object, ByVal e As EventArgs) _
        Handles DataGridSMT.CurrentCellDirtyStateChanged   '<--------THIS LINE WAS POINTING TO DataGridView1 instead of DataGridSMT!
    
            If DataGridSMT.IsCurrentCellDirty Then
                DataGridSMT.CommitEdit(DataGridViewDataErrorContexts.Commit)
            End If
        End Sub
    
        ' If a check box cell is clicked, this event handler disables  
        ' or enables the button in the same row as the clicked cell.
        Public Sub DataGridSMT_CellValueChanged(ByVal sender As Object, _    
            ByVal e As DataGridViewCellEventArgs) _
            Handles DataGridSMT.CellValueChanged
    
            If DataGridSMT.Columns(e.ColumnIndex).Name = "SMTOrder" Then
                'do stuff
                MessageBox.Show("You edited SMT.")
                DataGridSMT.Invalidate()
            End If
    
            If DataGridSMT.Columns(e.ColumnIndex).Name = "FLY" Then
                'do stuff
                MessageBox.Show("You edited Fly.")
                DataGridSMT.Invalidate()
            End If
        End Sub
    I was handling the incorrect DGV in the code I posted earlier. I have fixed this to point to the correct DGV and the textcolumn and checkbox column IF-Then statements execute as expected, however the textcolumn IF-Then statement fires after every character typed into the box. I need it to only fire when the edit is complete, which tells me maybe I need to handle a separate CellEndEdit for this specific column? Is there a better way?
    Last edited by Fedaykin; Jan 13th, 2016 at 03:56 PM.

  12. #12

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    Okay, finally got this working. Thank you for everyone's input.
    I could only make this work by handling the checkbox column and textbox columns separately.
    I originally thought I could separate them with simple If-Then calling out which e.ColumnIndex had been edited, but this is not the case.


    Code:
        ' In your form load event remove the handler then add it back after the form loads
        ' to avoid firing the checkboxes as the database populates them in your DataGridView. 
        ' Removing the handler is especially useful if you are inserting and populating a checkbox column after grid creation.
    
        RemoveHandler DataGridSMT.CellValueChanged, AddressOf DataGridSMT_CellValueChanged
    
           'Load your DataGridView
    
        AddHandler DataGridSMT.CellValueChanged, AddressOf DataGridSMT_CellValueChanged
    
    
         'These next two subs handle the checkbox user click:
    
        Private Sub DataGridSMT_CurrentCellDirtyStateChanged(ByVal sender As Object, ByVal e As EventArgs) Handles DataGridSMT.CurrentCellDirtyStateChanged  
                                                                   '<--Note that e is EventArgs, not DataGridViewCellEventArgs!--->
    
            If DataGridSMT.IsCurrentCellDirty Then
                DataGridSMT.CommitEdit(DataGridViewDataErrorContexts.Commit) 'This commits the checkbox and automatically calls the CellValueChanged event
            End If
    
        End Sub
    
         'Second sub for handling checkbox user click
        Private Sub DataGridSMT_CellValueChanged(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles DataGridSMT.CellValueChanged
    
            If DataGridSMT.Columns(e.ColumnIndex).Name = "CheckBoxColumnName" Then
                'do stuff
                MessageBox.Show("You edited your checkbox column.")
            End If
    
        End Sub
    
    
         'This single sub handles the textbox column user edit
        Private Sub SMT_CallEndEdit(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles DataGridSMT.CellEndEdit    '<--Note e is DataGridViewCellArgs, not EventArgs
    
            If DataGridSMT.Columns(e.ColumnIndex).Name = "TextBoxColumnName" Then
                Messagebox.Show("You edited the textbox.")
            End If
    
        End Sub


    Also, just in case anyone else can benefit from it. If you both a right click context menu as well as the need to edit individual text cells you'll want to use something like this:

    Code:
        Private Sub DataGridSMT_CellClick(ByVal sender As Object, ByVal e As MouseEventArgs) Handles DataGridSMT.MouseDown
            If e.Button = Windows.Forms.MouseButtons.Right Then
                Dim hit As DataGridView.HitTestInfo = DataGridSMT.HitTest(e.X, e.Y)
                With DataGridSMT
                    .SelectionMode = DataGridViewSelectionMode.FullRowSelect
                    .MultiSelect = False  'Prevents Multiple rows from being selected
                    DataGridSMT.Rows(hit.RowIndex).Selected = True
                    DataGridSMT.ContextMenuStrip.Show(Me.DataGridSMT, New Point(hit.RowIndex, hit.ColumnIndex))
                End With
            ElseIf e.Button = Windows.Forms.MouseButtons.Left Then
                Dim hit As DataGridView.HitTestInfo = DataGridSMT.HitTest(e.X, e.Y)
                With DataGridSMT
                    .SelectionMode = DataGridViewSelectionMode.CellSelect
                    .MultiSelect = False  'Prevents Multiple rows from being selected
                End With
            End If
        End Sub

  13. #13

    Thread Starter
    Addicted Member
    Join Date
    Jul 2013
    Posts
    178

    Re: VB.net DataGridView CellContentClick and CellValueChanged

    EDIT: I had to further refine the code to prevent the CellValueChanged from firing twice. Apparently it fires once when the checkbox is Dirty and again when it is clean after the commit. To fix this I just set the DataGridView.CurrentCell = Nothing after the first fire. Since you've set the current cell to nothing, you also need to check for nothing (If IsNothing(DataGridView1.CurrentCell) Then Exit Sub)

    EDIT: I also had to get very specific about the type of column that is edited by the user by testing for TypeOf DataGridView Cell before allowing the DataGridSMT.CommitEdit(DataGridViewDataErrorContexts.Commit) to fire.

    EDIT: Finally, you need to test that the current cell is being edited when the CellValueChanged fires

    My complete code that works is here:

    Code:
        '1 of 2 subs to update a DataGridView1 checkbox click back to the database.
    
        Private Sub DataGridView1_CurrentCellDirtyStateChanged(ByVal sender As Object, ByVal e As EventArgs) Handles DataGridView1.CurrentCellDirtyStateChanged
            If IsNothing(DataGridView1.CurrentCell) Then Exit Sub
            If DataGridView1.IsCurrentCellDirty And TypeOf DataGridView1.CurrentCell Is DataGridViewCheckBoxCell Then
                DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit) 'This automatically fires the CellValueChanged event in the sub below:
            End If
        End Sub
    
    
        '2 of 2 subs that updates a DataGridView1 checkbox click
        '<--- Note that e is defined as DataGridViewCellArgs, Not EventArgs --->
    
        Private Sub DataGridView1_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
     
            If e.ColumnIndex = 8 And DataGridView1.IsCurrentCellInEditMode = True Then
                  'do code to UPDATE database
            End If
            DataGridView1.CurrentCell = Nothing
        End Sub
    
    
            '1 of 1 sub that handles the TextBoxColumn edits
    
        Private Sub Kit_CallEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit
             If IsNothing(DataGridView1.CurrentCell) Then Exit Sub
            If If e.ColumnIndex = 7 And TypeOf DataGridView1.CurrentCell Is DataGridViewTextBoxCell Then
                  'do code to UPDATE database
            End If
        End Sub
    Enjoy!
    Last edited by Fedaykin; Jan 14th, 2016 at 11:00 PM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width