Adding several items in BindableCollection ends up in reverse order

Dec 9, 2010 at 12:40 PM

Hi!

I'm using CM on WP7 and discovered today that it seems like items ends up in reverse order when adding them to a BindableCollection using AddRange() (and probably also with Add()). 

If I replace BindableCollection with an ObservableCollection I don't have this problem and if I add items while stepping through the code in the debugger it's also no problem.

Is this a know problem?

Thanks,
Linus

Dec 9, 2010 at 1:02 PM
Edited Dec 9, 2010 at 1:04 PM

Are you filling your collection using a background thread?

If so, I suppose that the issue is caused by the fact that the current implementation of BindableCollection<T> does not perform AddRange as an 'atomic' action from the Dispatcher point of view (i.e. every call to the Add method is dispatched separately, and the same goes for the final change notification). This approach avoids to stall the Dispatcher when performing long insert operations, since the Dispatcher can execute some more code between subsequent insert operations, but could lead to problems in case the UI accesses the list before the change notification.

You could try to change the current implementation this way

/// <summary>
/// Adds the range.
/// </summary>
/// <param name="items">The items.</param>
public void AddRange(IEnumerable<T> items)
{
    Execute.OnUIThread(() =>
                        {
                            IsNotifying = false;
                            int index = Count;
                            foreach (T item in items)
                            {
                                InsertItemBase(index, item);
                                index++;
                            }
                            IsNotifying = true;
                            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
                            OnPropertyChanged(new PropertyChangedEventArgs(string.Empty));
                        });
}

so that the AddRange function is 'atomic' from the Dispatcher point of view, and the UI is not notified of the change until the update process is in progress, and see if the behaviour you are experiencing is gone.

If you are interested on the topic, you can have a look at this thread from Bea Stollniz.

Coordinator
Dec 9, 2010 at 1:32 PM

I can't really fix the individual calls to Add, but perhaps I can change the implementation of AddRange based on the code above. Would that be helpful?

Dec 9, 2010 at 1:37 PM

Awesome, thanks for all the info.

I guess it would be the same as calling the BindableCollection like this :

Execute.OnUIThread(() => collection.AddRange(items));

This seems to work fine.

Again, thanks :)

 

 

 

Dec 9, 2010 at 1:45 PM
EisenbergEffect wrote:

I can't really fix the individual calls to Add, but perhaps I can change the implementation of AddRange based on the code above. Would that be helpful?

Yes, that would be very nice :)

Dec 9, 2010 at 2:45 PM
Edited Dec 9, 2010 at 2:45 PM
kvarnhammar wrote:

I guess it would be the same as calling the BindableCollection like this :

Execute.OnUIThread(() => collection.AddRange(items));

Yes, it is logically the same! The proposed code avoids some Dispatcher.CheckAcess and shortens the function calling tree, but nothing more. :)

@Rob: I suppose that the above code (or the quick-fix proposed by kvarnhammar) would be better than leaving the current implementation, since there could be situations where the items get even duplicated on the UI (I got this kind of problems with a similar implementation, since the collection was evaluated as changed before the notification).

Coordinator
Dec 9, 2010 at 2:56 PM

I added a ticket. So, I'll probably get this fixed in the next week or so. 

Coordinator
Dec 22, 2010 at 2:42 PM

Fixed in c6d71bdd2794