Handling Solid Edge Events

by Solution Partner Phenom Solution Partner Phenom ‎03-16-2015 09:26 PM - edited ‎03-17-2015 12:49 AM (2,481 Views)

Solid Edge provides a wide range of COM event sets that notify us when certain things occur. In this article, I will discuss how you can attach to these events from .NET. Prior to .NET, handling COM events was rather straightforward. It's a little tricker in .NET but still completely possible as you'll see.

 

For this article, I will be focusing on most popular Solid Edge event set, ISEApplicationEvents.

 

From .NET, we have two approaches available for connecting to COM events.

  1. Delegate Event Model
  2. Connection Point Model

Delegate Event Model

The delegate event model is typically more natural to .NET developers. This approach allows you to handle specific events rather than every event that an event set exposes.

 

If you open the Object Browser and search for ISEApplicationEvents, you will see the raw interface definition. This raw interface is not what we need in the delegate event model.

 

 

There is a hidden class that is generated by the type library importer named ISEApplicationEvents_Event that we need to leverage in this approach. In order to see the hidden class ISEApplicationEvents_Event, modify the Object Browser settings as shown below to Show Hidden Types And Members.

 

 

With the Object Browser settings in place, now search for ISEApplicationEvents_Event

 

 

Now that we are aware that ISEApplicationEvents_Event exists, we can leverage it with the following sample code. Please note that the code below is for demonstration purposes only and does not handle situations like when the BeforeQuit event is raised.

 

*Note that the ISEApplicationEvents_Event class will not be available in the code editor intellisense since it is a hidden class. You will have to manually type the full name and it will resolve.

 

Visual Basic - Delegate Event Model Example

Imports System
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Namespace EventTest
    Partial Public Class Form1
        Inherits Form

        Private _application As SolidEdgeFramework.Application
        Private _applicationEvents As SolidEdgeFramework.ISEApplicationEvents_Event

        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
            ' Connect to Solid Edge.
            _application = DirectCast(Marshal.GetActiveObject("SolidEdge.Application"), SolidEdgeFramework.Application)

            ' Connect to application events.
            _applicationEvents = CType(_application.ApplicationEvents, SolidEdgeFramework.ISEApplicationEvents_Event)
            AddHandler _applicationEvents.AfterDocumentSave, AddressOf _applicationEvents_AfterDocumentSave
            AddHandler _applicationEvents.BeforeDocumentSave, AddressOf _applicationEvents_BeforeDocumentSave
        End Sub

        Private Sub _applicationEvents_AfterDocumentSave(ByVal theDocument As Object)
            ' Handle AfterDocumentSave.
        End Sub

        Private Sub _applicationEvents_BeforeDocumentSave(ByVal theDocument As Object)
            ' Handle BeforeDocumentSave.
        End Sub

        Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
            ' Disconnect to application events.
            RemoveHandler _applicationEvents.BeforeDocumentSave, AddressOf _applicationEvents_BeforeDocumentSave
            RemoveHandler _applicationEvents.AfterDocumentSave, AddressOf _applicationEvents_AfterDocumentSave
            _applicationEvents = Nothing
        End Sub
    End Class
End Namespace

 

C# - Event Delegate Model Example

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace EventTest
{
    public partial class Form1 : Form
    {
        private SolidEdgeFramework.Application _application;
        private SolidEdgeFramework.ISEApplicationEvents_Event _applicationEvents;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Connect to Solid Edge.
            _application = (SolidEdgeFramework.Application)Marshal.GetActiveObject("SolidEdge.Application");

            // Connect to application events.
            _applicationEvents = (SolidEdgeFramework.ISEApplicationEvents_Event)_application.ApplicationEvents;
            _applicationEvents.AfterDocumentSave += _applicationEvents_AfterDocumentSave;
            _applicationEvents.BeforeDocumentSave += _applicationEvents_BeforeDocumentSave;
        }

        void _applicationEvents_AfterDocumentSave(object theDocument)
        {
            // Handle AfterDocumentSave.
        }

        void _applicationEvents_BeforeDocumentSave(object theDocument)
        {
            // Handle BeforeDocumentSave.
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Disconnect to application events.
            _applicationEvents.BeforeDocumentSave -= _applicationEvents_BeforeDocumentSave;
            _applicationEvents.AfterDocumentSave -= _applicationEvents_AfterDocumentSave;            
            _applicationEvents = null;
        }
    }
}

 

Connection Point Model

The Connection Point Model is a more raw, manual approach to handling events. It involves having a class implement an event interface, ISEApplicationEvents in this case. This means you will be handling every event that a particular event set raises.

 

In order to do this from .NET, we will need to leverage the IConnectionPointContainer and IConnectionPoint interfaces from the System.Runtime.InteropServices.ComTypes namespace.

 

Visual Basic - Connection Point Model Example

Option Infer On

Imports System
Imports System.Runtime.InteropServices
Imports System.Runtime.InteropServices.ComTypes
Imports System.Windows.Forms

