Delete multiple records from a sorted databound DataGridview

Posts   
 
    
Posts: 35
Joined: 19-Mar-2007
# Posted on: 22-Mar-2007 09:42:16   

Hi!

I found trouble when I was about to delete multiple records from a DataGridView that is databound to a collection class.

If I haven't sorted the DataGridView it all works fine and as expected, but ones I've sorted the data by clicking one of the column headers it doesn't quite work. When I debug I can see that after the first delete action the underlying code seems to start reloding the data from my collection into the DataGridView control and thus breaking the chain of events fired by the initial delete action.

I have tried to find a way around this and guess that one way would be to not perform the actual entity.Delete() in the delete event chain fired by the DataGridView control, but instead collect info and wait until all those events have come to an end before persisting. This way however, I would find myself in a cumbersome situation if any of those deletes causes an error. I would have to store the way the DataGridView was sorted and reload the data from SQL to restore the current situation.

Before doing these modifications to my code I just want to know if I'm missing something. Is there a better way? Can I pause the reloding of the sorted DataGridView by queuing what I think is binding events fired from the collection? Or...?

These are the two events that I use to delete multiple records in the UNSORTED DataGridView control that works just fine (but mal functions when sorted).



        private void OnUserDeletingRowPersonsDataGridView(object sender, DataGridViewRowCancelEventArgs deleteRowEventArgs)
        {
            if (!m_IsDeleting && !m_HasCancelledDeleting)
            {
                m_DeleteCount = m_PersonsDataGridView.Rows.GetRowCount(DataGridViewElementStates.Selected);
                DialogResult deleteAnswer = MessageBox.Show(Utility.FormatString(LanguagesBusiness.GetTranslatedMessage("AreYouSureYouWantToDeleteRecords"), m_DeleteCount.ToString()), "", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
                if (deleteAnswer == DialogResult.Yes)
                {
                    m_IsDeleting = true;
                }
                else
                {
                    deleteRowEventArgs.Cancel = true;
                    m_HasCancelledDeleting = true;
                }
            }
            if(m_HasCancelledDeleting)
            {
                deleteRowEventArgs.Cancel = true;
                m_DeleteCount--;
            }
            if (m_IsDeleting)
            {
                PersonsEntity person = (PersonsEntity)deleteRowEventArgs.Row.DataBoundItem;
                if (!person.Delete())
                {
                    MessageBox.Show(Utility.FormatString(LanguagesBusiness.GetTranslatedMessage("FailedToDeletePerson"), person.FullName), "", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                    deleteRowEventArgs.Cancel = true;
                    m_HasCancelledDeleting = true;
                    m_DeleteCount--;
                }
            }
        }

        private void OnUserDeletedRowPersonsDataGridView(object sender, DataGridViewRowEventArgs e)
        {
            m_DeleteCount--;

            if (m_DeleteCount == 0)
            {
                m_IsDeleting = false;
                m_HasCancelledDeleting = false;
            }
        }

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 22-Mar-2007 10:06:09   

My first guess is that you should remove the deleted entity from the bound collection as well, or you should refetch the entityCollection from the database. So when an entity is selected for deleteion, it should be deleted from the database and removed from the underlying entityCollection.

Posts: 35
Joined: 19-Mar-2007
# Posted on: 22-Mar-2007 17:55:24   

I tried that. I added code like entityCollection.Remove(entityThatHasBeenDeletedFromDb). This makes it even worse. Now I can't delete multiple UNSORTED records. I guess this has to do with that the DataGridView propagates a remove to the underlying collection via the binding source object. I don't know if this is a fact, but I think so, as it worked on unsorted data before and this is also what I can see while debugging.

Refetching the collection is something I'd like to avoid as the amount of data in the grid might be quite big.

Any other clues?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 23-Mar-2007 09:20:19   

Which runtime library version are you using?

Posts: 35
Joined: 19-Mar-2007
# Posted on: 23-Mar-2007 10:17:30   

I'm using v2.0.50727 of SD.LLBLGen.Pro.ORMSupportClasses.NET20

I'm going to try a new approach in the meantime though.

Hypothesis:

Use Delete() and Remove() on the bound collection and override the default behaviour of the DataGridView's delete; i.e cancel every delete event fired by the grid and collect info for the custom delete/remove of the bound collection once all those delete events have come to an end.

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 23-Mar-2007 15:07:13   

I'm using v2.0.50727

That's not a valid RTL version number. Please check the following thread to know how to get the RTL version number: http://llblgen.com/TinyForum/Messages.aspx?ThreadID=7720

Posts: 35
Joined: 19-Mar-2007
# Posted on: 23-Mar-2007 15:12:46   

Ok!

Version 2.0.0.0 Final

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 23-Mar-2007 15:21:14   

The runtime library version is obtainable by rightclicking the SD.LLBLGen.Pro.ORMSupportClasses.NETxy.dll in windows explorer and then by selecting properties and the version tab. The version is then enlisted at the top as the fileversion. It has the typical format as 2.0.0.YYMMDD, or starting in 2007, the format 2.0.YY.MMDD

Posts: 35
Joined: 19-Mar-2007
# Posted on: 23-Mar-2007 19:44:36   

Sorry about that. This should be the requested version number: 2.0.0.61005

Posts: 35
Joined: 19-Mar-2007
# Posted on: 24-Mar-2007 07:28:36   

Okey! I got it to work in a satisfying way now.

I do as I suggested earlier. Modifying the defualt behaviour of the DataGridView controls UserDeletingRow event by collecting info on what to delete and cancelling every one of those events to prevent the grid to be updated before the actual delete/remove is done on the bound collection instead.

Some code below for the one's that are in needsimple_smile


        private void OnUserDeletingRowPersonsDataGridView(object sender, DataGridViewRowCancelEventArgs deleteRowEventArgs)
        {
            try
            {
                if (!m_IsDeleting && !m_HasCancelledDeleting)
                {
                    m_DeleteCount = m_PersonsDataGridView.Rows.GetRowCount(DataGridViewElementStates.Selected);
                    DialogResult deleteAnswer = MessageBox.Show(Utility.FormatString(LanguagesBusiness.GetTranslatedMessage("AreYouSureYouWantToDeleteRecords"), m_DeleteCount.ToString()), "", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
                    if (deleteAnswer == DialogResult.Yes)
                    {
                        m_IsDeleting = true;
                    }
                    else
                    {
                        deleteRowEventArgs.Cancel = true;
                        m_HasCancelledDeleting = true;
                    }
                }
                if (m_HasCancelledDeleting)
                {
                    deleteRowEventArgs.Cancel = true;
                    m_DeleteCount--;
                }
                if (m_IsDeleting && !m_HasCancelledDeleting)
                {
                    try
                    {
                        PersonsEntity person = (PersonsEntity)deleteRowEventArgs.Row.DataBoundItem;
                        m_PersonsCollection.AddEntityToRemove(person);
                        deleteRowEventArgs.Cancel = true;
                        m_DeleteCount--;
                    }
                    catch (Exception deleteException)
                    {
                        // TODO : handle error
                        throw;
                    }
                }

                if (m_DeleteCount <= 0)
                {
                    m_IsDeleting = false;
                    m_HasCancelledDeleting = false;
                    m_PersonsCollection.RemoveEntitiesToRemove();
                }
            }
            catch (Exception deleteEventException)
            {
                MessageBox.Show(LanguagesBusiness.GetTranslatedMessage("FailedToDeletePerson"), Blank, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                m_HasCancelledDeleting = true;
                m_DeleteCount--;
            }
        }


To support this delete method I added custom props/methods to my collection class:


        private PersonsCollection m_EntitiesToRemove;

        public PersonsCollection EntitiesToRemove
        {
            get
            {
                if (m_EntitiesToRemove != null)
                {
                    return m_EntitiesToRemove;
                }
                else
                {
                    return new PersonsCollection();
                }
            }
        }

        public void AddEntityToRemove(PersonsEntity entityToRemove)
        {
            if (m_EntitiesToRemove == null)
            {
                m_EntitiesToRemove = new PersonsCollection();
            }
            m_EntitiesToRemove.Add(entityToRemove);
        }

        public void ResetEntitiesToRemove()
        {
            if (m_EntitiesToRemove != null)
            {
                m_EntitiesToRemove.Clear();
            }
        }

        public void RemoveEntitiesToRemove()
        {
            foreach (PersonsEntity person in m_EntitiesToRemove)
            {
                this.Remove(person);
            }
            m_EntitiesToRemove.DeleteMulti();
            ResetEntitiesToRemove();
        }


This is still a bit rough around the edges as it needs error handling and the ResetEntitiesToRemove() method seems unnecessary. confused