Issues with Add-ins using ControlDefinitions in C#

Issues with Add-ins using ControlDefinitions in C#

Anonymous
Not applicable
1,658 Views
4 Replies
Message 1 of 5

Issues with Add-ins using ControlDefinitions in C#

Anonymous
Not applicable

I've run into an issue trying to get my add-in to execute inventor commands via ControlDefinitions and was wandering if anyone else has run into this and figure out how to make this work (in C#).  I'm using user interactions to have the user select a face then export the selected face to a .DWG file via the GeomToDXFCommand (all I need are plines describing the edge of the selected face).

 

Here's the OnExecute portion of the StandardAddInServer.cs file:

 

 

void CreateDwgButtonDef_OnExecute(NameValueMap Context)
{
Die DieCreation = new Die(m_inventorApplication);
}

 

Here's the basic area of the class in question

public class Die
{
#region Class Variable Declaration
private bool bStillSelecting;

private Inventor.Application inventorApp;
private Edge xAxis;
private Face dieProfile;
private PartDocument partDoc;

private SelectEvents selectEvents;
private InteractionEvents interaction;
#endregion

public Die(Inventor.Application app)
{
#region Variable Declarations
inventorApp = app;
partDoc = (PartDocument)inventorApp.ActiveDocument;

ControlDefinition controlDef;
CommandManager commandManager = inventorApp.CommandManager;
#endregion

#region Setup event handlers for user interaction
interaction = commandManager.CreateInteractionEvents();
interaction.SelectEvents.OnSelect += new SelectEventsSink_OnSelectEventHandler(SelectEvents_OnSelect);
selectEvents = interaction.SelectEvents;
#endregion

#region Select Extrusion Face and X-Axis
// Note, that the event handler takes care of assigning the selected entities to the
// correct object (dieProfile or xAxis).
UserSelect("Select surface describing the extrusion", SelectionFilterEnum.kPartFacePlanarFilter);
UserSelect("Select X-Axis for Die Properties", SelectionFilterEnum.kPartEdgeLinearFilter);
#endregion

#region Die Export
// Export the Die Profile to a user specified file
partDoc.SelectSet.Clear();
partDoc.SelectSet.Select(dieProfile);

controlDef = commandManager.ControlDefinitions["GeomToDXFCommand"];
controlDef.Execute();
#endregion
}

void SelectEvents_OnSelect(ObjectsEnumerator JustSelectedEntities, SelectionDeviceEnum SelectionDevice, Point ModelPosition, Point2d ViewPosition, Inventor.View View)
{
// check to see if the entity select is a face or an edge
if ((JustSelectedEntities[1] as Face) != null)
dieProfile = (Face)JustSelectedEntities[1];
else
xAxis = (Edge)JustSelectedEntities[1];

bStillSelecting = false;
}

void UserSelect(string statusBar, SelectionFilterEnum filter)
{
// setup Inventors status bar
interaction.StatusBarText = statusBar;

// Setup the selection filter based on the passed filter
selectEvents.ClearSelectionFilter();
selectEvents.ResetSelections();
selectEvents.AddSelectionFilter(filter);


selectEvents.SingleSelectEnabled = true;
bStillSelecting = true;
interaction.Start();

//loop until the user selects an entity
while (bStillSelecting)
System.Windows.Forms.Application.DoEvents();

interaction.Stop();
}
}

 

 

 

 

 

The problem occurs within the Die Export Region of the code.  I've set the Control Definition to the GeomToDXFCommand but nothing happens (no export occurs).  If I run the above code as part of a stand alone application (not as an add-in) that hooks into an existing instance of inventor  using the below code I don't have any issues (everything works perfect).

 

 

    Inventor.Application inventorApp = null;
try
{
// Attempt to get a reference to a running instance of Inventor.
inventorApp = (Inventor.Application)Marshal.GetActiveObject("Inventor.Application");

}
catch
{
return;
}

Die dieData = new Die(inventorApp);

 

The REALLY weird part is I was worried that maybe the entity being pre-selected was an incorrect entitiy type (saw something similar to this on another post).  So, I did something to confirm I was having problems with the ControlDefinition and not the entity selected.  I inserted the following piece of code into my app and still absolutely nothing.

 

 

 

    controlDef = commandManager.ControlDefinitions[""PartNew3DSketchCmd""];
controlDef.Execute();

 Since the PartNew3DSketchCmd doesn't take any preselected entities or have any user interaction to create the sketch it should have created a new 3D Sketch in the active part file.  Since nothing happened I'm pretty sure I was able to isolate my problem to how I'm using ControlDefinitions (or at least I hope it's how I'm setting them up and that they aren't bugged for Add-ins when using C#).

 

