3

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 ModelObjinstance 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 !

user2164703
  • 199
  • 1
  • 11

2 Answers2

3

the COMObj is only accessible from the thread which created it

this is not true. It depends on objects apartment model, but usually you can access it from any thread and it will be either called on same thread or marshaled to proper thread.

I belive that your problem is that you update GUI from background thread which is a major no-no. You should always update GUI from GUI thread. When you update your model object, it still happens on background thread and event of INotifyPropertyChanged interfaces fires on that thread.

You need to synchronize model update to GUI thread by using something like this (WinForms, not WPF - in WPF you should use frm.Dispatcher.BeginInvoke but the problem is the same):

private delegate void ExecuteActionHandler(Action action);

public static void ExecuteOnUiThread(this Form form, Action action)
{
  if (form.InvokeRequired) { // we are not on UI thread
    // Invoke or BeginInvoke, depending on what you need
    // but you said ' and continue immediatly' so BeginInvoke it is 
    form.BeginInvoke(new ExecuteActionHandler(ExecuteOnUiThread), action);
  }
  else { // we are on UI thread so just execute the action
    action();
  }
}

There is another question with similar problem and I have provided additional details there.

Community
  • 1
  • 1
Zdeslav Vojkovic
  • 14,391
  • 32
  • 45
  • "the COMObj is only accessible from the thread which created it", you are actually right. I just add comments for others: If i make my new thread MTA, the COMObj reside in the main Thread (as it is the first to call CoInitialize of something like that i understand). But the ThreadingModel (see in the registry Editor) is Apartment, thats why this was true in my specific case. – user2164703 Mar 13 '13 at 10:35
  • I just have a residual question, assuming i call the BeginInvoke procedure but as I said, it takes more time to Update the UI than to process data, I'll make other BeginInvoke call before the previous action was terminated on the UI thread. Is my call lost or enqueued ? I'd rather for it to be lost. – user2164703 Mar 13 '13 at 12:51
  • Not sure for WPF as I don't use it, but for WinForms the calls are enqued as they are really handled with PostMessage. I would be surprised if WPF forms wouldn't use some similar technology - for sure the calls will not be lost, but I am not sure whether the order of execution is guaranteed. See more here: http://stackoverflow.com/a/2411183/1663919 – Zdeslav Vojkovic Mar 13 '13 at 12:55
  • Finally i decided to delete my use of invisible Control and use the Dispatcher Class: http://msdn.microsoft.com/en-us/library/ms615907.aspx I have a static variable getting the result of BeginInvoke with a DispatcherOperation , i check if the operation is completed through the status property, if not i send the update but with the DispatcherPriority.Inactive so the message is sent but as nothing will happen i wont saturate the whole thing. – user2164703 Mar 13 '13 at 15:58
0

I do not know how much data you process, or how much time it takes to perform the GUI part. You may also consider to use locked queues. You can use a queue within your ModelObj to enqueue new tasks by it. This you do with everything you get. Then you may have a timer thread (on the GUI thread).

Here you just check the locked queue, whether there is some new data to display on the GUI. You may dequeue the full list here locally. Then you can also check, whether there is more than one data to display on one component. This way you can skip updates, where you already have newer updates. And you skip the time for invoking the gui thread to perform the action. You can do several GUI updates at once. If you have too much things to do, you may dequeue only up to a specific number of items to let the GUI react on user interactions. However, you need to check that the queue is not constantly growing.

Patrick
  • 907
  • 9
  • 22
  • Thanks for your answer, i actually did think about what you describe but didnt want to use timers. My data are processed in couple of micro-seconds with a high optimized lib in c++, the UI update made it explodes to 1 to 20 ms. ( its a particles physic app) – user2164703 Mar 13 '13 at 11:24
  • I meant to use the timer only for GUI, not data processing. You may also gather your particles in a 2D array (X,Y position) And you can keep it in time slides. Then you may define an averaging window of e.g. 0.5s. You fill the array in your data thread, and push the rendered combined image from time to time to the GUI. – Patrick Mar 13 '13 at 12:10
  • Yes i already use a buffer in fact notify my GUI every X entries, timer would allow me to update at regular intervals, Its an idea, i'll look at it, or make it an option. Thks. – user2164703 Mar 13 '13 at 12:30