Strange bahaviour of BusinessListBase

Strange bahaviour of BusinessListBase

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


Niemand posted on Wednesday, November 10, 2010

My program is using CSLA 2.1.4

I have a class TaskTimeSpanList Inherits BusinessListBase(Of TaskTimeSpanList, TaskTimeSpan)

When timer form returns new TaskTimeSpanList, I add it's items to the parent object list:

For Each ts As TaskTimeSpan In frm.TimeSpans
SelectedTask.TaskTimeSpans.Add(ts.Clone)
Next

Add method is not overridden in  TaskTimeSpanList class.

 Mostly it works well, but sometimes a strange thing happens: I can see all the added items in the databound datagridview, but "for each item in me" cycle "ignores" these items. As a consequence the program can neither save new items nor calculate the total length (For each cycle is used in both cases).

Could anyone give me any ideas why and how it may be happening?

RockfordLhotka replied on Wednesday, November 10, 2010

When you say "timer form" do you mean some async timer event is being used?

CSLA .NET is not threadsafe - and actually .NET collections aren't threadsafe in general. So if you somehow have an async task modifying a collection from a background thread you should expect all sorts of nasty issues.

Niemand replied on Wednesday, November 10, 2010

No. My program is winforms based. I have one form with a TaskList object that is bound to a datagridview. Once a user selects a task in the datagridview and presses a start timer button, a timer form is shown in a dialog mode. User can start/pause timer (winforms component) many times and all time spans are stored in a TimeSpanList object within timer form. When the timer form is closed, it passes the created TimeSpanList object to the form with TaskList object. Then I need to add all the TimeSpan items from the TimeSpanList returned by timer form to the TimeSpanList stored in the selected Task object.

Dim frm As New F_Timer
frm.ShowDialog()

For Each ts As TaskTimeSpan In frm.TimeSpans
      SelectedTask.TaskTimeSpans.Add(ts.Clone)
Next

RockfordLhotka replied on Wednesday, November 10, 2010

In that case it is most likely the case that you somehow have two instances of your collection. The one bound to the UI gets the new items, but you have some other instance that doesn't have them, and that's where your foreach loops are running.

I mean ultimately the items are either in the collection or they aren't right? :)

If you look at a collection and see the items, and then look at a collection and don't see the items, and there's no async stuff involved, the possibilities are limited.

Niemand replied on Wednesday, November 10, 2010

"I mean ultimately the items are either in the collection or they aren't right?"

I thought so, but now I see a situation when items are and are not in the same collection simultaneously :)

Basicaly I'm adding items from one TimeSpanList to another.

In databound  datagridview I have an object with the following hierarchy: TaskList -> Task -> TimeSpanList

One Task object per one datagridviewrow. TimeSpanList within Task is not shown in a datagridviewrow, but could be viewed in separate form by selecting task and pressing a show time spans button.

So when I add TimeSpan items, I add them to the TaskList.Task.TimeSpanList. When I look at  TaskList.Task.TimeSpanList, I look at the very same list. All items are present. But when I make a breakpoint in subtotal function with for each cycle they are not there anymore. Moreover it only happens sometimes (rarely) and I see no explanation why. It seems random.

 My ideas for the moment: maybe children of the first collection does not change their parent (list) when I add them to another list?

Maybe it has something to do with the Clone part in SelectedTask.TaskTimeSpans.Add(ts.Clone)?

RockfordLhotka replied on Wednesday, November 10, 2010

BLB is just a subclass of BindingList(Of T). The collection itself isn't a CSLA thing, it is a .NET thing.

In other words, things like the Parent reference are immaterial for the purpose of whether the item is in the collection or not. Either the collection contains the item or it doesn't.

(that's not to say that other things might not break if Parent was wrong - just that basic .NET features like foreach shouldn't be)

If I were in your position, I'd use the debugger to walk through the loop where you add the items to the collection, and watch the collection's Count property go up.

Or put code immediately following the addition of the items to check the Count property and then do a foreach to create your own count and compare them.

Basically confirm that the items were actually added to the collection immediately after you think you added them.

But ultimately the thing is that BLB doesn't manage the list of items - it is the .NET BindingList(Of T) that actually contains the items. BLB might throw exceptions to prevent items from being added, but it won't make them mystically disappear :)

Niemand replied on Wednesday, November 10, 2010

The problem is that this mystical behavior only happens sometimes (randomly?).  I cannot reproduce it intentionally.  It takes me a day of random playing with the TaskList to encounter that.

 

P.S. Thanks for a nice framework anyway Cool

RockfordLhotka replied on Wednesday, November 10, 2010

This is why my first instinct was to suspect a threading issue, as those are often sporadic.

If you can't reproduce the issue in a test I'm not sure what you can do. In cases like these I try to replicate the problem in a simpler situation, typically using automated testing (nunit, mstest, etc) to make the test running easier.

Copyright (c) Marimer LLC