New row cancel on grid not working in 2.1 ?

New row cancel on grid not working in 2.1 ?

Old forum URL: forums.lhotka.net/forums/t/1202.aspx


Ivan posted on Wednesday, September 13, 2006

After upgrading to CSLA 2.1 beta from 2.0 I have noticed strange behavior when databinding to grid (Infragistics). In 2.0 when I have clicked on the new row and started editing I could cancel the new added row by pressing Esc twice (once for cell, once again for row). In 2.1 that doesn't work. When I press Esc row clears but doesn't get removed from the grid. I have noticed that RemoveItem(int) isn't called in 2.1 but it is in 2.0. When I switch back to 2.0 everything works fine.

I have also tried new EditableRootListBase and it also doesn’t call RemoveItem when I press Esc to cancel new row.

The reason I whish to upgrade to 2.1 is EditableRootListBase which I think is very useful in my scenario (immediate insert, update, delete).

I would appreciate any help whit this.

 

ajj3085 replied on Wednesday, September 13, 2006

Certainly sounds like a bug to me.  You're subclassing BusinessListBase?

Ivan replied on Wednesday, September 13, 2006

Yes, I'm using BusinessListBase. Everything works fine with 2.0 but not with 2.1.

 

ajj3085 replied on Wednesday, September 13, 2006

I'm currently updating my UI layer to use Infragistics controls, and one of the pages has and editable grid. I'll see if I can't repo this problem as well.

Ivan replied on Wednesday, September 13, 2006

