Link to home
Start Free TrialLog in
Avatar of LenTompkins
LenTompkinsFlag for United States of America

asked on

InvalidOperationException Occurs When Editing the Last Row After Previously Deleting the last Row from a DataGrid

I am having a problem when I delete the last row of a table.  The delete will work properly, but if I then edit the new last row I am getting an Invalid Operation Exception from my CurrentChanged Event Handler.   What I noticed is that when I am deleting the last record, it does the delete to the datagrid then jumps to the CurrentChanged event handler and after it finishes, it goes back and finishes the rest of the delete routine.  Why is it doing this?  Any thoughts?

    // Instantiate binding source for binding navigator
            this.m_srcCollectionHistoryType = new BindingSource();
            this.m_srcCollectionHistoryType.DataSource = this.m_dsCollectionHistory.CollectionHistoryType;

            this.grdCollectionHistoryType.AutoGenerateColumns = false;

            this.grdCollectionHistoryType.DataSource = this.m_srcCollectionHistoryType;
            this.navCollectionHistoryType.BindingSource = this.m_srcCollectionHistoryType;

this.m_srcCollectionHistoryType.CurrentChanged += new EventHandler(m_srcCollectionHistoryType_CurrentChanged);


//Event Handlers
        private void btnDeleteCollectionHistoryType_Click(object sender, EventArgs e)
        {
            DataRowView rowView =
                (DataRowView)this.grdCollectionHistoryType.CurrentRow.DataBoundItem;
            try
            {
                string currentRow = rowView["Type"].ToString();
                if (currentRow == "Unknown")
                {
                    MessageBox.Show("You cannot delete an 'Unknown'");
                    return;
                }

                rowView.Delete();      <-- Jumps to CurrentChanged event handler after executing this statement
                int recordsAffected =
                    this.m_adpCollectionHistoryType.Update(rowView.Row);
                MessageBox.Show(string.Format("Collection History Type: '{0}' deleted.", currentRow));
            }
            catch (InvalidConstraintException)
            {
                MessageBox.Show("You cannot delete a record that is linked to records in Collection History Key Table!");
            }
            catch (SqlException)
            {
                MessageBox.Show("You cannot delete this record!");
            }
        }

