tags:

views:

30

answers:

1

I have a data grid in a view that is bound to a List in a viewmodel. I have a lot of data to retrieve for the list, so I want to break it up into many small retrievals instead of one big one.

I want this to happen on a background thread with the UI updating (the grid binding the new data) at the end of each batch retrieved.

At the end of each retrieval, I am doing a List.AddRange() on the private backer, then raising the OnPropertyChanged event passing the name of the public property that the grid is bound to.

Initially I tried this with 6 iterations that retrieve 100 items each. When running in the background, the UI would update after the first 100, but then not update the last 500 (even though the data was successfully added to the underlying list in the viewmodel).

Thinking that I had some issues with marshalling to the UI thread, I ran it sychroneously, expecting it to either work as expected (albeit blocking the UI during each retrieval) or block the UI during all the retrievals - but in either case, updating at the end to show 600 items. However, it ends up doing the same thing as when I run it in the background - only updates the first 100 and not the rest.

Below is the method I am using with both attempts, the top half being the background version commented out.

What am I doing wrong?

public void StartDataStream()
{
    //Task<List<Car>> task = _taskFactory.StartNew(this._retrieveData);

    //task.ContinueWith(t =>
    //{
    //    if (this._cars == null) this._cars = new List<Car>();

    //    this._cars.AddRange(t.Result);
    //    base.OnPropertyChanged("Cars");

    //    this.iterations += 1;
    //    if (iterations < 6) StartDataStream();
    //});

    if (this._cars == null) this._cars = new List<Car>();

    this._cars.AddRange(this.GetCarList(eq,s,e));
    base.OnPropertyChanged("Cars");

    this.iterations += 1;

    if (iterations < 6) StartDataStream();
}
A: 

Have you tried using an ObservableCollection<T> rather than a List<T>

I assume you have a public property called Cars similar to...

public List<Car> Cars{

   get { return this._cars;}
   set
   {
      this._cars = value;
      base.OnPropertyChanged("Cars");
   }

}

If not this will not actually do anything...base.OnPropertyChanged("Cars");

Extension Method AddRange for ObservableCollection

public static class Extensions
{
    public static void AddRange(this ObservableCollection obj, List<T> items)
    {
        foreach (var item in items)
          obj.Add(item);
    }
}
gmcalab
Actually, I considered it but didn't try it because of the lack of an AddRange method on the ObservableCollection. Short of implementing my own ObservableCollection with an AddRange, I was worried about the performance of the UI updating on EVERY item as opposed to every 100.
MarkB
I had some issues with using a `List` as opposed to `Observable` and when I switched it seemed to play better. The `List` type does NOT implement `INotifyCollectionChanged`, where `Observable` does implement it. I would give it a shot see if it makes an difference for you.
gmcalab
Yea, an ObservableCollection is worth a try - I will try it now. Regarding the public property, yes, mine looks exactly like you have there - sorry, I should have included that with my example.
MarkB
That's cool just wanted to make sure you had that there to double check :)
gmcalab
Ok, so using ObservableCollection, with the synchronous approach, the UI updates with 600 after all iterations are complete (appearently blocking through them all). Then I did the same thing with the Task approach and never got any UI update at all (not even the first 100) - so maybe I am a step closer and now I actually do have a marshalling issue to the UI thread?
MarkB
Are you using `TwoWay` binding ?
gmcalab
I am not specifying the Mode property on the binding in my XAML, so I guess I am using whatever the default is. Should explicitly set a mode to something?
MarkB
One-way is good for me - this is read only data. I just tried One Way and no change.
MarkB
gmcalab
I tried them all. Have to go home now, but later tonight, I am going to try to get the change events sent over to the UI thread as is discussed here: http://stackoverflow.com/questions/590590/making-sure-onpropertychanged-is-called-on-ui-thread-in-mvvm-wpf-app
MarkB