Infragistics Wingrid ICancelAddNew - unused new row not cancelling

Infragistics Wingrid ICancelAddNew - unused new row not cancelling

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


Tom_W posted on Tuesday, April 28, 2009

Hi All,

first poster I'm afraid!  I have spent the last month or so going up the CSLA curve, and I'm loving the framework, it is an awesome achievement Cool [H].

I've been working up a simple winforms test app of the standard contact/order header/order line ilk and have hit a problem with the infragistics wingrid, which I'm hoping someone may be able to help with.  The scenario is as follows:


The above all saves/updates/deletes correctly and is generally great. 


However, when I switch to using an Infragistics WinGrid instead of the Windows DataGridView, the new row adding no longer works as expected:


I have had this same problem with Infragistics grids on a framework we wrote and never found a solution, so I'm guessing this maybe an Infragistics issue, but, what I'm hoping is that someone here could tell me:

  1. Has anyone else experienced this?
  2. Is this expected behaviour for infragistics wingrids?
  3. Is there a workaround?

Many thanks in advance

Tom


Versions:
- OS: Windows XP
- .NET: 3.5 SP1
- VS: 2008
- CSLA: 3.6.2
- Infragistics: V8.2

RockfordLhotka replied on Tuesday, April 28, 2009

You might try a small sample of your scenario using the standard Microsoft DataGrid control to help establish whether it is Infragistics, data binding, your object or CSLA that is causing the problem.

Tom_W replied on Tuesday, April 28, 2009

Hi Rocky

Thanks for your thoughts, I started with the vanilla Windows DataGridView and it worked absolutely fine (details of how I added it etc are in the original post).  No doubt it is either my crappy code or the Infragistics control - I've had this problem with custom business object binding before with these controls and never solved it.

What would be great is to know if anyone has made the Infragistics WinGrid cancel newly added rows successfully and if so what they did to make it play nicely? 

Cheers,

Tom
 

Tom_W replied on Wednesday, April 29, 2009

Hi Rocky

I posted a version of my original question on the Infragistics forums too.  Mike Saltzman raised the following thoughts (http://news.infragistics.com/forums/t/24944.aspx):

ICancelAddNew is a relatively new interface. Before this interface existed, the proper way to cancel an AddNewRow was to use the IEditableObject interface.

In order to maintain backward compatbility, the grid checks for the IEditableObject interface first and if this interface is implemented, then it calls the CancelEdit method on it. The grid then has to assume that the CancelEdit method did what it is supposed to do and cancelled the addnew row. It therefore cannot go ahead and also call into the ICancelAddNew interface, also.

I have no experience with the CSLA object, but my guess (and this is only a guess) is that the CSLA objects in this case are implementing IEditableObject, but not handling the CancelEdit method properly.

Mike Saltzman

R&D Engineer

Infragistics, Inc.

I've just reread the part of Expert VB 2008 BOs that deals with IEditableObject (p279) and it seems like this whole area has been given a heck of a lot of thought and attention in CSLA, so I'm at a bit of a loss.  Does any of what Mike's saying here sound like it could be the cause in your opinion?

Thanks

Tom

RockfordLhotka replied on Wednesday, April 29, 2009

I suppose it is possible that there’s a bug in the IEO implementation.

 

I’m a little surprised that they give preference to the old style, not the new style.

 

Back in .NET 1.x the way this worked was that IEO.CancelEdit was responsible for removing the item from the parent list. That code is still in CSLA, but I bet it has been untested and unused for the past several years – so maybe it is broken. It worked in 2001-2004, but past that I can’t say.

 

The thing is, any well behaved child object will implement IEO, even when contained in a modern list (like BindingList<T>) that implements ICancelAddNew – that came in with .NET 2.0. I would think most IEO implementations these days probably don’t do the cancel thing, since it hasn’t been relevant since 2005.

 

Regardless, if this is what they do, then it is what they do.

 

You can look at Csla.Core.BusinessBase to see how the CancelEdit() implementation checks the edit level added value to determine whether to call into the parent collection to tell it to remove the child. You can put a breakpoint there to see if that code is reached or if there’s a problem. That might help figure out what’s going on.

 

Rocky

 

Tom_W replied on Wednesday, April 29, 2009

Thanks Rocky. 

I don't really understand quite what Mike is saying.  If I have it right then ICancelAddNew works at the collection level so it only supercedes the part of IEO's functionality that relates to cancelling unused new rows?  IEO would still be responsible for Begin/Cancel/End Edit for an object when it is not being considered as part of a collection? 

If I have that right then any custom BO is going to be implementing IEO so by Mike's logic of "if it has IEO then we never use ICancelAddNew " the ICancelAddNew methods would never be run.. that doesn't sound right to me Confused [*-)]