private void m_srcCollectionHistoryType_CurrentChanged(object sender, EventArgs e)
        {
            if (this.grdCollectionHistoryType.CurrentRow == null) return;
           
 
            if (this.grdCollectionHistoryType.CurrentRow.Index == (this.grdCollectionHistoryType.RowCount - 1))
            {
                this.grdCollectionHistoryType.DataSource = null;                     <---- Causes InvalidOperationException occurs here
                this.grdCollectionHistoryType.DataSource = m_srcCollectionHistoryType;
            }
 
Avatar of 13598
13598
Flag of United States of America image

CurrentChanged is triggered when the bound value changes but you are trying to use the datagridview when erroring, correct? grdCollectionHistoryType is yout dgv?
It may be that you deleted the last row but didn't commit the change to the bindingsource yet?
So currentrow and bindingsource row are out of synch one doesnt exist and the other one still does?
You could try either changing your code to use the bindingsource for what you are doing or commiting the changes righ before by using bindingsource.endedit at the beginning of your event?
Avatar of LenTompkins

ASKER

I am new to coding in C# but how do I commit the change to the binding source?  I thought that when you update the table adapter, the binding source gets updated as well.
Using:
Bindingsource.EndEdit()     (Replace Bindingsource with the actual name of your bindingsource)
When the EndEdit method is called, all pending changes are applied to the underlying data source.
I just tried that and the delete works, but when I then edit the last row of the table I am getting an "Operation is not valid because it results in a re-entrant call to the set current cell address core function.  It is occrring in:
 if (this.grdCollectionHistoryType.CurrentRow.Index == (this.grdCollectionHistoryType.RowCount - 1))
            {
                this.grdCollectionHistoryType.DataSource = null;
                this.grdCollectionHistoryType.DataSource = m_srcCollectionHistoryType;
            }
I added the following code so that when I added a new record to the end of the table and then deleted it, the code was abending.  I thought this would resolve it, but now after I have added a new record, then deleted it, and then edited the last row, I get this error.  
I would move this to the delete routine, but after I do:
rowView.Delete();    it jumps to the CurrentChanged method.

Am I going about this all wrong?
What are you trying to accomplish with that code?
I added the code to bypass an error that I was getting after deleting the last row of the table.  I just commented out that code, and added a new record then deleted it.  After it does the delete statement, it jumps to the Current Changed method and abends with System Index out of range exception. Everytime I come into this current changed, should I perform an end-Edit so that the binding source is in sync?
Are you saying it abends in the currentchanged even if there is no code there?
Remove the code and let's figure out the problem.
That code was just because of the error correct? You don't actually need to do anything?
Here is the routine the way I now have it:
private void m_srcCollectionHistoryType_CurrentChanged(object sender, EventArgs e)
        {
            if (this.grdCollectionHistoryType.CurrentRow == null) return;

            if (this.grdCollectionHistoryType.CurrentRow.Index == (this.grdCollectionHistoryType.RowCount - 1))
            {
          //      this.m_srcCollectionHistoryType.EndEdit();
               // this.grdCollectionHistoryType.DataSource = null;
               // this.grdCollectionHistoryType.DataSource = m_srcCollectionHistoryType;
            }

            //Save original 'Type' column in case it needs to be restored
            int rowIndex = this.grdCollectionHistoryType.CurrentRow.Index;

            DataRow row = this.m_dsCollectionHistory.CollectionHistoryType.Rows[rowIndex];

            string origType = row["Type", DataRowVersion.Original].ToString();

            //this.grdCollectionHistoryType.EndEdit();
            try
            {
                DataRowView drv = (DataRowView)this.grdCollectionHistoryType.CurrentRow.DataBoundItem;

                if (drv.Row.RowState == DataRowState.Modified)
                {
                    if (origType == "Unknown")
                    {
                        MessageBox.Show("You cannot modify an 'Unknown'");
                        // Change Type back to "Unknown"
                        this.m_dsCollectionHistory.CollectionHistoryType[rowIndex].Type = origType;
                        return;
                    }

                    //Update "Last Touched By" & "Last Touched Date" columns before saving updated record
                    this.m_dsCollectionHistory.CollectionHistoryType[rowIndex].LastTouchedBy =
                                            SystemInformation.UserName;
                    this.m_dsCollectionHistory.CollectionHistoryType[rowIndex].LastTouchedDate = DateTime.Now;

                    int recordsAffected =
                         this.m_adpCollectionHistoryType.Update(drv.Row);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
   
When I delete the last row, after the delete, it goes right to this current changed and I am getting an error on:
 DataRowView drv = (DataRowView)this.grdCollectionHistoryType.CurrentRow.DataBoundItem;

saying the row index is out of bounds.  
How should I resolve this?
I don't fully understand what you are doing and why you are doing it in this event but to solve your issue I would try not using CurrentRow since that is the problem. Your CurrentRow is not pointing at the right place.
Doesn't your e arg give you the rowindex. Use that instead?
Something like:
DataRowView drv = (DataRowView)this.grdCollectionHistoryType.e(RowIndex).DataBoundItem;
The dataRow View statement doesn't work here.  It says that Systems.Form.datagrid doesn't contain a definition for e.

I have this routine, because, when I want to change a row's text we have one row that can never be changed.  I was defining a row view to see if the original text =" UnKnown".  If it is, the change will be cancelled, otherwise it continues on.  where else can I perform this test?
ASKER CERTIFIED SOLUTION
Avatar of 13598
13598
Flag of United States of America image

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
No I don't but I will try that now.  Thank you for all of your assistance.  I'll try it now and get back to you.
Yes,  Thank you very much.  I finally solved the problem by getting rid of CurrentChanged performing a Row Validation.   Then I asked if the field was equal to the string Unknown and if it was, I then created the data row view to determine if the row state was modified.  It now works.
I and some other new programmers have been working on this problem for over 1 week.
Nicely done.  Glad I could help.