Event re-hooking on replace

Event re-hooking on replace

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


jh72i posted on Monday, September 17, 2007

Folks/Rocky,
Been a long time since I posted on here and everytime I do I seem to have a similar theme!  (btw, pity that all my old posts from years ago are now gone).

Anyway, back to Event handling in CSLA or generally - if I replace an object in my collection how can I guarantee that all events hooked to my old object are correctly re-hooked to my new object?  Specifically, if I replace an object that has an internal collection I need to be sure that any client hooked to the events of that internal collection are rehooked to the new object.

I have always used methods revolving around serialization and registereventhandlers but I only now (well, for a while) realise that while I can register handlers within my own objects I have not thought about external event sinks - the ones I don't know anything about until run-time.

Consider a graph:

People <collection>
  Person <object>
    Addresses <collection>
      Address <object>

Now I hook up an Infragistics grid (or any component but a those grids are great because they will hook a new "band" to the internal collection of addresses) to the collection of people.

Now, somewhere down the line one of these people has a change in address.  My system will "notify" all other collections listening on the same channel of the change.  Now, rather than copy the new incoming data field by field I simply send the entire new object and upon receipt replace it in the other collections.  In 99% of cases the objects don't have "dependencies" on internal collections - and maybe this example isn't a great one either - basically, indulge me here and consider that the concurrency of Person changed when the Address collection is changed.  So, in this example I send the Person object rather than the Address object.  When it is received it is replaced in the Persons collection and the ListChanged of the Addresses collection is hooked back up to the Person object.

Now, the problem is that other event sinks that were hooked up to the old Addresses collection are not now hooked up to the new one!


This was long winded and maybe difficult to follow - I'm sorry - but my general point is that I don't see in any CSLA implementation any thoughts about unhooking event sinks from one object and hooking them to another.  And what I really mean are events sinks that are not within the object graph that the developer has control over but those external events that we have no knowledge of until we run-time debug and GetInvocationList().

I'm thinking that if _nonSerializableHandlers and _serializableHandlers were publicly available I could unhook and rehook successfully.  Well, I know I can because I tried.  But I'm wondering if there is some other way?

Thanks for your time today.

 

BVeenstra replied on Friday, September 21, 2007

I have a similar object graph to yours... (gory details here)


I am able to add/delete/update AllocationDetails and the AllocationDetailList ListChanged still fires...

What operation are you doing on the Addresses collection?  I'm assuming delete, then add...

jh72i replied on Tuesday, September 25, 2007

Thanks for the reply - been away so sorry for not picking up on it immediately.  No, essentially my issue is in replacing an item that has sub collections.  When the item is replaced (like, List[ i ] = newPerson) any events hooked to the subcollection (Addresses in this example) of the old item would remain hooked to the old and not the new.

It is possible to find them and hook them to the new collection but I just wondered how people deal with this.  I suspect the approach is to Remove the old item and Add the new.  Trouble with this is that inappropriate events get fired. 

And I know its probably all about how you look at it - it may be that I should be adding a new person object but what I feel I'm really doing is updating an existing person with his/her latest state.

BVeenstra replied on Tuesday, September 25, 2007

"inappropriate events get fired" --- is the RaiseListChangedEvents not able to handle this situation on your List?

jh72i replied on Tuesday, September 25, 2007

No.  Just that any client hooked up doesn't expect to get itemdeleted and itemadded events when really an item has only just changed is all.

BVeenstra replied on Tuesday, September 25, 2007

So JH72I, I'm at a loss then, I'm really just getting started in CSLA-land.

jh72i replied on Tuesday, September 25, 2007

That's cool BVeenstra.  You prob won't come into this issue at all.  I'm just using csla a little ....creatively...i suppose.

ben replied on Wednesday, September 26, 2007

Hi jh72i

You said:

I'm thinking that if _nonSerializableHandlers and _serializableHandlers were publicly available I could unhook and rehook successfully.  Well, I know I can because I tried.  But I'm wondering if there is some other way?

May you show me the code that you used to unhook and rehook event handlers?.

I think that could help me to resolve a problem I have. It is about passing objects through Remoting (Serialization issue). And it may be very closed to your problem.

Thanks

Benjamin

This is my problem:

As you know, when an objects that belong to a BLB raises a PropertyChanged event with PropertyName=String.Empty, then the list raises the event ListChanged. The problem is that if the object has been serialized (by Remoting or by cloning it) then the ListChanged event is of type ItemChanged (this is the right behaviour and it is implemented by the CSLA code).  Other ways the ListChanged event is of type Reset (this behaviour is problematic in some cases and it is the default implementation of BindingList).

I’m looking for a way to unhook all handlers that ListChanged event has from the BindingList implementation to replace them for the CSLA implementation <<see BusinessListBase.Child_PropertyChanged(sender, e) handler>>.

For more ditails see:

http://forums.lhotka.net/forums/thread/17626.aspx

jh72i replied on Wednesday, September 26, 2007

Hi Ben,
One important word in that sentence of mine is tried. I have not, as yet, implemented any kind of graceful solution but tried an idea which actually worked for the test cases I had (very few test cases at that). Also, I'm still using an old version of csla but I don't think that matters.

Anyway, here was my approach......without any error checking, etc.....

..yes, I temporarily made the nonSerializableHandlers public

..implemented a new OnSetComplete something like (a please check for errors and nulls etc.):

protected override void OnSetComplete(int index, object oldValue, object newValue)
{
// need to remove event sinks from the old discarded object and hook them to the new
EventHandler oldHandlers = (EventHandler)((BusinessBaseEx)oldValue)._nonSerializableHandlers.Clone();
Delegate[] list = ((BusinessBaseEx)oldValue)._nonSerializableHandlers.GetInvocationList();
for(int i = 0; i < list.Length; i++)
{
  listIdea [I] =
null;
}
((BusinessBaseEx)oldValue)._nonSerializableHandlers =
null;

// hook the event sinks for the old object to the new object
((BusinessBaseEx)newValue)._nonSerializableHandlers = oldHandlers;

// base.OnSetComplete (index, oldValue, newValue);
// bypass base for a moment and just call the listchanged event from here
OnListChanged(
new ListChangedEventArgs(ListChangedType.ItemChanged, index));
}

Now, you'd need to do more to ensure this is the behaviour you want all the time, etc.  Lost more.  But essentially is does seem to hook the new object (collection) to the event sinks of the old.  Im my case I could prove it all the way through by binding to an Infragistics grid but the grid does seem to have some bug in which Band objects hang on to the old object while RowsCollections, Grid, etc. CM, RelatedCM, etc. all end up hooked to the new.

BTW, BusinessBaseEx is my own object that inherits from BusinessBase(maybe old-world csla speak!?) and likewise I have a BusinessCollectionBaseEx.

 

Anyway, see what you can make of this approach.  I'm not sure about performance or what I might be losing, etc. so I'm open to all manner of abuse.

Copyright (c) Marimer LLC