I took your advice of debugging through BusinessBase and found where the problem lies (I'm using the RolesEdit.vb form with the DGV swapped for an Infragistics WinGrid).  Recreating my steps:


1) Opening the form causes:
IEditableObject.BeginEdit to fire three times, which in turn causes BindingBase.BeginEdit to fire once.
EditLevel raised from 0 to 1 (presumably the first row in the list getting focus?)

2) Clicking on a different existing row (without editing the first row) causes:
IEO.EndEdit to fire once and BB.ApplyEdit to fire once (presumably the first row losing focus)
Then IEO.BeginEdit is called twice, first time causes BB.BeginEdit to fire.

3) Editing the text in that row and then pressing tab causes:
IEO.BeginEdit to fire twice, but BB.BeginEdit is not fired (as expected as the if statement is guarding for these superfluous BeginEdit calls from the UI?)

4) Clicking back to the first row again causes:
IEO.EndEdit to fire twice, first time calling BB.Applyedit
Then IEO.BeginEdit is called twice, first time causes BB.BeginEdit to fire.

5) Now, clicking on a new row causes:
IEO.EndEdit to fire twice, first time calling BB.Applyedit
Then IEO.BeginEdit is called twice, first time causes BB.BeginEdit to fire.

6) Typing some text in the field then immediately hitting Escape causes:
IEO.CancelEdit to fire, then BB.CancelEdit to fire and then BINGO, the cause of the problem:

The next line of code is:

        if (IsNew && _neverCommitted && EditLevel <= EditLevelAdded)

IsNew is True, _neverCommitted is true, but EditLevel = 1 where as EditLevelAdded = 0, meaning the last check fails and so the next line of code...

          if (Parent != null)
            Parent.RemoveChild(this);

... never fires, which is what causes the row to not get deleted.  If I force execution onto that line then the new row is deleted as per standard DGV behaviour.

I think EditLevelAdded relates to the n-undo, rather than being a part of one of the Windows binding interfaces?  I'm not sure how the EditLevelAdded value gets raised, but it doesn't seem to be getting raised when BB.EditLevel  is raised?  Should it be?

I have a bit of an understanding of the binding interfaces having implemented myself on a little framework we did in house, but I'm a bit lost now EditlevelAdded is in the mix.  Could you point me in the right direction?

Many Thanks

Tom



RockfordLhotka replied on Thursday, April 30, 2009

EditLevelAdded is the edit level of the collection at the time the child was added to the list.

It acts as the base level - when the edit level reaches that point in a cancel, it means you've canceled the child back to the point where it started, and so if the child is new then it can be removed - because it has been canceled back to the point where it didn't exist to start with.

Since you never called BeginEdit() on the collection, the collection's edit level should be 0, and so it sounds like EditLevelAdded is actually correct. What is odd is that EditLevel should be at 1, and the cancel should be lowering it to 0.

It is quite possible that changes over the past couple years have rearranged the order of events so the EditLevel value isn't decremented until after the check you are seeing - which is a long-winded way of saying there's probably a bug.

Tom_W replied on Thursday, April 30, 2009

Thanks Rocky, that sounds logical.  I've stepped through it all line by line and can confirm that there doesn't appear to be any code that reduces the EditLevel when the CancelEdit occurs. 

