0

I have this:

  1. Shows a waiting animation to 'block' the UI while performs a loading operation in the background.
  2. At the end of the loading I call a method that instances a User Control and displays some data by using Bindings (and ObservableCollection among others)
  3. This User Control gets displayed and user can interact with it, however the ObservableCollection seems to be stuck in another thread as it doesn't allow to add new items to it.

I've tried to update the UI at the Completed event of a BackgroundWorker, using Dispatcher, using DispatchTimer... all of this displays the User Control, but the ObservableCollection stays of out reach for adding.

The code that tries to add items to the collection is inside the UserControl.

The exact error is: "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread"

This does not happen if I don't do the loading in the background.

Thank you for any workaround for this.

By the way, trying to add the items using Dispatcher doesn't work either.

In other words, what I would like to do is to create an object in the UI Thread while being in the background... I know this may sounds silly.

NestorArturo
  • 2,476
  • 1
  • 18
  • 21

5 Answers5

1

You may have to check which Dispatcher you are using? In your case you could be referring to two different dispatchers.

Also why not use thread safe observable collection?

Community
  • 1
  • 1
WPF-it
  • 19,625
  • 8
  • 55
  • 71
1

Usually I will create the objects on my UI thread, then populate them with data obtained from a background thread.

For example,

void async LoadButton_Clicked(object sender, EventArgs e)
{
    MyCollection = new ObservableCollection<SomeItem>();

    // Can also use a BackgroundWorker
    var collectionData = await GetCollectionData();

    foreach(var item in collectionData)
    {
        MyCollection.Add(item);
    }
}

I'm using C# 5.0 async and await keywords for asynchronous operations, but you can also use a BackgroundWorker that does your background work.

You can also use Dispatcher.BeginInvoke() for some lighter background work (such as copying data into MyCollection), although for heavy work I find it still locks up the UI so I prefer to use background threads.

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Thank you for your response Rachel... however the process that takes time is a Deserialization, a single line, so I cannot create the object in the UI as the Deserialization creates it. – NestorArturo Nov 23 '11 at 17:01
  • @NestorArturo Can't you deserialize the object on a background thread, then add the deserialized objects to something that was created on the UI thread? WPF won't allow you to access items from the UI thread that were created on another thread. – Rachel Nov 23 '11 at 17:11
0

It is not possible to modify the contents of an ObservableCollection on a separate thread if a view is bound to this collection, instead you can override ObservableCollection and provide support for it and use it across your application.

This sample contains exactly what you want - http://tomlev2.wordpress.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/

Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • Thank you for your suggestion... however the two of those kind of implementations I've tried doesn't work for me. I Don't really know why but throws errors or just blocks the application ¿?. The real problem for me is to show this "Animation" while loading the data, if I do this without some kind of background process the animation doesn't even show up. – NestorArturo Nov 22 '11 at 18:21
0

When it comes to threads and ui-elements one of the most important rules to follow which may safe you a lot of trouble in the long run is to keep ui-element instantiation on the ui-thread. Surely you can manage that. And if you need to change those objects from another thread you can use the Dispatcher.

(The threading model reference may also be of interest)

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • Really appreciate if you show me how to "keep ui-element instantiation on the ui-thread" without blocking the animation. – NestorArturo Nov 22 '11 at 18:17
  • @NestorArturo: You can do things on the UI in parallel using [`DispatcherFrames`](http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherframe.aspx), maybe i'll try to create an example, but perhaps you can find one on your own. Animations should not really diminish UI interactivity anyway, what exactly are you doing? – H.B. Nov 22 '11 at 18:20
  • Thank you... I'm just trying to block the UI "nicely" by showing an spinning ellipse (using Storyboard). I'll check your suggestion. – NestorArturo Nov 22 '11 at 18:24
  • Checked the suggestion, but now freezes the animation. – NestorArturo Nov 22 '11 at 18:53
0

Thank you everyone for your help... a guy from MS visited the company (sorry for the commercial annotation) to do other things, I stoled him and show this behavior. In a matter of 2 minutes founds the source of the problem... which I'm not sure to really understand.

It happens that I'm using an ICollectionView to display a sorted/filtered version of my problematic ObservableCollection. I was creating this ICollectionView in the constructor of my class, so at the moment of deserialization it was created in another thread. He suggested to move this creation to a further time in code (when the related property gets read). This solved the problem.

However the ObservableCollection, created in that other thread, now lets me add new item. Not sure why, but now it works.

Sorry for being this late and thank you again.

NestorArturo
  • 2,476
  • 1
  • 18
  • 21