Namespace EventTest
    Partial Public Class Form1
        Inherits Form
        Implements SolidEdgeFramework.ISEApplicationEvents

        Private _application As SolidEdgeFramework.Application
        Private _connectionPoint As IConnectionPoint
        Private _cookie As Integer

        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
            ' Connect to Solid Edge.
            _application = DirectCast(Marshal.GetActiveObject("SolidEdge.Application"), SolidEdgeFramework.Application)

            ConnectEvents()
        End Sub

        Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
            DisconnectEvents()
        End Sub

        Private Sub ConnectEvents()
            ' Get the event GUID.
            Dim typeGuid = GetType(SolidEdgeFramework.ISEApplicationEvents).GUID

            ' Get a reference to the IConnectionPointContainer.
            Dim container As IConnectionPointContainer = DirectCast(_application, IConnectionPointContainer)

            ' Lookup the IConnectionPoint.
            container.FindConnectionPoint(typeGuid, _connectionPoint)

            ' Advise the sink.
            _connectionPoint.Advise(Me, _cookie)
        End Sub

        Private Sub DisconnectEvents()
            ' Unadvise the sink.
            _connectionPoint.Unadvise(_cookie)

            ' Clear variables.
            _cookie = 0
            _connectionPoint = Nothing
        End Sub

        #Region "ISEApplicationEvents"

        Public Sub AfterActiveDocumentChange(ByVal theDocument As Object)
        End Sub

        Public Sub AfterCommandRun(ByVal theCommandID As Integer)
        End Sub

        Public Sub AfterDocumentOpen(ByVal theDocument As Object)
        End Sub

        Public Sub AfterDocumentPrint(ByVal theDocument As Object, ByVal hDC As Integer, ByRef ModelToDC As Double, ByRef Rect As Integer)
        End Sub

        Public Sub AfterDocumentSave(ByVal theDocument As Object)
        End Sub

        Public Sub AfterEnvironmentActivate(ByVal theEnvironment As Object)
        End Sub

        Public Sub AfterNewDocumentOpen(ByVal theDocument As Object)
        End Sub

        Public Sub AfterNewWindow(ByVal theWindow As Object)
        End Sub

        Public Sub AfterWindowActivate(ByVal theWindow As Object)
        End Sub

        Public Sub BeforeCommandRun(ByVal theCommandID As Integer)
        End Sub

        Public Sub BeforeDocumentClose(ByVal theDocument As Object)
        End Sub

        Public Sub BeforeDocumentPrint(ByVal theDocument As Object, ByVal hDC As Integer, ByRef ModelToDC As Double, ByRef Rect As Integer)
        End Sub

        Public Sub BeforeDocumentSave(ByVal theDocument As Object)
        End Sub

        Public Sub BeforeEnvironmentDeactivate(ByVal theEnvironment As Object)
        End Sub

        Public Sub BeforeQuit()
        End Sub

        Public Sub BeforeWindowDeactivate(ByVal theWindow As Object)
        End Sub

        #End Region
    End Class
End Namespace

 

C# - Connection Point Model Example

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Windows.Forms;

namespace EventTest
{
    public partial class Form1 : Form, SolidEdgeFramework.ISEApplicationEvents
    {
        private SolidEdgeFramework.Application _application;
        private IConnectionPoint _connectionPoint;
        private int _cookie;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Connect to Solid Edge.
            _application = (SolidEdgeFramework.Application)Marshal.GetActiveObject("SolidEdge.Application");

            ConnectEvents();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            DisconnectEvents();
        }

        private void ConnectEvents()
        {
            // Get the event GUID.
            var typeGuid = typeof(SolidEdgeFramework.ISEApplicationEvents).GUID;

            // Get a reference to the IConnectionPointContainer.
            IConnectionPointContainer container = (IConnectionPointContainer)_application;

            // Lookup the IConnectionPoint.
            container.FindConnectionPoint(ref typeGuid, out _connectionPoint);

            // Advise the sink.
            _connectionPoint.Advise(this, out _cookie);
        }

        private void DisconnectEvents()
        {
            // Unadvise the sink.
            _connectionPoint.Unadvise(_cookie);

            // Clear variables.
            _cookie = 0;
            _connectionPoint = null;
        }

        #region ISEApplicationEvents

        public void AfterActiveDocumentChange(object theDocument)
        {
        }

        public void AfterCommandRun(int theCommandID)
        {
        }

        public void AfterDocumentOpen(object theDocument)
        {
        }

        public void AfterDocumentPrint(object theDocument, int hDC, ref double ModelToDC, ref int Rect)
        {
        }

        public void AfterDocumentSave(object theDocument)
        {
        }

        public void AfterEnvironmentActivate(object theEnvironment)
        {
        }

        public void AfterNewDocumentOpen(object theDocument)
        {
        }

        public void AfterNewWindow(object theWindow)
        {
        }

        public void AfterWindowActivate(object theWindow)
        {
        }

        public void BeforeCommandRun(int theCommandID)
        {
        }

        public void BeforeDocumentClose(object theDocument)
        {
        }

        public void BeforeDocumentPrint(object theDocument, int hDC, ref double ModelToDC, ref int Rect)
        {
        }