The order of events when I clicked off the automatically added newly created row without having made any changes was:

  1. IEO.CancelEdit was called, then BB.CancelEdit called
  2. BB.CancelEdit calls Undo Changes (EditLevel is 1 at this point)
  3. In UndoableBase.UndoChanges calls UndoingChanges (which just calls protected virtual void UndoingChanges(){})
  4. Then the code checks this.EditLevel - 1 != parentEditLevel, which it is (EditLevel = 1,  parentEditLevel = 0).  It checks the editlevel, but doesn't change it.
  5. The code then restores all the values back from the stack
  6. UndoChangesComplete() is called which starts to re-setup the validation and business rules and then hits the OnUnknownPropertyChanged() method call. This calls the OnPropertyChanged code which then causes IEO BeginEdit to fire again - this in turn causes BusinessListBase.Child_PropertyChanged to be called.
  7. BLB.UndoChangesComplete() then calls base.UndoChangesComplete and exits and then UndoableBase.UndoChanges completes and exits
  8. BusinessBase.CancelEdit then completes and execution returns to IEO.CancelEdit

So, it would appear that although the cancel edit occurs and the object's data is wound back, the EditLevel for that object is never reduced.  Should that occur as part of the above chain of events, maybe when the values are restored back from the stack (stage 5 in the above list)? 

If it did, then the EditLevel <= EditLevelAdded condition in the next line of code would return true (0<=0) and the child would be removed.

So, all of the above is aimed at hopefully identifying where the issue occurs.. any idea what I need to do to fix it?

ajj3085 replied on Thursday, April 30, 2009

Tom_W:
Thanks Rocky. 

I don't really understand quite what Mike is saying.  If I have it right then ICancelAddNew works at the collection level so it only supercedes the part of IEO's functionality that relates to cancelling unused new rows?  IEO would still be responsible for Begin/Cancel/End Edit for an object when it is not being considered as part of a collection? 

If I have that right then any custom BO is going to be implementing IEO so by Mike's logic of "if it has IEO then we never use ICancelAddNew " the ICancelAddNew methods would never be run.. that doesn't sound right to me Confused [*-)]


That doesn't sound right to me either.. and given that the MS grid seems to work fine, maybe you can point that out and say "your implementation is out of skew with the MS equivolent implementation" to get them to acknowledge they need to fix their grid. Good luck though.. they seem to believe that THEIR 3rd party controls are just fine, but anyone elses that are involved in the mix.. oh well it must be that other third party not working right.

Seem if you can't come up with a demo that illustrates the problem without Csla in the mix.. where their grid fails and the MS one works. That will almost certainly get them to fix their grid.

Tom_W replied on Thursday, April 30, 2009

Thanks Andy.  To be fair to Infragistics the specific issue does seem to be a CSLA issue, but this whole if IEO exists dont use ICAN thing is a bit confusing to say the least (well to me anyway!).

I've posted a response on the Infragistics forum based on what I've learnt so far and asking for some clarification from them on exactly how it all works.  There is a link further up to that thread, so for anyone who has an interest now or in the future that's a good reference too.

It's weird, the number of CSLA users out there and the number of Infragistics users out there I would have thought this would have come up sooner!

ajj3085 replied on Thursday, April 30, 2009

Tom, I hear what you're saying, and there could be a bug in Csla too (and it sounds like there is). But it also sounds like the bug shouldn't matter, if ICAN is the interface to use if present. Again, I would defer to what the MS Grid does. If the MS Grid + Csla behave as expected, then Infragistics should use similar behavior.

I think this actually does affect me, but I've never looked into why. Instead I've told users to highlight the "new" row and hit delete.. but it only happesn on certain grids.

Tom_W replied on Thursday, April 30, 2009

Yep, I agree completely, my expectation would be for WinGrid to effectively behave exactly like the standard MS DataGridView as the default.  Once I get a bit of clarification from Infragistics on how the control works I will be pressing for an explanation if it isn't the same as the DGV. 

Yep, your symptoms sound exactly the same as mine and I've had to tell our users the same thing (in this case for a non CSLA app. using a framework I built).  It is hardly an ideal solution considering users already understand the concept of automatically cancelling new rows from MS Access and so on.  I've found the Infragistics grids work perfectly with DataSets but are flakier with custom collections.

