New Posts New Posts RSS Feed: DataGridView Cancel New Row
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

DataGridView Cancel New Row

 Post Reply Post Reply
Author
Customer View Drop Down
Senior Member
Senior Member
Avatar
User Submitted Questions to Support

Joined: 30-May-2007
Location: United States
Posts: 260
Post Options Post Options   Quote Customer Quote  Post ReplyReply Direct Link To This Post Topic: DataGridView Cancel New Row
    Posted: 16-Jul-2007 at 9:52am
I am using a DataGridView with an Add Row at the bottom  (* row) to allow my
users to input new data directly into the grid.  I run into a problem when
the user clicks into the add row by accident, and then immediately clicks
out without changing any data.  What happens here is that the new row (which
was created in the PersistenceManager via the bindingSource "AddingNew"
event) is removed from the grid automatically, but it is not actually
removed from the PersistenceManager cache.  If the user saves the graph back
to the server and reloads it, a blank row will now be visible in the grid,
even though they thought that it was gone.  During testing, I can click in
and out of the add row several times and I end up with several extra, blank
detail lines in my grid after saving.

Is there a way to handle "cancel new row" events on the DataGridView so that
I can delete the *accidental* object from the PersistenceManager?

Back to Top
IdeaBlade View Drop Down
Moderator Group
Moderator Group
Avatar

Joined: 30-May-2007
Location: United States
Posts: 353
Post Options Post Options   Quote IdeaBlade Quote  Post ReplyReply Direct Link To This Post Posted: 16-Jul-2007 at 9:54am

The .NET DataGridView just doesn't seem quite to have the hook we need.  The following gets pretty close:

1. Declare at the class level in the Form or UserControl that contains the grid:
        Order mLastOrderAdded;

2. Handler for the BindingSource's AddingNew event:
        void mOrdersBS_AddingNew(object sender, AddingNewEventArgs e) {
            mLastOrderAdded = AddNewOrder();
            e.NewObject = mLastOrderAdded;
        }

3. Handler for the grid's KeyDown event:
      void mOrdersDGV_KeyDown(object sender, KeyEventArgs e) {
         if (e.KeyValue == 27) {
            //if (mOrdersDGV.CurrentRow.IsNewRow) {
            //if (mOrdersDGV.CurrentRow.Index == mOrdersDGV.NewRowIndex - 1) {
            if (mOrdersDGV.CurrentRow.DataBoundItem.Equals(mLastOrderAdded)) {
               mLastOrderAdded.Delete();
            }
         }
      }

This combination does the needful; unfortunately it will also delete the same row later if the user is (a) on that row, (b) presses ESC, and (c) no other row has been added since.  Unfortunately, the NewItem row seems to become a non-NewItem row as soon as a created object is passed to it (as above in mOrdersBS_AddingNew() when the new Order is assigned to e.NewObject).  So the IsNewRow test in the KeyDown handler (commented out) fails.  If ESC was pressed on the row just added by clicking in the NewItem row, the test (mOrdersDGV.CurrentRow.Index == mOrdersDGV.NewRowIndex - 1; also commented out) succeeds, only because there's now a NewItem row with an index one higher than the one where the user is doing the editing.  And that test can't distinguish between a last row just added using the NewItem row, and a last row that has been there for 20 minutes, with lots of editing going on in other rows, in between.

One piece of good news is that the code above doesn't cause deletion of the row containing the mLastOrderAdded if the user presses ESC while editing the value in a particular cell in that row. That press of ESC seems to get eaten in the process of undoing the cell edit, and doesn't trigger the DataGridView's KeyDown event.

By the way, I also explored the RowsRemoved, Validating, RowLeave, and CancelRowEdit events of the DataGridView, and the ListChanged event of the BindingSource that supplies the grid, without any success. It may simply be that the DataGridView is just a bit too DataSet- and DataTable-oriented to handle this particular occurrence well.  Perhaps the DevExpress or Infragistics grid does a better job.  Wish I had better news.