I have done some more test and have verifyed that everything work fine with versons 2.0 - 2.0.3. The problem is evident only with 2.1 (c# and VB).

RockfordLhotka replied on Wednesday, September 13, 2006

So to be clear.

You are using BusinessListBase to create a collection.

You are binding this to a grid (Infragistics).

You move to the last row in the grid, thus adding a new row.

You press ESC to cancel this new row.

The virtual/Overridable RemoveItem() method is not being invoked?

I want to be clear, because that's not my method - it is Microsoft's method. Given that BusinessListBase is the bottom of the inheritance hierarchy, it's RemoveItem() should be the one that is invoked, followed by the one in the new ExtendedBindingList, followed by BindingList<T>, etc.

I'm not saying I didn't break something, but I want to be clear on the problem before going too far. I don't have the Infragistics grid, so I'll have to try and replicate it with the DataGridView - and/or ask for your help using the debugger to walk through your code and the CSLA code to try and figure out what's going on.

RockfordLhotka replied on Wednesday, September 13, 2006

As I feared, I can't replicate the problem with the DataGridView.

I created a simple test project with a parent, childlist and child. I created a form bound to parent, with a grid bound to the childlist collection.

I can add new child objects in the grid, and press ESC and they are removed as expected.

I even added an override of RemoveItem() to ChildList so I could a breakpoint in there, and it is called as expected.

That's what I suggest you do: override RemoveItem() with a simple override that merely calls MyBase.RemoveItem(index) or base.RemoveItem(index); as you choose. Then you can put a breakpoint on that one line of code to see if it gets called as expected.

Ivan replied on Thursday, September 14, 2006

Thanks Rocky for trying to help. I have tested my code with Infragistics UltraGrid and DataGridView. With CSLA 2.0 both grids called RemoveItem that I have overrided in my collection class but with version 2.1 only DataGridView called RemoveItem.

If I call BeginEdit on my object before databinding to Infragistics UltraGrid then it calls RemoveItem and it worked fine. If this is the solution what then to call on EditableRootListBase which doesn't have BeginEdit and also doesn't work with Infragistics UltraGrid ?

RockfordLhotka replied on Thursday, September 14, 2006

Do you have to manually call BeginEdit in CSLA 2.0.x for UltraGrid to work? Or is the manual call to BeginEdit only required in 2.1?

Are you using SortedBindingList or FilteredBindingList, or just binding to a BusinessListBase-derived list directly?

Ivan replied on Thursday, September 14, 2006

I do not have to call BeginEdit in 2.0 for UltraGrid to work, only in 2.1. I use only BussineListBase derived classes. I have tried binding UltraGrid via BindingSource and directly to BLB objects and no change. Still not working.

Ivan replied on Tuesday, September 26, 2006

I still haven't find solution for this problem or find why it is behaving like this so I had to revert my code back to CSLA 2.0 release.

bmay replied on Thursday, October 05, 2006

Ivan, 

I upgraded to CSLA 2.1 (RTM) yesterday, and I was caught by your post, since I use the Infragistics WinGrid as well.  I have a BusinessListBase child inside a parent BusinessBase class, I used the Add New functionality, and I was able to click ESC (as Rocky did) to get it to delete. 

Just a note, by default, the WinGrid makes you do a double-ESC to remove the row (the first ESC just highlights the cell), but the second ESC call fully removed the row for me. (Also note, no BeginEdit was called here, this was just using the default AddRow functionality in the WinGrid)

Maybe something in the RTM fixed it? (I didn't try the beta)

Barry

Ivan replied on Friday, October 06, 2006

Barry and Rocky,

I have the same problem whit RTM. Maybe I am doing something wrong.

I have done the test project that demonstrates the problem that I have. I made one EditableRootListBase collection and one BusinessListBase. Item objects are of BusinessBase. One is marked as child and other isn't. I have created test form whit two Infragistics grids bined to two BindingSource components. At form load event I create instances of collections and give them as a datasource to binding sources (I have tried also binding them directly to grids whit same result). When I click in the addnewrow and write somethin after hitting ESC it clears the cell. On the second ESC row doesn't get removed. The solution hasCSLA 2.1 project included to easy whit debuging.

I have created copy of this solution but whit CSLA 2.0 (without EditableRootListBase) and found that OnUnknowPropertyChanged increments the edit level because of call to BeginEdit. I have replaced OnUnknownPropertyChange in 2.1 whit one from 2.0 and the problem whit BusinessListBase has been solved.

protected virtual void OnUnknownPropertyChanged()
{
     PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
     foreach (PropertyInfo item in properties)
            OnPropertyChanged(item.Name);
}

For EditableRootListBase and Infragistics grid problem is in that it calls RemoveChild that doesn't do enything. Microsoft DataGridView calls RemoveItem so it works fine. I have modified RemoveChield whit:

void Csla.Core.IParent.RemoveChild(Core.IEditableBusinessObject child) 
{
    int index;
     index =
this.IndexOf((T)child);
     if (index >= 0)
     RemoveItem(index);
}

That has solved the problem with EditableRootListBase and Infragistics grid. It also works fine whit DataGridView.

I dont't like making modifications to CSLA because of the future versions and maintainence. If anybody wants I can send both test projects so you can see for yourself what is happening.

Once again, maybe I am doing something wrong but I'm using CSLA from version 1.0.

Ivan

bmay replied on Sunday, October 08, 2006

Ivan,

I'm seeing the problem in 2.1, but I think I see the disconnect you're having with Rocky's scenario.  Rocky, I'm also seeing Ivan's scenario, which causes a problem with DataGridView (details below)...

Rocky stated in his earlier post:
-------------
I created a simple test project with a parent, childlist and child. I created a form bound to parent, with a grid bound to the childlist collection.
-------------

I was doing the exact same thing in my scenario (specifically binding the parent object to the form's separate binding source) and THAT has it working ok, including with the WinGrid.  Here's where it falls apart:

Problem Scenario: If you simply add a bindingsource tied only to the BusinessListBase, and not a separate bindingsource tied to the parent BusinessBase, then you'll see the problem (I'm seeing the problem with WinGrid or DataGridView).  In CSLA 2.0, this did not cause a problem.

Working Scenario: If you have two bindingsources, one tied to the BusinessListBase, and one to tied to the parent BusinessBase, then it'll work fine (with both WinGrid and DataGridView).

The difference (from what I'm seeing is) appears to be twofold, although I haven't figured out if #1 really is causing a problem, or why #2 is happening at all, and if it should be:
   1) The EditLevel is now based on a stack instead of a counter, and
   2) The OnPropertyChanged call (which is called on the deletion through UndoChangesComplete's OnUnknownPropertyChanged) is itself causing a BeginEdit to happen (which pushes to the stack)

The bolded check in RemoveChild's line
============
"if (IsNew && _neverCommitted && EditLevel <= EditLevelAdded)"
============
 is 1<=1 in CSLA 2.1 when it's removing properly, 0<=0 in CSLA 2.0 when it's removing properly, and 1<=0 in the Problem Scenario in CSLA 2.1.

Ivan, with the workaround above (assuming you have a parent businessbase object), I think you'll should be doing fine with it in 2.1.

Rocky, could you explain a bit more how the change to EditLevel is with 2.1, and if this parent bindingsource tie-in should always be done? Regardless, thanks for all the additions in 2.1 - the new changes look extremely useful.

Barry

RockfordLhotka replied on Tuesday, February 20, 2007

I'm addressing a couple BLB issues - or at least trying to - related to binding to a root BLB.

Unfortunately I'm unable to duplicate the issues I think are being reported.

  1. There's a failure to undo when ESC is pressed while adding the a new row in the grid control
  2. There's a null reference exception dealing with validation rules - I think when ESC is pressed in the grid, but I'm not sure

To try and isolate the issues, I've created the simplest possible editable root list and editable child combo, and bound it to a grid control. The attached project does this with CSLA version 2.1.3+ (maybe older, but I know 2.1.3 or higher is good).

If those of you having issues can make this app fail, please post a detailed list of steps to cause failure.

If you can't make it fail, try to compare it to what you have in your failing code and tell me the difference. Better yet - try to alter my code to match your failing code (without complicating the example) and post it back here.

Thanks!

Vaidal replied on Wednesday, February 21, 2007

Here you have your code modified.

We have added a property that gets the rules description (in order to configure our UI controls) and then we have eliminated the validation rules in the business base class.

Just add some rows and the nullReferenceException appears.

RockfordLhotka replied on Wednesday, February 21, 2007

Are you sure? In that code the grid is bound to the ValidationRulesDescription array, not to the business list at all, and so it is not possible to add items to the grid at all.

RockfordLhotka replied on Wednesday, February 21, 2007

Btw, I’m not asking if your bug doesn’t exist – I believe that it does – but the code in the zip file doesn’t seem to illustrate the issue.

 

Don’t spend time on it though – based on your code/description I now have a unit test that replicates the issue, so I can work on it.

 

Rocky

 

From: RockfordLhotka [mailto:cslanet@lhotka.net]
Sent: Wednesday, February 21, 2007 9:00 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] New row cancel on grid not working in 2.1 ?

 

Are you sure? In that code the grid is bound to the ValidationRulesDescription array, not to the business list at all, and so it is not possible to add items to the grid at all.

RockfordLhotka replied on Wednesday, February 21, 2007

OK, that null reference issue is fixed in the code in svn, so it will be in the next 2.1.4 release, or you can get it now at www.lhotka.net/cslacvs - the change only affects the ValidationRules class.

Vaidal replied on Wednesday, February 21, 2007

yes.... it's only an example.

In real code we are using devexpress grid and it keeps checking that Property although it's marked as not bindeable.

JZuerlein replied on Wednesday, March 28, 2007

Rocky,

I've been working on this with Microsoft for a while now.  I wrote a small project, not as small as yours, that uses data from a Northwind db, and the DataGridView control.  It exhibits the behavior of failing to undo when ESC is pressed while adding a new row to the grid.  Microsoft gave me an unreleased hotfix for System.Windows.Forms.dll.  Using the new dll, the problem goes away sometimes.  If the first column in the grid is a checkbox, a null reference exception will be thrown in the DataGridView.CancelEdit method.  I'm waiting for feedback from MS on the cause of the checkbox column problem.  I also see the null reference exception error with the the dll that shipped with VS2005 and the hotfixed version.  I have not been able to isolate it.

Can you tell me more about how it relates to validation rules?

I tried to reproduce the same problems with your code, using the original System.Windows.Forms.dll.  After adding a new row with the yellow + sign, I could not undo the action with the ESC key.  I am able to generate an "Invalid Operation" exception by starting the program, adding a new row, deleting all the rows, add a row by clicking in the empty cell, then pressing ESC.  This does not happen with the new dll.

This is one bug I really want to squish! 

Jeff

JZuerlein replied on Thursday, March 29, 2007

I downloaded CSLA 2.1.4 and spent the morning walking through the code.  I think I now understand why the ESC button was not removing the row from the grid in my program, but the checkbox column is still a problem.

Jeff

jgk1701 replied on Thursday, April 19, 2007

I just started using 2.1 with an Infragistics grid, and this is happening to me.  I read through all of the posts, but not one suggestion has fixed the issue.  Has there been a definative answer to this problem?

 

Jeff

JZuerlein replied on Thursday, April 19, 2007

 

Well....I've been using the datagridview control, so your mileage may vary, but here is a list of lessons I learned from dealing with this problem.

1)  In your BusinessListBase collection class, override the AddNewCore() function.