        public void BeforeDocumentSave(object theDocument)
        {
        }

        public void BeforeEnvironmentDeactivate(object theEnvironment)
        {
        }

        public void BeforeQuit()
        {
        }

        public void BeforeWindowDeactivate(object theWindow)
        {
        }

        #endregion
    }
}

 

Connection Point Model - Option 2

You know I can't talk about this kind of stuff without mentioning the SolidEdge.Community NuGet Package. It's situations like this where the open source package shines. The NuGet package installs a class library with pre-built classes to handle scenarios like this. In this particular case, it provides a ConnectionPointController class that makes attaching to COM events very easy.

 

Visual Basic - Connection Point Model using SolidEdge.Community NuGet Package

Imports SolidEdgeCommunity
Imports System
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Namespace EventTest
    Partial Public Class Form1
        Inherits Form
        Implements SolidEdgeFramework.ISEApplicationEvents

        Private _application As SolidEdgeFramework.Application
        Private _connectionPointController As ConnectionPointController

        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
            ' Connect to Solid Edge.
            _application = DirectCast(Marshal.GetActiveObject("SolidEdge.Application"), SolidEdgeFramework.Application)

            _connectionPointController = New ConnectionPointController(Me)
            _connectionPointController.AdviseSink(Of SolidEdgeFramework.ISEApplicationEvents)(_application)
        End Sub

        Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
            _connectionPointController.UnadviseAllSinks()
        End Sub

        #Region "ISEApplicationEvents"

        ...

        #End Region
    End Class
End Namespace

 

C# - Connection Point Model using SolidEdge.Community NuGet Package

using SolidEdgeCommunity;
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace EventTest
{
    public partial class Form1 : Form, SolidEdgeFramework.ISEApplicationEvents
    {
        private SolidEdgeFramework.Application _application;
        private ConnectionPointController _connectionPointController;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Connect to Solid Edge.
            _application = (SolidEdgeFramework.Application)Marshal.GetActiveObject("SolidEdge.Application");

            _connectionPointController = new ConnectionPointController(this);
            _connectionPointController.AdviseSink<SolidEdgeFramework.ISEApplicationEvents>(_application);
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _connectionPointController.UnadviseAllSinks();
        }

        #region ISEApplicationEvents

        ...

        #endregion
    }
}

 

Conclusion

I was a programmer long before .NET was released and can remember how easy it was handling events from Visual Basic 6 so I can appreciate how some of you might feel after reading this article. To me, this all boils down to change. Yes it is different. Yes it is a bit more code. Yes you have to understand more than you did before .NET. The question is what are you going to do about it? You can either say this is too hard and give up or spend a little time understanding and learning the new techniques to stay relevant. As always, my goal is to be the hand that reaches out says "It's ok, I'll help you.".

 

Comments
by Phenom
‎03-09-2016 03:37 AM - edited ‎03-09-2016 03:50 AM

I am trying to handle the AfterActiveDocumentChange event and getting error

"AddHandler Statement Event Operand must be a dot-qualified expression or a simple name".

 

 

Private oApp As SolidEdgeFramework.Application

Private oAppEvents As SolidEdgeFramework.ISEApplicationEvents

Private oDoc As SolidEdgeFramework.SolidEdgeDocument

 

Sub Main()

oApp = DirectCast(Marshal.GetActiveObject("SolidEdge.Appl​ication"), SolidEdgeFramework.Application)

oDoc = DirectCast(oApp.ActiveDocument, SolidEdgeFramework.SolidEdgeDocument)

oAppEvents = CType(oApp.ApplicationEvents, SolidEdgeFramework.ISEApplicationEvents_Event)

 

AddHandler oAppEvents.AfterActiveDocumentChange(oDoc), AddressOf oApp_AfterActiveDocumentChange

End Sub

 

Private Sub oApp_AfterActiveDocumentChange(ByVal theDocument As Object)

' TO DO

End Sub

 

If I remove the argument oDoc in the AddHandler line, I get an error

"AfterActiveDocumentChange is not an event of SolidEdgeFramework.ISEApplicationEvents"

 

Has anyone seen this error before ?

Any help is highly appreciated.

Thanks.

 

~Tushar

 

by Solution Partner Phenom Solution Partner Phenom
on ‎03-09-2016 04:43 AM

I haven't coded it to verify but just by eye balling it, you should be using:

SolidEdgeFramework.ISEApplicationEvents_Event

not

 

SolidEdgeFramework.ISEApplicationEvents

I also recommend you download and look at my See my EventHandling VB sample.

 

by Dreamer
on ‎10-14-2016 08:14 AM

Dear jnewell,

 

I remember it was recommended in early versions to call GC.Collect() at the end of each event handler. Now, I can't see it in your examples anymore. Evenmore, we are experiencing freezing issues caused by GC.Collect() since ST7.

 

Are there still some cases where calling GC.Collect() is recommended? Or, what version it became obsolete?

 

Thanks in advance.

by Experimenter
on ‎03-04-2017 09:10 AM

is it possible get a mouse event click with the delegate method?

Labels