Problem removing item with 2.1.4

Problem removing item with 2.1.4

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


amselem posted on Tuesday, March 06, 2007

Hi all,

I have some problems with the latest version of CSLA 2.1.4 wich I didn't have with CSLA 2.1.3. I've tracked down the problem and it's the order of execution inside RemoveItem at BusinessListBase.vb. In 2.1.4 this is the code:


Protected
Overrides Sub RemoveItem(ByVal index As Integer)

' when an object is 'removed' it is really
' being deleted, so do the deletion work

Dim child As C = Me(index)

MyBase.RemoveItem(index)
CopyToDeletedList(child)

End Sub

but in previous versions the CopyToDeletedList was executing before RemoveItem. I guess that there is a good cause for swapping those lines but this change broke my code. This is because I've some GUI elements that are listening for the ListChanged / ItemRemoved event wich is fired by RemoveItem(index). Then my code checks for the EditableCollection.IsDirty value but it's inconsistent because CopyToDeletedList(child) has not been executed yet (IsDirty depends on DeletedList count). In a few words, what I want is to enable the Save button if the user removes an item from the EditableCollection.

Any thoughts on this issue? Should I implement this in other way..?
Regards
Jacobo

tetranz replied on Tuesday, March 06, 2007

I have the same problem. Rocky explains in the change log why it was changed but this may be an unexpected effect.

Ross

tetranz replied on Sunday, March 11, 2007

Any thoughts on this Rocky?  I agree with Jacobo that it breaks the standard way many of us are controlling buttons. I use the binding source CurrentItemChanged event but when that fires, IsDirty is still false so buttons don't get enabled.

Cheers
Ross

RockfordLhotka replied on Sunday, March 11, 2007

Hmm, that's unfortunate...

I can't just put the code back though, because the original problem was serious - triggering a Reset event on every remove, which can be very expensive, and was technically wrong in any case.

What might work, is the following sequence:

  1. Add the to-be-deleted object to deletedList
  2. Remove the to-be-deleted object from the active list
  3. Unhook any PropertyChanged event handler from the to-be-deleted child
  4. Mark the to-be-deleted object as deleted

The only catch to this, is that for a brief time the object will be in deletedList, but it won't be marked for deletion.

Perhaps most notably, when your UI code is handling the ListChanged event, the collection's IsDirty will be true, but at that instant the to-be-deleted child won't be fully in its deleted state.

 

Alternately, perhaps I could revert the BLB code, but change BB so its DeleteChild() implementation doesn't trigger a call to OnUnknownPropertyChanged. That would prevent the child from raising its changed event, thus preventing BLB from raising the ListChanged(Reset) event.

ajj3085 replied on Monday, March 12, 2007

Is there a way to suspend the raising of events until both operations have completed, then after both have completed, raise the required events?

RockfordLhotka replied on Monday, March 12, 2007

I don’t have control over the ListChanged event being raised – that comes from BindingList<T> - so I don’t think there’s any realistic way for me to suspend the events, no.

 

Rocky

 

From: ajj3085 [mailto:cslanet@lhotka.net]
Sent: Monday, March 12, 2007 7:21 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Problem removing item with 2.1.4

 

Is there a way to suspend the raising of events until both operations have completed, then after both have completed, raise the required events?


tetranz replied on Monday, March 12, 2007

I'm not in a convenient spot to try this right now but wouldn't something like this work? Isn't it the listchange here that bubbles up to the BindingSource?

C child = this[index];
this.RaiseListChangedEvents = false;
base.RemoveItem(index);
this.RaiseListChangedEvents = true;
CopyToDeletedList(child);
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));

Ross

RockfordLhotka:
I don’t have control over the ListChanged event being raised – that comes from BindingList<T> - so I don’t think there’s any realistic way for me to suspend the events, no.

RockfordLhotka replied on Monday, March 12, 2007

Yes, that appears to work – glad you brought up that idea!!

 

Rocky

 

 

From: tetranz [mailto:cslanet@lhotka.net]
Sent: Monday, March 12, 2007 11:55 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Problem removing item with 2.1.4

 

I'm not in a convenient spot to try this right now but wouldn't something like this work? Isn't it the listchange here that bubbles up to the BindingSource?

C child = this[index];
this.RaiseListChangedEvents = false;
base.RemoveItem(index);
this.RaiseListChangedEvents = true;
CopyToDeletedList(child);
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));

Ross

RockfordLhotka:

I don’t have control over the ListChanged event being raised – that comes from BindingList<T> - so I don’t think there’s any realistic way for me to suspend the events, no.



ajj3085 replied on Monday, March 12, 2007

I thought you could use the RaiseListChangedEvent property to suspend the raising of events in a BindingList<T>?


Edit:  Opps, I should have read the other replies first :-)

RockfordLhotka replied on Monday, March 12, 2007

Yes, I wasn’t thinking – rub it in, rub it in J

 

