Blog

Blog2023-10-15T01:29:24-04:00

Event Handlers in SOLIDWORKS Addins

Written by Sean Stubbe

Introduction

Event handlers in SOLIDWORKS addins appear relatively straightforward to implement but they lack good documentation and I have not been able to find a full example online. There are also some caveats that can easily trip you up. Firstly, event handlers are called ‘Delegates’ in the SOLIDWORKS API and while there is a difference between events and delegates (see Delegates vs. events | Microsoft Docs), we will use the terms interchangeably in this article. You can find a full list of the events available in the Sldworks interface and its quite useful to browse them to see which events are available.

A common naming schema is used where every delegate starts with ‘D’ followed by the context in which they apply, and end with a ‘_’ suffix. For example, ‘DAssemblyDocEvents_DeleteItemPreNotifyEventHandler’ fires whenever an item is about to be deleted in an assembly. There are currently 8 interfaces in which events are implemented but note that most of them are directly available from ISldWorks.

  • ISldWorks – application events
  • IPartDoc – part events
  • IAssemblyDoc – assembly events
  • IDrawingDoc – drawing events
  • IModelView – modelview events (graphics related)
  • IMouse – mouse events (mouse moved, button pressed)
  • IMotionStudy – (implemented in swmotionstudy namespace)
  • ISWPropertySheet – property sheet events
  • ITaskpaneView – taskpane events
  • IFeatMgrView – feature manage design tree events (very limited)

Implementation Example

This example assumes we already have the boilerplate for a default C# Solidworks addin. The goal is to force new drawing views to use ‘Projected’ dimensions so we need to catch a ‘View Created’ event somehow and change the dimension type. It is a good example because it contains the boilerplate for implementing handlers and goes a littler further by demonstrating how to ‘chain’ events to access ones in specific contexts.

First, add a new class for the event handler logic. All of the following functions are added to this class.

using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
using System;

internal class EventHandlers
{
}

Next, declare all the event handlers you wish to implement as private static members. Note that you may need to ‘chain’ events to get the desired functionality. In this example, we need to handle the ActiveModelDocChanged event to catch the AddItemNotifyEvent event in drawings. Note the OnModelDocChanged and OnDrawingFeatureCreated parameters – these are the functions will get called when the events fire.

private static DSldWorksEvents_ActiveModelDocChangeNotifyEventHandler modelChanged = new DSldWorksEvents_ActiveModelDocChangeNotifyEventHandler(OnModelDocChanged);
private static DDrawingDocEvents_AddItemNotifyEventHandler drawCreateFeature = new DDrawingDocEvents_AddItemNotifyEventHandler(OnDrawingFeatureCreated);

Add a function to attach application level event handlers. This needs to be called from your main ConnectToSW() function. Note that the modelChanged event we created in the first step is referenced here.

public static void AttachEventHandlers(SldWorks swApp)
{
    swApp.ActiveModelDocChangeNotify += modelChanged;
}

Add a function to detach application level event handlers. This needs to be called from your main DisconnectFromSW() function. Note that the modelChanged event is removed and another function is called to remove other event handlers.

public static void DetachEventHandlers(SldWorks swApp)
{
    swApp.ActiveModelDocChangeNotify -= modelChanged;
    DetachDocEventHandlers();
}

Next, add functions for attaching and detaching document level events. Note that we are only implementing a drawing event in this example but the full structure is shown so you can see where to add part and assembly event handlers as well.

private static void AttachDocEventHandlers()
{
    ModelDoc2 swModel = Main.swApp.ActiveDoc;
    if (swModel != null)
    {
        switch ((swDocumentTypes_e)swModel.GetType())
        {
            case swDocumentTypes_e.swDocPART:
            break;
            case swDocumentTypes_e.swDocASSEMBLY:
            break;
            case swDocumentTypes_e.swDocDRAWING:
            (swModel as DrawingDoc).AddItemNotify += drawCreateFeature;
            break;
        }
    }
}

private static void DetachDocEventHandlers()
{
    ModelDoc2 swModel = Main.swApp.ActiveDoc;
    if (swModel != null)
    {
        switch ((swDocumentTypes_e)swModel.GetType())
        {
            case swDocumentTypes_e.swDocPART:
            break;
            case swDocumentTypes_e.swDocASSEMBLY:
            break;
            case swDocumentTypes_e.swDocDRAWING:
                (swModel as DrawingDoc).AddItemNotify -= drawCreateFeature;
            break;
        }
    }
}

Now we need to implement the functions we specified earlier and handle the events we attached to. The OnModelDocChanged() function is pretty simple and just adds the document event handlers in this example. This will fire every time the active model is changed.

private static int OnModelDocChanged()
{
    AttachDocEventHandlers();
    return 0;
}

Finally, the OnDrawingFeatureCreated() function can be implemented to add the functionality we are looking for. This event fires every time a new feature is added to a drawing so we handle it and get the last feature added, check if its a view, and set the view to use projected dimensions if it is.

private static int OnDrawingFeatureCreated(int featureType, string featureName)
{
    try
    {
        if (featureType == (int)swNotifyEntityType_e.swNotifyDrawingView)
        {
            ModelDoc2 swModel = Main.swApp.ActiveDoc;
            Feature swFeat = swModel.Extension.GetLastFeatureAdded();
            View swView = swFeat.GetSpecificFeature2();
            swView.ProjectedDimensions = true;
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Unhandled Exception. " + ex.StackTrace);
    }
    return 0;
}

Cancelling Events

Sometimes it is desirable to ‘cancel’ events to prevent users from performing certain commands or to redirect them to different functionality. This is usually supported for ‘Pre’ events but there are no solid rules as far as I can tell. You may have noticed that the handler functions return an integer and they return 0 in the example above. Returning 1 instead of 0 tells SOLIDWORKS that the ‘Pre’ event has failed and it will not proceed any futher, thus ‘cancelling’ the event. However, this will not work for every event. Another option that works in some cases is to throw a COMException. This exception will get passed to SOLIDWORKS and it will end the thread processing the event in some cases.

By |October 15th, 2023|0 Comments

Visit us at 3DExperience World 2023!

Hard to believe that its been three years since the SOLIDWORKS community gathered together in person. In that time, CADSharp has grown over four-fold, from five full-time contractors to over twenty. We’re more excited than ever to talk to SOLIDWORKS and SOLIDWORKS PDM customers about their automation needs. You can find us at booth 747. I’ll also be presenting on Monday at 11:15 AM on the topic, “Macros vs Addins vs Stand-Alones”, where I’ll be covering the pros and cons of each program type you can use with the SOLIDWORKS API.

See you in Nashville!

Keith

If you want to learn about upcoming learning opportunities, be sure to join our newsletter.

By |February 10th, 2023|0 Comments
Go to Top