Site Tools


Event Watchers

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.

Why is this of any interest to you?

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.

So... what can I do about this?

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

But... I really do need to update my control's state even when in the wrong thread!

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
developer/dotneteventwatcher.txt ยท Last modified: 2015/09/14 (external edit)