NOTICE: The Rhino.NET SDK is deprecated in Rhino 5. This example adapted for the new RhinoCommon SDK is here
If you have some controls that are using an event watcher to synchronize a control's appearance with what is going on in Rhino, please read the following.
The virtual function inside your event watcher class potentially could be called from a thread that is NOT your main user interface thread. This happens in the case where a long running command has started a thread to allow a user to cancel a command. A sample case where this occurs is in the contour command and the OnAddObject virtual function.
Windows applications can not update any user interface from any thread other than the main UI thread. Changing a Windows Forms control property typically causes the control to immediately update its display. When this happens, windows will crash the application.
If you are updating a control from inside your event watcher virtual function, you should check to see if InvokeRequired on your control is equal to True. If this is the case, you must invoke a delegate to handle your UI updating. This is actually easier than it sounds.
Here is a VB.NET sample of OnAddObject inside of your event watcher subclass
Public Overrides Sub OnAddObject(ByRef doc As MRhinoDoc, ByRef obj As MRhinoObject) 'm_ctrl is your windows forms control that you want to update If( m_ctrl.InvokeRequired ) Then 'This code is being called inside a non-ui thread. You should not updated your 'control from this thread Else 'It is fine to update your control m_ctrl.Text = "OnAddObject was called" End If End Sub
This is where Invoke or BeginInvoke comes into play. You can tell your control that your want it to run some code in the main UI thread. Here is a VB.NET sample of how to do this. Again this would all be inside of your event watcher subclass.
'delare a delegate Private Delegate Sub OnAddDelegate( text as String ) Private Sub SetControlText( text as String ) m_ctrl.Text = text End Sub Public Overrides Sub OnAddObject(ByRef doc As MRhinoDoc, ByRef obj As MRhinoObject) If( m_ctrl.InvokeRequired ) Then m_ctrl.BeginInvoke( New OnAddDelegate(AddressOf SetControlText), "OnAddObject was called" ) Else SetControlText( "OnAddObject was called" ) End If End Sub
The above function could be rewritten to just always call the delegate
Public Overrides Sub OnAddObject(ByRef doc As MRhinoDoc, ByRef obj As MRhinoObject) m_ctrl.BeginInvoke( New OnAddDelegate(AddressOf SetControlText), "OnAddObject was called" ) End Sub