Link to home
Start Free TrialLog in
Avatar of FMabey
FMabeyFlag for United Kingdom of Great Britain and Northern Ireland

asked on

RejectChanges Issue??

Hi all,

I have the following code which checks to see if a part number already exists when a user edits an existing part number. If it does, the changes will be rejected:

    Private Sub DGV_stiffs_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DGV_stiffs.CellValueChanged

        Dim dg As DataGridView = CType(sender, DataGridView)

        If e.RowIndex >= 0 AndAlso e.RowIndex < dg.RowCount Then

            Dim row As DataGridViewRow = CType(dg.Rows(e.RowIndex), DataGridViewRow)

            Dim STR_part As String

            If IsDBNull(Me.DGV_stiffs.CurrentRow.Cells("PRT_MARK_STF").Value) Then

                STR_part = ""

            Else

                STR_part = Me.DGV_stiffs.CurrentRow.Cells("PRT_MARK_STF").Value

            End If

            Dim STR_gdr As String

            If IsDBNull(Me.DGV_stiffs.CurrentRow.Cells("PRT_GDR_NO_STF").Value) Then

                STR_gdr = ""

            Else

                STR_gdr = Me.DGV_stiffs.CurrentRow.Cells("PRT_GDR_NO_STF").Value

            End If

            If Not (row.IsNewRow) Then

                ' Check is the part editted has already been nested.
                If DGV_stiffs.CurrentRow.Cells("PRT_REM_QUANT_STF").Value = 0 Then

                    ' Check if the field editted is either item mark or girder number
                    If e.ColumnIndex = row.Cells("PRT_MARK_STF").ColumnIndex Or e.ColumnIndex = row.Cells("PRT_GDR_NO_STF").ColumnIndex Then

                        Dim partrow1 As DataRow() = DS_parts_quick1.PART_QUICK.Select(String.Format("PRT_MARK = '{0}'", STR_part))

                        If partrow1.Length > 0 Then

                            DV_stiffs.Item(DGV_stiffs.CurrentCellAddress.Y).Row.RejectChanges()
                            MsgBox("Part already exists")

                        End If

                    End If

                End If

            Else

                ' If the part has been nested (greater than 0), warn the user.
                MsgBox("This part has already been nested." & vbCrLf & "You cannot edit nested items.", MsgBoxStyle.Exclamation, "Nested Item")

                ' Reset the row...
                DV_stiffs.Item(DGV_stiffs.CurrentCellAddress.Y).Row.RejectChanges()

            End If

        End If

    End Sub

All is fine until I enter a part that already exists. When I do this the code fires as I would expect, warning the user and rejecting the changes (returning the row to its original state). However, if I then try and re-enter a part that does not exist, the warning fires again and the rejectchanges fires. No matter what I type in after triggering the warning the 1st time, it will trigger the warning and rejectchanges.

Has anyone any ideas on what I'm doing wrong? This has only started happening since I put in the following line of code afte the length if statement:
DV_stiffs.Item(DGV_stiffs.CurrentCellAddress.Y).Row.RejectChanges()

Thanks in advance
Avatar of Sancler
Sancler

What you need to bear in mind is that - at the level when the CellValueChanged event fires - any edited value may not yet have found its way back to the datasource.  Changes in a DataGridView are only committed to its DataSource when either the user moves to a new row/record or there is explicit calling of some "committal" method - like BindingSource.EndEdit or CurrencyManager.EndCurrentEdit.  So calling .RejectChanges on the DataRow in the DataSource may have no effect.  It may well still be in its original state.  And your code does nothing to change the state of the DataGridViewRow itself so, even if the DataRow in the datasource is returned to its original state, the existing edit in the DataGridViewRow remains as it was - hence the repetition of your error message.

What you need to use is CancelEdit on the DataGridView itself.  That, as the docs say, "Cancels edit mode for the currently selected cell and discards any changes."

The other, general, point that it might be worth making is that your code seems to be using at least three different references to the same ultimate object.  You declare and fill your variable 'row' with the DataGridViewRow from DGV_Stiffs.  You then go on to (possibly) make changes direct to the CurrentRow (which I assume is the same as that you have put into 'row') of DGV_Stiffs.  You then check the .IsNewRow property of 'row' itself.  Then you check a value in DGV_stiffs.CurrentRow, and then go on to check column Indexes in 'row'.  And you then get hold of the actual DataRow (rather than the DataGridViewRow) by applying the CurrentCellAddress of DGV_Stiffs to the DV_Stiffs (I assume a DataView to which DGV_Stiffs is bound) Items collection.  While - saving the point made above - that may work, it makes it quite difficult to find one's way round your code.

Roger
Avatar of FMabey

ASKER

Thanks for your help on this Roger.

As I'm self taught I suspect I've picked up some pretty bad habits and ways of doing things! Some of which you've highlighted above! I have got myself a little muddled on this.

I've tried using DGV_stiffs.CancelEdit() in my code but it leaves the typed value in the cell.
Sorry, my fault.  CellValueChanged only fires when the user has moved to another cell.  So then the CurrentCell is not the one that you want to restore.  You'd do better to use CellValidating.  That fires before the move to another cell is implemented.

Roger
Avatar of FMabey

ASKER

Will my code work under the CellValidating? Wont it be looking at the wrong values (old values rather than new)?
ASKER CERTIFIED SOLUTION
Avatar of Sancler
Sancler

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of FMabey

ASKER

Good example. I like that.. I'll have a play with this and get back to you a s a p.

thanks again Roger.
Avatar of FMabey

ASKER

Roger,

I've had a play around and I think this will do just the job. One quick question.

Is there an easy way of determining whether or not a field has actually been editted? At the moment the cellvalidating fires every time a cell is entered. I have placed a boolean variable in CellBeginEdit which turns true if a cell has been editted. I then place the CellValidating code within:
If BOO_edit = True then
'Code
End if
If you want to miss out the tests if the cell being validated is not in edit mode, then you could use

        If Not DataGridView1.Item(e.ColumnIndex, e.RowIndex).IsInEditMode Then Exit Sub

If, even if it was in edit mode, you wanted to miss out the tests if the value was unchanged, then you could use

        If e.FormattedValue = DataGridView1.Item(e.ColumnIndex, e.RowIndex).Value Then Exit Sub

And, no doubt, there are other variations on the theme ;-)

Roger
Avatar of FMabey

ASKER

Excellent solution... Provides a solution which still allows you to do the work and learn.