ajj3085 replied on Thursday, April 30, 2009

Hmm... so this was the issue all along. Well, good thing for me my users were using another program, not Access, so they didn't expect the Access-like behavior to begin with. I found this in the documentation for ICancelAddNew.. I'm not sure I'm reading it correctly, but it sounds like you should use the "newer" method if it's there.. but unfortunatly isn't really all that clear. What do you think?

.NET Framework Class Library
ICancelAddNew Interface

"There are two models that allow transactional addition of an item to a data-bound collection:

The older model relies directly on a collection that implements the IBindingList interface and is data-bound directly using the System.Windows.Forms..::.CurrencyManager class. The AddNew, EndCurrentEdit, and CancelCurrentEdit methods of the System.Windows.Forms..::.CurrencyManager class are responsible for transactional support for adding new items. However, this functionality depends upon the items supporting transactional behavior through the IEditableObject interface. If the items do not support this interface, the item will always be added to the list, regardless of subsequent calls to CancelCurrentEdit.

The newer model supports a more robust data-binding scenario through the generic BindingList)>) class, which implements the IBindingList and ICancelAddNew interfaces. In this case, the transactional support is managed by the BindingList)>) collection directly.
"

Tom_W replied on Thursday, April 30, 2009

ajj3085:
Hmm... so this was the issue all along. Well, good thing for me my users were using another program, not Access, so they didn't expect the Access-like behavior to begin with. I found this in the documentation for ICancelAddNew.. I'm not sure I'm reading it correctly, but it sounds like you should use the "newer" method if it's there.. but unfortunatly isn't really all that clear. What do you think? .NET Framework Class Library ICancelAddNew Interface "There are two models that allow transactional addition of an item to a data-bound collection: The older model relies directly on a collection that implements the IBindingList interface and is data-bound directly using the System.Windows.Forms..::.CurrencyManager class. The AddNew, EndCurrentEdit, and CancelCurrentEdit methods of the System.Windows.Forms..::.CurrencyManager class are responsible for transactional support for adding new items. However, this functionality depends upon the items supporting transactional behavior through the IEditableObject interface. If the items do not support this interface, the item will always be added to the list, regardless of subsequent calls to CancelCurrentEdit. The newer model supports a more robust data-binding scenario through the generic BindingList<(Of <(T>)>) class, which implements the IBindingList and ICancelAddNew interfaces. In this case, the transactional support is managed by the BindingList<(Of <(T>)>) collection directly. "


Hi Andy, that's great and I agree it sounds like the bits of IEO in question are effectively deprecated. 

The demo suggestion is a good one, once they fill me in on exactly what the WinGrid is up to then I will try and put a non CSLA semo together that demonstrates the ICAN not being called.  However, this still needs Infragistics to view that as being an issue of course, they may just take the view that as they are implementing IEO then there isn't a problem.

Thanks

Tom

RockfordLhotka replied on Thursday, April 30, 2009

I agree Andy, it seems like they should honor ICAN first, and fall back to
IEO if necessary. That appears to be the behavior of the standard Microsoft
data grid control, against which I measure CSLA's overall requirements.

But it does appear that there's a bug in CSLA that would make it not work
with the old .NET 1.x data grid. And honestly I can't say I'd care, except
it sounds like a more widely used grid control is unfortunately following
the old 1.x model.

I've added an item in bug tracker for this, but I don't know when I'll have
time to dig into it. The trick is that I'll have to either get a failure
case on the 1.x data grid (is that even still around?) or work with
Infragistics to get a license for their stuff (which I'm sure I can do, but
not in the next couple weeks).


The EditLevel DOES get decremented by the way - but it happens later in the
process, and in UndoableBase (if I remember correctly). That whole area
underwent a lot of change a couple years ago as we (this community) helped
me fight through all the data binding issues that are covered in the 'Using
CSLA .NET 3.0' ebook. To get the WinForms 2.0 data binding to really work,
the code dealing with EditLevel changed a lot - and it seems very likely
that I accidentally broke the old 1.x behavior.

