I have 2 NotificationObject objects that act as view models. First NotificationObject contains properties that are binded to the view of a specific control, and second NotificationObject has some code that executes in another thread using Thread object. I need to change properties of first NotificationObject from the running code of the second NotificationObject. When I try to do it I get an exception "The calling thread cannot access this object because a different thread owns it.".
I think that I need to use some sort of dispatcher to access those properties as I would do in Windows Forms or classic WPF, but I can't find how to do it in Prism MVVM. So how do I change the properties of first NotificationObject?
I am guessing that you have something created on one thread, and are trying to update it from the other thread, and WPF doesn't allow this. Objects can only be modified from the thread they were created on.
Usually all objects are created on the main UI thread, and the Dispatcher is used to pass asynchronous messages to the UI thread to update these objects. Any heavy processing can still be done on the background thread, however to update the property of an object you need to use the main UI thread.
For example, something that looks like this would work:
MyNotificationObject obj = new MyNotificationObject;
obj.Items = MethodThatRunsOnBackgroundThread();
List<SomeObject> MethodThatRunsOnBackgroundThread()
{
var list = new List<SomeObject>();
// Do Work
Return list;
}
While this will not:
MyNotificationObject obj = new MyNotificationObject;
MethodThatRunsOnBackgroundThread(obj);
void MethodThatRunsOnBackgroundThread()
{
var list = new List<SomeObject>();
// Do Work
// This won't work since obj was created on UI thread
obj.Items = List<SomeObject>;
}
Here is another example that works, because it is sending the message to update the object to the UI thread which created the object.
MyNotificationObject obj = new MyNotificationObject;
MethodThatRunsOnBackgroundThread(obj);
void MethodThatRunsOnBackgroundThread()
{
var list = new List<SomeObject>();
// Load List
Application.Current.Dispatcher.BeginInvoke(DispatherPriority.Background,
new Action(delegate {
obj.Items = list;
}));
}
Application.Current.Dispatcher is pretty much the easiest solution..
In .NET 4.5 this will thankfully not be necessary anymore.
Had to look for the Dispatcher in view's UserControl object, not in the model view's NotificationObject. I think that it is not good to reference views from model views in MVVM, but I haven't found a better solution yet.