Reputation: 549
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.
Second, what can I do about this?
Things that I've tested that didnt help:
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
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
Reputation: 2128
Take a look at the BindingOperations.EnableCollectionSynchronization and read this topic: Using BindingOperations.EnableCollectionSynchronization.
Upvotes: 1