2

I have an ObservableCollection<T> which will hold a lot of items. The data will be received async by using a backgroundworker (This works fine and fast).

But if I try to bind the huge collection to a listbox/listview (whatever) at the BackgroundWorkerCompletedTask the visualization will take a lot of time an the GUI will hang until the binding/visulization is completed.

Any ideas how to improve the performance or to prevent that behavior?

void bgGetData_DoWork(object sender, DoWorkEventArgs e)
{
    HugeData();
}

 void bgGetData_ProgressChanged(object sender, ProgressChangedEventArgs e)
 {
     devices.Add((ServiceReference1.Device)e.UserState);
 }

private void HugeData()
{
     foreach (ServiceReference1.Device dev in Proxy.client.GetHugeDate())
     {
         bgGetData.ReportProgress(0, dev);
     }
}

The data is bound by:

myControl.ItemsSource = devices;

Thank you.

user1011394
  • 1,656
  • 6
  • 28
  • 41
  • 1
    if you have used the observablecollection ui should update with every update to it... can you share your code how u r updating the observablecollection? – Nitin Sep 22 '13 at 10:42
  • Is there a way to add the items piece by piece during retrieval/creation in the backgroundworker? You could thena dd the items using `ProgressChanged`. – meilke Sep 22 '13 at 10:44
  • try updating the UI with each item added to the collection instead of update the entire huge collection when it finishes ... – Omri Btian Sep 22 '13 at 10:46
  • See the code above. I've already tried to update it by using ProgressChanged. – user1011394 Sep 22 '13 at 10:49
  • 3
    You problem might result from the fact that an ObservableCollection fires a CollectionChanged event on every single added (or removed or replaced) item. You may replace the standard ObservableCollection by an enhanced one as described in [this answer](http://stackoverflow.com/a/13303245/1136211). – Clemens Sep 22 '13 at 10:53
  • Post the full code and XAML. Otherwise it's all speculations. – Federico Berasategui Sep 22 '13 at 23:41

1 Answers1

0

I had a very similar problem, both on the collection data, and also on setting GroupNames for items in the collection (I wanted to allow empty groups so I'm manually updating the PropertyGroupDescriptor.GroupNames).

It turns out that when adding to an ObservableCollection you're firing the CollectionChanged event on every row added, and if you change the groups you're updating the groups and the rows for every group.

The solution is to use AddRange on the collection, which sadly doesn't exist, and you can't inherit from the ObservableCollection that contains group names because it's comes from a PropertyGroupDescriptor for the collection that holds the data ... but ... cludgiest of cludges you can get at the underlying Items using reflection.

So, I present my very nasty GroupNames update code:-

    public void CheckGroups(ObservableCollection<Object> GroupNames) {
        var lBindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;

        if (mHasUpdates) {

            var lHashC = new HashSet<Object>(GroupNames);
            var lHashN = new HashSet<Object>(mGroupList);

            var lAdd = lHashN.Except(lHashC).ToList();
            var lRemove = lHashC.Except(lHashN).ToList();

            if (lAdd.Count > 0 || lRemove.Count > 0) {

                var lType = GroupNames.GetType();
                var lProp = lType.GetProperty("Items", lBindingFlags);
                var lItems = (List<Object>)lProp.GetValue(GroupNames, null);
                var lMethod = lType.GetMethod("OnCollectionChanged", lBindingFlags, null, new Type[] { typeof(NotifyCollectionChangedEventArgs) }, null);
                var lArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);

                if (lAdd.Count > 0) lItems.AddRange(lAdd);
                if (lRemove.Count > 0) lItems.RemoveAll(R => lRemove.Contains(R));

                lMethod.Invoke(GroupNames, new Object[] { lArgs });

            }
        }

    }
Richard Petheram
  • 805
  • 12
  • 16