BussinesListBase<T<C>.ListChanged not setting NewIndex, or OldIndex

BussinesListBase<T<C>.ListChanged not setting NewIndex, or OldIndex

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


nermin posted on Saturday, October 14, 2006

Hello,

I am not sure whether this is an issue or by design, but an event ListChanged is being raised and ListChangedType is ItemChanged.  Both NewIndex and OldIndex pproperties of ListChangedArgument are always set to 0 no matter what item changed.

Is this by design and if yes, how do I get to the item that just changed?

I beleive I was using release candidate for 2.1 release of Csla.

Thanks,

Nermin

Brian Criswell replied on Saturday, October 14, 2006

Are these new objects?  Are you providing GetIdValue with an integer that corresponds to an identity column in the database?  Is the id value initialized to 0 in your new objects?  If yes, your new objects need to have their id values initialized to unique values.  There are a couple threads regarding this issue. 

Basically, the list does an IndexOf(object) to determine the index of the item that was changed.  It does this by calling object.Equals(object) on each item in the list until one matches.  The business objects implementation of Equals compares the values of GetIdValue().  If all your new objects have the same GetIdValue(), then the first item in the list will always be returned.

nermin replied on Monday, October 16, 2006

Yes Brian,

This was a new object and the Id was a value of the PK , which happpened to be an Identity column (not set until you save the object to DB).

Other than simulating an Oracle Sequence (e.g. something like http://jamesthornton.com/software/coldfusion/nextval.html), and using thise values as PKs instead of Identity Seed, do you have domething else you would reccomend as a Best Practice to follow (solution that worked for you).  I have to say that I have seen some threads that reccomend subclassing BussinessBase to create a BusinessBaseId, which then implements an autoGeneration of "Temporary Ids", but solution seemed to be not very elegant, I think I have also seen some comments about issues in multithreaded environments (duplicate keys possible), etc...

Anyway, thanks for explaining the problem, and I would appreciate any comments/recommendations that you might have for constructing Ids prior to save.

Regrds,
Nermin

nermin replied on Monday, October 16, 2006

Actually I have a follow up question.

If Rocky is calling ObjectInList.GetId(), wouldn't that mean that he already has a reference to the object in the list that changed (and we do not need to loop trough .GetId() to get to the one that we call IndexOf())?

In other words, if ObjectInList fires PropertyChanged, that in turn is captured in the ListChanged implementation, wouldn't the "object sender" argument point to the ObjectInList that we need to get the IndexOf() to set the NewIndex of the ListChangedArgument.

Seems to me that we might need some refactoring in Csla.  Please correct me if I am wrong.

Regards,

Nermin

Brian Criswell replied on Monday, October 16, 2006

I am not following you completely, but I believe that the implementation is already correct.  There is no need to hook up a PropertyChanged event handler on each item as ListChanged already tells you which property changed.  The sender of the ListChanged event is the list not any item in the list.  Rocky's code is not calling IndexOf, BindingList<T> (the base class) is.  This is a new .NET framework class.  Did any of this answer your question, or did I completely misunderstand you?

nermin replied on Monday, October 16, 2006

I see, so the Csla does not have control of the ListChanged implementation, BindingList<T> does.  OK now everything makes sense. 


xal replied on Saturday, October 14, 2006

The listchanged event comes from System.ComponentModel.BindingList. The event itself is not very useful for many scenarios.
Not long ago, Rocky added a class called ExtendedBindingList which only introduces a new event ItemRemoved (or something like that). He did that because listchanged fails to indicate the index of the removed item, and is raised after the item was removed.
I'm not sure it is convenient for all the cases to raise an event when a property changes, but you can easily implement an intermediary class that just does that for you by overriding InsertItem and RemoveItem and adding / removing a handler for PropertyChanged accordingly. That way you can have your own ItemChanged event.

This is certainly a candidate to be added to ExtendedBindingList, but maybe not forced... Maybe we could have an EnableItemChanged prop to enable / disable the functionality. (thinking of some very large collections I have).

Anyway, I hope it helps!

Andrés

Brian Criswell replied on Sunday, October 15, 2006

xal:
Not long ago, Rocky added a class called ExtendedBindingList which only introduces a new event ItemRemoved (or something like that). He did that because listchanged fails to indicate the index of the removed item, and is raised after the item was removed.

Sorry, I missed this one.  Under what scenario does ListChanged not tell you the index of the item removed?  I use this functionality in a couple of my programs without any problems.

xal replied on Sunday, October 15, 2006

The listchanged event is raised _after_ the item was removed, so if you're an outside listener it's not easy to figure out what item was removed.
Suppose you want to add event handlers on item added and remove them on item removed... You can't perform that operation because the item was removed and you can't get a reference to the removed item (unless you keep a separate list).

Andrés

Copyright (c) Marimer LLC