views:

51

answers:

1

I have a WPF application that displays an ObservableCollection. It's about 182 rows, and the object (let's call it PositionLight) inside the collection has about 70 properties to display.

All calculation to input data in these properties are made in a second thread which will recalc everything every 20 secondes, and will send a List to the WPF window, thx to an Event. This way calculation doesn't slow down the GUI.

the List is transformed in an ObservableCollection in the constructor of the EventArgs sent with the event to the GIU.

The problem is even when i use a BeginInvoke and a delegate to do:

myGUICollection = myEventArgsCollection

the GUI will be frozen for 3 to 4 seconds... I've put a lot of Console.Writeline to find out where is the bottleneck, but it looks like the freeze will occurs just after it leaves the function called by the BeginInvoke. I'm really lost here.

I'm using a 4 core PC with 2.5Go RAM, so i don't think this is a hardware problem.

Do you guys have an idea?

Some code to give you a better idea of the insert in the GUI:

    public bool myCoreScope_OnCoreCalculationHandler(object myObject, CoreCalculationEventArgs myEventArgs)
    {

        foreach (PositionLight item in myEventArgs.MyPositionList)
        {
            lv.Dispatcher.BeginInvoke(new DisplayPositionItemCallBack(DisplayPositionItem), DispatcherPriority.Send, new object[] { item });
        }

    }


    private delegate void DisplayPositionItemCallBack(PositionLight item);

    private void DisplayPositionItem(PositionLight item)
    {
        try
        {
           MyPositionList.Remove(MyPositionList.First(position => position.ID== item.ID));
        }
        catch (Exception)
        { }
        MyPositionList.Add(item);
    }
+1  A: 

When you call BeginInvoke you are marshalling the update of the ObservableCollection onto the GUI thread, so while the calculation may happen on a seperate thread the update of the UI does not. If you invoke an expensive update onto the GUI thread, then the thread will have to wait until that operation is completed.

An alternative approach is to perform an invoke for each item in the collection, rather than the whole collection at once, which will give the GUI time to process its other messages between updates.

var list = GetCollection();
foreach (var item in list)
{
    Dispatcher.BeginInvoke(new Action(() => myGuiCollection.Add(item)));
}

Another option you could try is to set the IsAsync attribute of the ItemsSource data-binding.

<ListBox ItemsSource="{Binding myGuiCollection, IsAsync=True}" />
Fara
what you say does make sense, however, adding item one by one means i have first to find the old item, remove it, and then add the new one. I'm afraid that won't speed up the process. I will give it a try anyway
Gregfr
GOT IT! Instead of deleting and inserting new item, i'm updating evry existing item, one by one. It looks like this way it use a lot less CPU, and the GUI is not frozen anymore. I'll let the topic open few more hours just to confirm it's working correctly
Gregfr
Ah OK, I was thinking more about initializing the collection, not updating it. For updating things bound to the UI you should look at the INotifyPropertyChanged interface. That is the best way to do this sort of thing.
Fara
with the updating it turns out it didn't solve anything at all... Problem is still here, GUI frozen during the update of the ObservableCollectionI already used INotifyPropertyChanged extensively, with the result i'm struggling with: not responsive GUI
Gregfr