Erik83
Erik83

Reputation: 549

This type of CollectionView does not support changes to its SourceCollection from a thread... while using the dispatcher?

So Im developing an addon with a UI that is used inside an application (main application). To make my UI responsive when the main application is working I'm starting my UI in its separate thread like this:

    public  void ShowDialog(IIFCConverter ifcConverter)
    {

        thread = new Thread(x =>
        {
            thread.Name = "UI-thread";
            window = new MainWindow();
            var mainViewModel = ServiceLocator.Current.GetInstance<MainWindowViewModel>();
            mainViewModel.SetIFCConverter(x as IIFCConverter);
            ViewModelLocator.MainWindow = window;
            window.ShowDialog();



        });
        thread.SetApartmentState(ApartmentState.STA);

        thread.Start(ifcConverter);

    }

The first time I start my addon it all works. The second time I start it and it tries to raise events (like OnCollectionChanged) I get a NotSupportedException with the message: "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread"

This is one of my methods:

    private void AddNewFile(AddNewFileMessage obj)
    {
        if (!(obj.Sender is ButtonViewModel)) return;

        if (string.IsNullOrEmpty(obj.Path)) return;



        var ifcFileViewModel = new IFCFileViewModel(new Common.Model.IFCFile { Path = obj.Path, Active = true });
        DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            ListBoxItems.Insert(ListBoxItems.Count - 1, ifcFileViewModel);
        });

    }

I get this eventhough Im using the DispatcherHelper from MVVM light. I have tried using the "normal" dispatcher to, but that gives me the same result.

First of all Im curious to know the mechanics of why its doing this? I've checked my threads and I can see that the OnOllectionChanged is called from my UI-thread. I cant seem to find any differences to the thread structure between the first run (that works) and the following.

OnCollectionChanged called on UI-thread, right?

Second, what can I do about this?

Things that I've tested that didnt help:

  1. Im using the IoC container from MVVM light and its registered as a LocatorProvider, but I create a new IoC container everytime I initialize the UI and set that instance as the LocatorProvider.
  2. Im initializing the DispatcherHelper in the constructor of my window. So that should be on the correct thread.
  3. Something that does actually work is wrapping the action in a try Catch-block like this:

    private void AddNewFile(AddNewFileMessage obj)
    {
    if (!(obj.Sender is ButtonViewModel)) return;
    
    if (string.IsNullOrEmpty(obj.Path)) return;
    
    
    
    var ifcFileViewModel = new IFCFileViewModel(new Common.Model.IFCFile { Path = obj.Path, Active = true });
    
    DispatcherHelper.CheckBeginInvokeOnUI(() =>
    {
        try
        {
            ListBoxItems.Insert(ListBoxItems.Count - 1, ifcFileViewModel);
        }
        catch(Exception ex)
        {
    
        }
    });
    

    }

However I find this very ugly and would like to avoid it and why does that even work? Everything seems to work fine when I wrap all my actions in try Catch-blocks.

Upvotes: 2

Views: 2248

Answers (2)

Erik83
Erik83

Reputation: 549

Ok, so I found the real problem. The viewmodel was indeed created on the same thread as my addon UI.

HOWEVER: I was using the Messenger that is avaliable in the MVVMLight toolkit to handle communication between viewmodels and I forgot to unregister the viewmodel when my windows was closed. So the second time I opened my window and started sending messages between my viewmodels. The first viewmodel reacted and that was what was causing the problem. That is also why the try-Catch-block worked, because there was a second call from the correct thread that was working. I added a datetime to the constructor of the viewmodel and there are indeed two different viewmodels being called. I do not understand why I get that exception. If anything the first viewmodel should be connected via datacontext to the first view. Its like the view has hooked up to the events of two different viewmodels.

Anyway, it works now: I just unregister the viewmodel from the message service when my window is closed and it works like a charm.

Upvotes: 2

Related Questions