2) In the child object, implement a private shared variable to store the lastID that was used.  In the constructor, decrement the lastID, and assign the lastID to the unique identifier.

3) Override the GetIDValue in the child object to return the unique identifier.

4) Use version 2.1.4 of CSLA or later. (bug fixes)

5) Watch out for components that may call EndEdit or CancelEdit on the binding source.  The grid will need to call CancelEdit, and it won't if some component has already done that. (A Command management component was doing this, and it took forever to figure it out. )

6)  There is a bug in the DataGridView control that can cause a problem if you try to cancel the edit of the only row in the grid.  MS has a fix, but it has not been released yet.

7)  If the first column in a datagrid control is a checkbox column, you'll run into problems trying to cancel an edit.  It's a confirmed bug, but I have not seen the fix yet.

Hope this helps...

ajj3085 replied on Tuesday, June 19, 2007

I'm experiencing a similar problem using an Infragistics grid with an EditableRootListBase.

The behavior is slightly different though; on adding a new row via the grid, pressing ESC twice (once to cancel the cell edit, again to cancel the row edit).  The * in the row selector disappears as does the cells value.  However, the error provider icons do not (the new row initally starts invalid).

Clicking onto another row or another form element causes the grid to call EndEdit, which somehow attempts to save the row that should have been removed.  Since its not valid, a ValidationException is thrown.