Any Ideas?

Alan

 

0 Likes
1,659 Views
4 Replies
Replies (4)
Message 2 of 5

Anonymous
Not applicable

I talked to one of our in-house programmers and he asked a good question.  With Inventor can you execute an inventor command from within an add-in?  I had assumed yes, but based on what I'm seeing above I question if my assumption is right.  Anyone know definitely that it's possible to execute an Inventor command from within an Add-in?

0 Likes
Message 3 of 5

AlexFielder
Advisor
Advisor

Hi Alan,

 

I was going to write a post with an example, but Brian has an article on how to do this here so it's saved me the trouble.

 

Cheers,

 

Alex. 

 

 

0 Likes
Message 4 of 5

Qube-it
Advocate
Advocate

In my experience, the use of the "Application.DoEvents()" method causes unexpected things to happen.  Just Bing/Google "Why DoEvents is evil" and you'll see what I mean.  That method might be interfering with being able to call the "controlDef.Execute()" method from inside the Inventor process (i.e. as an add-in).  Don't ask me how, though.  🙂  

 

I can see that you're using "Application.DoEvents()" to essentially wait for the selection process to end before calling the "interaction.Stop()" method.  Instead, I personally would let the "interaction.Start()" method be the last line of your "UserSelect()" method and call the "interaction.Stop()" method from inside the OnSelect_EventHandler.  Actually, I would probably take it one step further and create another method called "StopSelecting()" and call it as the last action inside the OnSelect_EventHandler.  "StopSelecting()" would contain code to clear the selection, reset the selection filter, and call the "interaction.Stop()" method.

 

Just something I would try.  Smiley Happy

-Brian Hall-
0 Likes
Message 5 of 5

Anonymous
Not applicable

Brian,

 

Just got back to this one.  When I first read your post a few weeks back I thought I understood what you were heading towards, but when I started to code it I couldn't figure out what prevents the code from continueing on immediately and not waiting for the user to select something?  Wouldn't the code immediately proceed past the two UserSelect commands and get down to the line

 

 partDoc.SelectSet.Select(dieProfile);

where it would crash since the dieProfile hasn't been assigned yet?  There needs to be some kind of a loop (or command) in the code somewhere to prevent the code from proceeding on until the selection process is complete.

 

I really don't think the issue is with DoEvents() tho.  I tried to explain this but did it rather badly now that I go back and look at what I said.  I placed the code below right after the CommandManager definition and deleted out everything else.  No DoEvents() and things still didn't workout.

 

controlDef = commandManager.ControlDefinitions[""PartNew3DSketchCmd""];
controlDef.Execute();

 

I suspects there's an issue with Addins not running properly when coded from C# with regards to ControlDefinitions. I'm assuming that it's an issue with C# and not VB.net since more people seem to be using VB.net to write their add-ins.

 

I did find a rather roundabout workaround.  Here's the steps for anyone interested:

 

     1)  Create an external app that will do everything you want (with regards to controldefinitions that is).  Simply write it in such a way that you have to pass the Inventor.Application object to it when starting the executable (you didn't want to rely on the code going out and finding the correct instance of inventor if multiple instances were running). 

     2)  Add the application (executable) to a seperate C# Project as a Resource that will be Embedded into the library when compiled.

     3)  Executed the embeded resource within the ButtonDef_OnExecute in a seperate thread.

 

Here's the code for step 3.  It's actually the trickiest.

 

 

        void UpdateDwgButtonDef_OnExecute(NameValueMap Context)
        {
            //A seperate thread is required for the execution of an embeded executable with
            //the resources.
            System.Threading.Thread t = new System.Threading.Thread(Launch);
            t.Start();
        }

        private void Launch()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            System.IO.Stream stream = assembly.GetManifestResourceStream("DrawingUpdateAddin.Resources.DrawingUpdate.exe");
            byte[] ba = new byte[stream.Length];
            stream.Read(ba, 0, ba.Length);
            Assembly embedded = Assembly.Load(ba);
            Type t = embedded.GetType("DieDrawingUpdate.Program");
            BindingFlags bf = BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
            t.InvokeMember("Main", bf, null, null, null);
        }

The key is making sure the compiled executable from your other C# project is an embeded resourse.  You could also do this as a seperate executable and not embed the file and simply the code above.  I just like the fact that this method creates a single DLL for distribution purposes.

 

 

0 Likes