This is my first post here as actually i usually solve all my issue with the awesome post database you can find here. But I'm actually stuck right now:
I'm working on a project following the MVVM including a COM object. As I read during my research, I understand that the COM object is only accessible from the thread which created it. My COM object implements the following interface
interface IComUpdate
{
void Update();
}
So when I create my COM object, each time there is an update (I dont know when, its random) the COM Server will call the Update()
of the COM object class I did implement.
My goal was to create a different thread, naming a COM object thread, where the COM object exist independantly of my UI Thread, so everytime there is an update, I handle it in a different thread than the UI Thread.
Actually it is working:
At the Beginning of my ViewModel I create a collection of a specific object.
This object, lets call it ModelObj
, is part of the model and defines a static constructor in which the application, apart from initializing some variables, creates and starts a new thread for the COM object:
Thread t = new System.Threading.Thread(() =>
{
System.Threading.Thread.CurrentThread.Name = "Thread of COM Object";
IComUpdate myComObj;
myComObj = (IComUpdate)Activator.CreateInstance(blabla);
Application.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
It actually works very well, in the Update()
implementation of my COM object, I actually see that the thread is the one just created and not the UI thread.
Now the issue is this: this ModelObj
I create implements the INotifyPropertyChanged
interface.
My thinking was the following: each time the COM object receives an update, I handle data from the COM object thread, and update some property of my ModelObj
instance from this thread, so these properties will then raise the property change of my ModelObj
and the UI thread will update the User Interface.
If the UI update takes too much time, I might miss some Update()
to appear on the screen but the COM object will have them recorded in my ModelObj
instance so it is not very important that the UI catch all the updates, I just didnt want the COM object to have to wait for the UI to be updated to be called again.
I read tons of posts and thought then that my RaisePropertyChanged("property")
would fail.
Actually even in the COM object's thread, the RaisePropertyChanged
successfully executes, so tracing my code, I see it switches to my ViewModel assembly where I do
// Here I'm still in the thread of my COM object!
base.NotifyOfPropertyChange<string>(() => this.property)
and then the UI Update.
Note: I'm using Caliburn Micro for binding between my View in WPF and my ViewModel.
So I can't trace after this base.NotifyOfPropertyChange<string>(() => this.property)
. Maybe Caliburn handles the thread switch, this is not really my issue.
What I can say is that my COM object thread waits for the UI to update to get to the next instruction after my RaisePropertyChanged("property")
, so it's exactly the same as if the UI thread did the whole work.
I want my COM object thread to update my ModelObj
which will send to send the UI a message to update (because some fields of this ModelObj
have changed) and continue immediatly, without knowing if the UI actually updates or not.
Does someone got an idea about this behaviour?
Thank you very much.
####UPDATE####
Thanks everyone for such quick answers.
I did actually as Zdeslav Vojkovic suggested :
You should always update GUI from GUI thread
For completeness here is how I did:
Because my View is full WPF with no code behind i dont have any controls or form to be call BeginInvoke from, so in the static constructor of my ModelObj, I built an invisible Control from the UI Thread just to be able to call BeginInvoke on it.
So i declared it :
public static Control mInvokeControl;
delegate void MyDelegate();
private MyDelegate _NotifyDelegate;
and then did this in the static constructor of my Object:
mInvokeControl = new Control();
mInvokeControl.CreateControl();
in the normal constructor i Initialize the delegate this way:
_NotifyDelegate = new MyDelegate(this.NotifyByInvoke);
Then after i just use it this way:
ModelObj.mInvokeControl.BeginInvoke(this._NotifyDelegate );
With the method being:
public void NotifyByInvoke()
{
RaisePropertyChanged("Update");
}
Everything works fine !