0

In my WPF project, when it first opens, there is a great deal of initialisation/loading to perform.

I do this within an opening dialog and because of the time taken for the load the process is initialised as follows:

   Task.Factory.StartNew(() =>
   {
        DoLoad();
   });

The DoLoad method periodically calls a delegate to update the screen to indicate progress. The loading process involves creatings several objects that themselves create collections (some Observable collections for data binding) etc and this process works fine.

However.

Once the loading is complete, any attempt to modify these collections is greeted with the exception:

"This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread."

If I move the loading process into the main thread , i.e. just calling DoLoad, everything is fine but the interface is frozen until the loading is complete. The length of time it takes to load means that this is not acceptable.

So how do I maintain a responsive UI while loading. I thought that moving the loading into a separate thread and using delegates to update the UI is EXACTLY what you're supposed to do?

I found the following code snippet which I thought would solve my problem:

Where do I get a thread-safe CollectionView?

    public class MTObservableCollection<T> : ObservableCollection<T>
{
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
        if (CollectionChanged != null)
            foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
            {
                DispatcherObject dispObj = nh.Target as DispatcherObject;
                if (dispObj != null)
                {
                    Dispatcher dispatcher = dispObj.Dispatcher;
                    if (dispatcher != null && !dispatcher.CheckAccess())
                    {
                        dispatcher.BeginInvoke(
                            (Action)(() => nh.Invoke(this,
                                new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
                            DispatcherPriority.DataBind);
                        continue;
                    }
                }
                nh.Invoke(this, e);
            }
    }
}

All my collections now derive from this, but it has made no difference whatsoever.

Thanks for any help.

Community
  • 1
  • 1
Muckers Mate
  • 399
  • 8
  • 23
  • Why you don't just use a splash screen instead. http://msdn.microsoft.com/en-us/library/cc656886(v=vs.110).aspx. In WPF all UI operation are supposed to happen on the UI thread and you are going away from that model. – Vitalij May 15 '14 at 10:54
  • This is the entire problem. The lengthy processing is undertaken in separate threads, with the Splash screen updating to provide progress feedback (otherwise the UI freezes if the loading is undertaken on the main thread). But, when the loading is complete when the collections (generated during the loading)are referenced/modified on from different threads (i.e. via data binding for example or events), these errors occur. For example, classes 1 and two load in their separate threads. Class 1 registers an onChange event in Class 2. Class 2 changes, calls the event of Class 1 which then.... – Muckers Mate May 16 '14 at 15:10
  • ...attempts to modify its collection and the error occurs. I've circumvented this problem, by creating all objects on the main UI thread with this code: >>>>>>> public static void UiInvoke(Action a) { Application.Current.Dispatcher.Invoke(a); } <<<<< where a is call to the OnChange event handler – Muckers Mate May 16 '14 at 15:12

0 Answers0