Back to Top
IdeaBlade View Drop Down
Moderator Group
Moderator Group
Avatar

Joined: 30-May-2007
Location: United States
Posts: 353
Post Options Post Options   Quote IdeaBlade Quote  Post ReplyReply Direct Link To This Post Posted: 16-Jul-2007 at 9:54am
Did you ever get any further with this?  I've beat my head against it a bit more, and while it seems like it would be possible to make it work by setting flags and using events like RowLeave and RowEnter to keep up with what the user is doing, in practice that seems unsatisfactorily complicated.
 
I tried doing the same thing with the Developer Express XtraGrid, and it behaves much more predictably. The user can locate herself in the NewItemRow, then navigate out without entering anything, and no trace is left.  ESCaping out is not supported; once data has been entered, the row stays. But that works, too, since it is then clearly apparent as an unwanted row, and can simply be deleted by the normal means. 
 
On the other hand, we've had other not-so-felicitous behavior reported with respect to the NewItemRow in the XtraGrid, having to do with the first character entered in the first cell of the NewItemRow getting "eaten".  I'm unable to reproduce that behavior at the moment in my NewItemRow app, but I did reproduce it before, so maybe the event handlers I've got wired up in the current one are affecting its behavior.  The sum of my experience to date with the NewItemRow, in multiple grids, is that it's a tricky son of a gun.
Back to Top
Dominique View Drop Down
Groupie
Groupie
Avatar

Joined: 28-Jun-2007
Location: Norway
Posts: 44
Post Options Post Options   Quote Dominique Quote  Post ReplyReply Direct Link To This Post Posted: 18-Jul-2007 at 6:36am
Hi,
I was just about to post a hack about the dotNet datagridView and it looks like it should be here.
Facing the same problem I solved it by calling the ResetBindings(False) method on the bindingSource.
The behaviour of the datagridview will then be much more predictable because each new row will appear in the grid right away.
I just tried on a demo app so I don't know if it will be sideeffects.
Does someone have any comments on using this hack? would it have consequences on the responsivness of the app?

In the Ideablade tutorial "Adding and Deleting Child Business Objects in a Grid" that means replacing

Private Sub OrderAddingNew(ByVal sender As Object, _
       ByVal e As System.ComponentModel.AddingNewEventArgs)      
    e.NewObject = Me.NewOrder()
End Sub

with

Private Sub OrderAddingNew(ByVal sender As Object, _    
       ByVal e As System.ComponentModel.AddingNewEventArgs)      
    e.NewObject = Me.NewOrder()      
    mOrdersBS.ResetBindings(False) // will show the new row in the grid
End Sub


Dominique
Back to Top
Dominique View Drop Down
Groupie
Groupie
Avatar

Joined: 28-Jun-2007
Location: Norway
Posts: 44
Post Options Post Options   Quote Dominique Quote  Post ReplyReply Direct Link To This Post Posted: 19-Jul-2007 at 2:03am
Hi,
I have some comments after further testing of the above named solution to work around the "phantoms" row in the datagridview.
Originally posted by My self

I solved it by calling the ResetBindings(False) method on the bindingSource.
would it have consequences on the responsivness of the app?

When I tried this hack on my real app' I got some "reentrant exceptions" when the collection shown in the grid is empty. I don't know the accurate reason but I guess it has to do with the timing when the row is added to the bindinsource.
To solve this I now update the list right after having created the new row as illustrated under.


private mOrderListe as EntityList(of Order) = new ...
Private Sub Onload(...)
    mOrdersBS.datasource = mOrderListe
    mOrderListe.replaceRange(the_right_collection)
end sub

Private Sub OrderAddingNew(ByVal sender As Object, _
       ByVal e As System.ComponentModel.AddingNewEventArgs)      
    e.NewObject = Me.NewOrder()
   mOrderListe.replaceRange(new list(of CurrentCustomer.Orders)) 'or what ever the it should be
End Sub


It looks like it's doing the job, but I would appreciate any comments about this fix.

Dominique

Edited by Dominique - 19-Jul-2007 at 3:53am
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down