RemoveItem in ERLB is never called.

Any ideas?  I'm using Csla 3.0 beta refresh 1.

ajj3085 replied on Tuesday, June 19, 2007

Ok, I tracked down why this is occuring.

Basically, CancelEdit DOES get called.  During the Canceling, OnUnknownPropertyChanged is called, which raises the event back to the BindingSource.  The BindingSource immediately calles BeginEdit again, before the cancel operation is complete.  This re-increments the EditLevel.

Then in Csla.Core.BusinessBase, CancelEdit returns, and the next statement (an if) executes.  The problem is that now EditLevel is <= EditLevelAdded ( 1 <= 0 ), and so the call to RemoveChild never executes.  Attempting to leave the row calls EndEdit, which attempts to save the new, invalid row and that is where the exception is occuring.

At this point I'm going to see if I can't intercept the grids call to CancelEdit so I can turn off RaiseListChangedEvents on the BindingSource (which I hope will callow CancelEdit to complete without the BeginEdit call).

So am I doing something wrong, or is this a bug?

Thanks
Andy

RockfordLhotka replied on Tuesday, June 19, 2007

This is by design apparently. Again, look at the current ProjectEdit form code in svn and see how I did the Cancel button. Kind if a PITA, but that appears to be the correct solution.

ajj3085 replied on Tuesday, June 19, 2007

I think I might be missing something.  One difference between the sample (which I'm browsing in svn) is that I have an EditableRootListBase subclass for the collection in question.

Implementing code similar to the ProjectEdit.cs, things behave more correctly (as far as EditLevel goes), but the item does not get removed, because ERLB does nothing when Csla.Core.IParent.RemoveChild is called (via the item's CancelEdit).

I will add some code to handle this scenario... is that the proper way to proceed?

Code as currently implemented:
        private void DocumentCategoriesGrid_BeforeRowCancelUpdate( object sender, CancelableRowEventArgs e ) {
            IEditableObject assignment;

            DocumentCategoryBindingSource.RaiseListChangedEvents = false;
            DocumentCategoryBindingSource.DataSource = null;

            assignment = (IEditableObject)e.Row.ListObject;
            assignment.CancelEdit();

            // Add code here to remove item from collection?

            DocumentCategoryBindingSource.DataSource = assignments;
            DocumentCategoryBindingSource.RaiseListChangedEvents = true;
            DocumentCategoryBindingSource.ResetBindings( false );

            e.Cancel = true;
        }

RockfordLhotka replied on Tuesday, June 19, 2007

Hmm, it could be a bug in 2.1. I know there were some collection-based issues I fixed in 3.0 and this could be one of them.

I just created a simple test in 3.0 using the DataGridView, and I can add, remove, edit objects no problem - including using ESC to cancel an addnew.

Copyright (c) Marimer LLC