And that isn't entirely surprising - I didn't test the 1.x behaviors,
because I kind of thought they were so far in the past no one would care :)

Rocky

-----Original Message-----
From: ajj3085 [mailto:cslanet@lhotka.net]
Sent: Thursday, April 30, 2009 9:30 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Infragistics Wingrid ICancelAddNew - unused new
row not cancelling

Tom, I hear what you're saying, and there could be a bug in Csla too (and it
sounds like there is). But it also sounds like the bug shouldn't matter, if
ICAN is the interface to use if present. Again, I would defer to what the
MS Grid does. If the MS Grid + Csla behave as expected, then Infragistics
should use similar behavior.

I think this actually does affect me, but I've never looked into why.
Instead I've told users to highlight the "new" row and hit delete.. but it
only happesn on certain grids.

ajj3085 replied on Thursday, April 30, 2009

Yup.. I agree.

My suggestion to prod them I think is the ideal way to go. Build a demo without Csla in the mix, file a bug report with them, and I'm reasonably sure they will agree it's a bug they need to fix. If more than one person is reporting the same issue that might help as well.

That's been my experience anyway.. the initial hurdle is in getting them a demo that clearly illustrates the problem, but after that they are pretty good about fixing it, even if they are a bit slow at it. That's the only gotcha, is that you may be able to address Csla faster than they get their fix. :-)

I have some downtime, so I think I may work on my own demo as well, because it sounds like it does affect me.

Tom_W replied on Thursday, April 30, 2009

Thanks again Rocky, that all makes complete sense.

I guess Infragistics are stuck in the situation where they need to support the legacy code out there so it may be difficult for them to recode the control.  I do have the source code license so if I get a moment I will have a dig and try and work out what it's all doing.

The simplest solution would seem to be for Infragistics to give the developer the choice about whether the control uses ICAN or IEO to control the new list items, but that is probably a lot easier said than done!

I'm stil waiting for Infragistics to clarify exactly how they handle the overlap between ICAN and IEO, the devil is probably in the detail...

Cheers,  Tom

Tom_W replied on Thursday, April 30, 2009

One more quick question, just to check my understanding:

Am I correct in saying that:
Apologies, I know this isn't .NET databinding class 101....!

RockfordLhotka replied on Thursday, April 30, 2009

That sounds about right to me.

 

Rocky

 

From: Tom_W [mailto:cslanet@lhotka.net]
Sent: Thursday, April 30, 2009 2:56 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: Infragistics Wingrid ICancelAddNew - unused new row not cancelling

 

One more quick question, just to check my understanding:

Am I correct in saying that:


Apologies, I know this isn't .NET databinding class 101....!


Tom_W replied on Tuesday, May 05, 2009

Update on all of this:

I've discussed all of the above with Infragistics http://news.infragistics.com/forums/p/24944/92456.aspx#92456 and the upshot is that they concur that their needs to be an option to allow ICAN to fire first ahead of IEO.

They are going to look at either getting this into the next 9.1 Service Release or into Version 9.2 of the controls Big Smile [:D]

Hopefully that will happen and will work as expected, it certainly seems like a better solution for the WinGrid to implement ICAN too, rather than just IEO.


Thanks to everyone for your thoughts and inputs/explanations.

Tom_W replied on Friday, May 29, 2009

Further update on this; Infragistics have now confirmed that the developer will be given the option to use ICAN or IEO as of Release 2009 v2 (i.e. the next version).

RockfordLhotka replied on Friday, May 29, 2009

That's good news. Those guys at Infragistics are pretty responsive on the whole I think.

Tom_W replied on Tuesday, September 15, 2009

Just to let anyone else who is interested know; Infragistics Winforms 9.2 is now out and fixes the ICAN/IEO issue described in this thread.  Escaping a new row clears it correctly and moving focus from a new (but unedited) row causes it to be deleted.

Details of the new feature are here

The code to add to the constructor of the form is:
UltraGrid1.DisplayLayout.Override.AddRowEditNotificationInterface = AddRowEditNotificationInterface.ICancelAddNewAndIEditableObject

Copyright (c) Marimer LLC