Wednesday, October 3, 2007

Multi row delete in DataGridView

A couple of weeks ago a colleague of mine asked me about how to have a delete confirmation dialog to show only once even if there is multiple rows to be deleted from a System.Windows.Forms.DataGridView.
There are three events on the DataGridView which is directly related to row deletion: "RowsRemoved", "UserDeletedRow" and "UserDeletingRow". Entertaining enough all of them are called once for each row that is to be deleted.

Sadly I did not have a solution at hand and I kept wondering how to solve that problem. Today I sat down and tried to solve the problem.

I quickly found that adding a KeyDown event handler and then monitor the Delete key could do the trick. All I had to do was to ask the user and set "e.Handled" to true if I did not want to delete the rows.

  private void fruitsDataGridView_KeyDown( object sender, KeyEventArgs e )

  {

   Int32 count = this.fruitsDataGridView.SelectedRows.Count;

   if( count.Equals( 0 ) )

   {

    return;

   }

 

   e.Handled = !this.ConfirmDeletion( count );

  }


However, simple as it was I did not like the solution. So I started looking at the Call Stack to see which methods would help raising the three events that is raised once per row. A couple of lines down the Call Stack I found a method named "ProcessDeleteKey", nice! This method was for once not marked private or internal, but someone "forgot" to add the virtual keyword to the method's signature, so I were not able to override it. So I looked at the method that called the "ProcessDeleteKey". It is named "ProcessDataGridViewKey" and is both protected and virtual. So I quickly made a new class inheriting from DataGridView and made an overridden "ProcessDataGridViewKey" method where I could check for the Delete key and take action if needed. Additionally I added a new event to the class named UserDeletingRows that would be called once per deletion batch.

  protected virtual Boolean ProcessDeleteKey( KeyEventArgs e )

  {

   if( !this.AllowUserToDeleteRows )

   {

    return false;

   }

 

   if( this.EditingControl != null )

   {

    return false;

   }

 

   CancelEventArgs args = new CancelEventArgs( false );

   this.OnUserDeletingRows( args );

   if( args.Cancel )

   {

    return true;

   }

 

   return base.ProcessDeleteKey( e.KeyData );

  }


The Solution
Although the first solution is simpler, I find that the second solution is much better, because having the implementation within the grid class should make it be used more often. If only I can find a better name for the new event.

Both solutions are included in the downloadable project.

Download
To download the full project click here.


Solution: Visual Studio 2005
Language: C#
Framework: 2.0

1 comments:

Anonymous said...

I found this site using [url=http://google.com]google.com[/url] And i want to thank you for your work. You have done really very good site. Great work, great site! Thank you!

Sorry for offtopic