A question regarding best practices.
When coding methods for an Inventor addin, which is preferred, passing m_inventorApplication from StandardAddInServer.CS (or .VB) to any class methods or getting the inventor object in each class / method with Marshal.GetActiveObject("InventorApplication") ?
I also ask because .Net CORE doesn't play nicely with Marshal, and if things go in that direction, the C# DllImport workaround is painful.
Solved! Go to Solution.
Solved by Michael.Navara. Go to Solution.
Don't understand what you're asking.
In VB addin template:
#Region "Data"
' Inventor application object.
Private m_inventorApplication As Application
#End Region
#Region "ApplicationAddInServer Members"
Public Sub Activate(ByVal addInSiteObject As ApplicationAddInSite, ByVal firstTime As Boolean
) Implements ApplicationAddInServer.Activate
Try
' This method is called by Inventor when it loads the AddIn.
' The AddInSiteObject provides access to the Inventor Application object.
' The FirstTime flag indicates if the AddIn is loaded for the first time.
' Initialize AddIn members.
m_inventorApplication = addInSiteObject.Application
Catch ex As Exception
Windows.Forms.MessageBox.Show(ex.ToString())
End Try
End Sub
#End Region
If I have other classes/methods in the same project but in other .vb files that require the application object is it best practice to pass the Inventor Application object to them as a parameter (m_inventorApplication) or have them get the object themselves?
I passed m_inventorApplication to another module.
Used oApp = addInSiteObject.Application in the class with Window Form for dialog.
They're converted from VBA macro to VB.Net.
Now I'm thinking, could I make m_inventorApplication public for both?
A good idea. I just added a method to the StandardAddInServer class that will return the object. It should be pretty stable. I'll start some testing.
(c#)
public Inventor.Application inventorAppObj(Inventor.ApplicationAddInSite addInSiteObject)
{
return addInSiteObject.Application;
}
Thinking further on this, it's not going to work.
The Activate method recieves the ApplicationAddInSite from inventor when it loads.
The method I just made won't get it from anywhere. I don't know what I was thinking.
I believe the most stable solution is to rewrite all my custom methods to accept an application object and pass it to them from within the activate method where it's available.
The best practice is to pass the Inventor application instance to constructor of your class which needs to do something with inventor. Below is the minimalistic sample of inventor addin implementation
class StandardAddInServer : ApplicationAddInServer
{
Inventor.Application inventor;
MyCommand myCommand;
public void Activate(ApplicationAddInSite AddInSiteObject, bool FirstTime)
{
//Get inventor app instance
inventor = AddInSiteObject.Application;
//Pass the inventor app to the command class
myCommand = new MyCommand(inventor);
//Create buttons in ribbon
inventor.UserInterfaceManager.Ribbons["ZeroDoc"].RibbonTabs["id_TabTools"].RibbonPanels["id_PanelP_ToolsOptions"].CommandControls.AddButton(myCommand.ButtonDefinition);
inventor.UserInterfaceManager.Ribbons["Part"].RibbonTabs["id_TabModel"].RibbonPanels["id_PanelP_Model2DSketchCreate"].CommandControls.AddButton(myCommand.ButtonDefinition);
}
public void Deactivate()
{
//Clear all buttons from ribbon
CommandControlsEnumerator myCommandControls = inventor.UserInterfaceManager.AllReferencedControls(myCommand.ButtonDefinition as ControlDefinition);
foreach (CommandControl cmdCtrl in myCommandControls)
{
try { cmdCtrl.Delete(); }
catch { }
}
//Clear button definition
myCommand.ButtonDefinition.Delete();
//Finalize the addin
inventor = null;
}
// Obsolete
public void ExecuteCommand(int CommandID) { }
// Not implemented
public object Automation => null;
}
class MyCommand
{
private readonly Inventor.Application inventor;
private ButtonDefinition buttonDef;
public ButtonDefinition ButtonDefinition => buttonDef;
public MyCommand(Inventor.Application inventor)
{
this.inventor = inventor;
buttonDef = inventor.CommandManager.ControlDefinitions.AddButtonDefinition(
"My command", "MyCommandInternalName", CommandTypesEnum.kQueryOnlyCmdType /* etc. */);
buttonDef.OnExecute += MyCommand_OnExecute;
}
private void MyCommand_OnExecute(NameValueMap Context)
{
MessageBox.Show(inventor.ActiveDocument.DisplayName, "My command");
}
}
Thank you. This helps loads. Just wrapping my brain around it. . .
So the _OnExecute method has access to the Inventor object because 'inventor' is given the inventor object when an instance of MyCommand is created?
My methods in the past have all been static, so it's a new concept.
Here is modified version with renamed variables of Inventor application for better understanding.
If you pass the inventor using constructor you don't need to use them static.
class StandardAddInServer : ApplicationAddInServer
{
Inventor.Application inventorAtAddInLevel;
MyCommand myCommand;
public void Activate(ApplicationAddInSite AddInSiteObject, bool FirstTime)
{
//Get inventor app instance
inventorAtAddInLevel = AddInSiteObject.Application;
//Pass the inventor app to the command class
myCommand = new MyCommand(inventorAtAddInLevel);
//Create buttons in ribbon
inventorAtAddInLevel.UserInterfaceManager
.Ribbons["ZeroDoc"]
.RibbonTabs["id_TabTools"]
.RibbonPanels["id_PanelP_ToolsOptions"]
.CommandControls.AddButton(myCommand.ButtonDefinition);
inventorAtAddInLevel.UserInterfaceManager
.Ribbons["Part"]
.RibbonTabs["id_TabModel"]
.RibbonPanels["id_PanelP_Model2DSketchCreate"]
.CommandControls.AddButton(myCommand.ButtonDefinition);
}
public void Deactivate()
{
//Clear all buttons from ribbon
var myCommandButtonAsControlDef = myCommand.ButtonDefinition as ControlDefinition;
var myCommandControls =
inventorAtAddInLevel.UserInterfaceManager.AllReferencedControls(myCommandButtonAsControlDef);
foreach (CommandControl cmdCtrl in myCommandControls)
{
try { cmdCtrl.Delete(); }
catch { /* IGNORE ALL ERRORS*/ }
}
//Clear button definition
myCommand.ButtonDefinition.Delete();
//Finalize the addin
inventorAtAddInLevel = null;
}
// Obsolete
public void ExecuteCommand(int CommandID) { }
// Not implemented
public object Automation => null;
}
class MyCommand
{
private readonly Inventor.Application inventorAtMyCommandLevel;
private ButtonDefinition buttonDef;
public ButtonDefinition ButtonDefinition => buttonDef;
public MyCommand(Inventor.Application inventorAsArgument)
{
inventorAtMyCommandLevel = inventorAsArgument;
buttonDef = inventorAtMyCommandLevel.CommandManager.ControlDefinitions.AddButtonDefinition(
"My command", "MyCommandInternalName", CommandTypesEnum.kQueryOnlyCmdType /* etc. */);
buttonDef.OnExecute += MyCommand_OnExecute;
}
private void MyCommand_OnExecute(NameValueMap Context)
{
MessageBox.Show(inventorAtMyCommandLevel.ActiveDocument.DisplayName, "My command");
}
}
I've implemented the above successfully, and would like to add I found a way to get the Application object from the Document object:
DOCUMENT.DOCUMENTINTERESTS.APPLICATION
It's not exactly well-advertised. I tend to think of my methods as recieving only the document object, not both the application and document objects.
Can't find what you're looking for? Ask the community or share your knowledge.