I’ve made the change and the code is in svn (http://www.lhotka.net/cslacvs/viewvc.cgi/trunk/). In my test harness it appears to solve both the original and new problem.

 

Rocky

 

 

From: ajj3085 [mailto:cslanet@lhotka.net]
Sent: Monday, March 12, 2007 1:07 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Problem removing item with 2.1.4

 

I thought you could use the RaiseListChangedEvent property to suspend the raising of events in a BindingList<T>?


ajj3085 replied on Monday, March 12, 2007

Didn't mean to rub it in... just hit reply before seeing if anyone else had posted a similar answer... so bad posting etiquette on my part.

RockfordLhotka replied on Monday, March 12, 2007

Don’t mind me, I’m just giving you a hard time J

 

 

From: ajj3085 [mailto:cslanet@lhotka.net]
Sent: Monday, March 12, 2007 2:05 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: Problem removing item with 2.1.4

 

Didn't mean to rub it in... just hit reply before seeing if anyone else had posted a similar answer... so bad posting etiquette on my part.


amselem replied on Monday, March 12, 2007


Thanks everybody for your time and support with this issue, the current version it's working now for me. And sorry for being picky but shouldn't we preserve the RaiseListChangedEvents value ? Like this:

Protected Overrides Sub RemoveItem(ByVal index As Integer)

' when an object is 'removed' it is really
' being deleted, so do the deletion work
Dim child As C = Me(index)
Dim OldRaiseListChangedEvents As Boolean = Me.RaiseListChangedEvents
Me.RaiseListChangedEvents = False
Try
   
MyBase.RemoveItem(index)
Finally
   
Me.RaiseListChangedEvents = OldRaiseListChangedEvents
End Try

CopyToDeletedList(child)
OnListChanged(New ListChangedEventArgs(ListChangedType.ItemDeleted, index))
End Sub


Jacobo

RockfordLhotka replied on Monday, March 12, 2007

Yes, very good point!

 

Rocky

 

From: amselem [mailto:cslanet@lhotka.net]
Sent: Monday, March 12, 2007 4:52 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: RE: Problem removing item with 2.1.4

 


Thanks everybody for your time and support with this issue, the current version it's working now for me. And sorry for being picky but shouldn't we preserve the RaiseListChangedEvents value ? Like this:

Protected Overrides Sub RemoveItem(ByVal index As Integer)

' when an object is 'removed' it is really
' being deleted, so do the deletion work
Dim child As C = Me(index)
Dim OldRaiseListChangedEvents As Boolean = Me.RaiseListChangedEvents
Me.RaiseListChangedEvents = False
Try
   MyBase
.RemoveItem(index)
Finally
   Me
.RaiseListChangedEvents = OldRaiseListChangedEvents
E nd Try

CopyToDeletedList(child)
OnListChanged(New ListChangedEventArgs(ListChangedType.ItemDeleted, index))
End Sub


Jacobo



tetranz replied on Tuesday, March 13, 2007

amselem:
sorry for being picky but shouldn't we preserve the RaiseListChangedEvents value?
Just to continue the pain one more step Smile [:)], we should only generate our own event if RaiseListChangedEvents was true.

ajj3085 replied on Tuesday, March 13, 2007

tetranz,

The code as is will work fine; OnListChanged respects the value of RaiseListChangedEvents, which Rocky has restored to whatever value at the end.

tetranz replied on Tuesday, March 13, 2007

Okay, thanks. I didn't realize that.
ajj3085:
tetranz,The code as is will work fine; OnListChanged respects the value of RaiseListChangedEvents, which Rocky has restored to whatever value at the end.

stephen.fung replied on Monday, December 17, 2007

ajj3085:
tetranz,

The code as is will work fine; OnListChanged respects the value of RaiseListChangedEvents, which Rocky has restored to whatever value at the end.


Hi,

Maybe we're talking about different things, but this statement doesn't seem to match my experience with CSLA 3.0.2.

Using the .NET Reflector to look at the source code for BindingList<T>, it doesn't look like OnListChanged respects the RaiseListChangedEvents property.

Modifying the code to respect RaiseListChangedEvents in BusinessListBase.SetItem and RemoveItem before calling OnListChanged solved a problem for me related to this.

if(this.RaiseListChangedEvents)
    OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));

RockfordLhotka replied on Monday, December 17, 2007

You should look at the current (3.0.3) code, because I believe this is addressed in that version.

 

Rocky

 

 

From: stephen.fung [mailto:cslanet@lhotka.net]
Sent: Monday, December 17, 2007 7:37 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Problem removing item with 2.1.4

 

Hi,

Maybe we're talking about different things, but this statement doesn't seem to match my experience with CSLA 3.0.2.

Using the .NET Reflector to look at the source code for BindingList<T>, it doesn't look like OnListChanged respects the RaiseListChangedEvents property.

Modifying the code to respect RaiseListChangedEvents in BusinessListBase.SetItem and RemoveItem before calling OnListChanged solved a problem for me related to this.

if(this.RaiseListChangedEvents)
    OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));


Copyright (c) Marimer LLC