Thank you very much for your input @WCrihfield. And sorry for the late reply. I had to test multiple things to get things working.
I ended up with the following solution: Implementing a custom "Component Placer" with a "Re-Build" of "File open - Options"-GUI as pre-processing.
The problem in my case was, that we have an external AddIn, which registered a listener to execute a function everytime a "FileDialog.ShowOpen" was executed... and I found no way to suppress this "external" EventListening.. Maybe someone has an idea?
----
In case someone is interested in my solution, here is the coding:
InteractiveComponentPlacer.cs
public class InteractiveComponentPlacer
{
private readonly Application _invApp;
private readonly AssemblyDocument _asmDoc;
private readonly string _componentPath;
private readonly NameValueMap _loadOptions; // Options for placement/insertion
private NameValueMap _openOptions; // Options required for preview image creation (hidden load)
private InteractionEvents _interaction;
private MouseEvents _mouseEvents;
private KeyboardEvents _keyboardEvents;
private GraphicsNode _previewContainer;
private Document _compDoc;
private Action _onFinished;
public InteractiveComponentPlacer(Application inventorApp, string componentPath, NameValueMap loadOptions)
{
_invApp = inventorApp;
_componentPath = componentPath;
_loadOptions = loadOptions;
_asmDoc = _invApp.ActiveDocument as AssemblyDocument ?? throw new InvalidOperationException("Aktives Dokument ist keine Baugruppe.");
SetOpenOptions(loadOptions);
}
/// <summary>
/// Since we need to open the document in hidden mode we have to extract the valid
/// parameters for document function "OpenWithOptions()"
/// see @ https://help.autodesk.com/view/INVNTOR/2025/ENU/?guid=Documents_OpenWithOptions
/// </summary>
/// <param name="loadOptions"></param>
private void SetOpenOptions(NameValueMap loadOptions)
{
// At first copy given load options (insertion mode)
_openOptions = _invApp.TransientObjects.CreateNameValueMap();
for (int i = 1; i <= loadOptions.Count; ++i)
{
string name = loadOptions.Name[i];
_openOptions.Add(name, loadOptions.Value[name]);
}
// Remove via validator false open options (we do not require info about removed options)
InventorOpenOptionsValidator.ValidateNameValueMap(_componentPath, _openOptions);
}
public void StartPlacement(Action onFinished = null)
{
_onFinished = onFinished;
_interaction = _invApp.CommandManager.CreateInteractionEvents();
_interaction.InteractionDisabled = false;
if (_invApp.LanguageCode.Equals("de-DE"))
{
_interaction.StatusBarText = "Klicke zum Platzieren. ESC zum Abbrechen.";
}
else
{
_interaction.StatusBarText = "Click to place. ESC to cancel.";
}
_interaction.OnTerminate += OnInteractionTerminated;
_mouseEvents = _interaction.MouseEvents;
_keyboardEvents = _interaction.KeyboardEvents;
_mouseEvents.MouseMoveEnabled = true;
_mouseEvents.OnMouseMove += OnMouseMove;
_mouseEvents.OnMouseClick += OnMouseClick;
_keyboardEvents.OnKeyDown += OnKeyDown;
_interaction.Start();
CreatePreviewGraphics();
SetPreviewContainerTransformation();
}
private void OnMouseMove(MouseButtonEnum button, ShiftStateEnum shiftKeys, Point modelPosition, Point2d viewPosition, View view)
{
if (_previewContainer != null)
{
var matrix = _invApp.TransientGeometry.CreateMatrix();
matrix.SetTranslation(_invApp.TransientGeometry.CreateVector(modelPosition.X, modelPosition.Y, modelPosition.Z));
_previewContainer.Transformation = matrix;
view.Update();
}
}
private void OnMouseClick(MouseButtonEnum button, ShiftStateEnum shiftKeys, Point modelPosition, Point2d viewPosition, View view)
{
if (button != MouseButtonEnum.kLeftMouseButton)
{
return;
}
var matrix = _invApp.TransientGeometry.CreateMatrix();
matrix.SetTranslation(_invApp.TransientGeometry.CreateVector(modelPosition.X, modelPosition.Y, modelPosition.Z));
_asmDoc.ComponentDefinition.Occurrences.AddWithOptions(_componentPath, matrix, _loadOptions);
// Each insertion "destroys" existing preview Container. It is necessary to build it again
// so that OnMouseMove will display it correctly for further insertion
CreatePreviewGraphics();
SetPreviewContainerTransformation(matrix);
}
private void OnKeyDown(int keyCode, ShiftStateEnum shiftKeys)
{
if (keyCode == 27) // ESC
{
_interaction.Stop(); // Triggert OnInteractionTerminated
}
}
private void OnInteractionTerminated()
{
_interaction.OnTerminate -= OnInteractionTerminated;
_mouseEvents.OnMouseMove -= OnMouseMove;
_mouseEvents.OnMouseClick -= OnMouseClick;
_keyboardEvents.OnKeyDown -= OnKeyDown;
_asmDoc.Views[1].Update();
_compDoc?.Close(true);
_interaction = null;
if (_previewContainer != null)
{
_previewContainer.Delete();
}
_onFinished?.Invoke(); // Callback nach Abschluss
}
private void CreatePreviewGraphics()
{
if(_previewContainer != null)
{
_previewContainer.Delete();
}
_compDoc = _invApp.Documents.OpenWithOptions(_componentPath, _openOptions, false);
var clientGraphics = _interaction.InteractionGraphics.PreviewClientGraphics;
int nodeId = Guid.NewGuid().GetHashCode();
_previewContainer = clientGraphics.AddNode(nodeId);
ComponentDefinition compDef = null;
if (_compDoc is PartDocument partDoc)
{
compDef = partDoc.ComponentDefinition as ComponentDefinition;
}
else if (_compDoc is AssemblyDocument asmDoc)
{
compDef = asmDoc.ComponentDefinition as ComponentDefinition;
}
else
{
throw new InvalidOperationException("Nur IPT oder IAM werden unterstützt.");
}
_previewContainer.AddComponentGraphics(compDef);
_previewContainer.OverrideOpacity = 0.7;
}
private void SetPreviewContainerTransformation(Matrix matrix = null)
{
if(matrix == null)
{
// Initiale Transformation setzen (z. B. Ursprung)
var initialMatrix = _invApp.TransientGeometry.CreateMatrix();
initialMatrix.SetTranslation(_invApp.TransientGeometry.CreateVector(0, 0, 0), false);
matrix = initialMatrix;
}
_previewContainer.Transformation = matrix;
}
}
InventorOpenOptionsValidator.cs
/// <summary>
/// See https://help.autodesk.com/view/INVNTOR/2025/ENU/?guid=Documents_OpenWithOptions for more information
/// </summary>
public static class InventorOpenOptionsValidator
{
/// <summary>
/// Valid open options based on filetype
/// </summary>
private static readonly Dictionary<string, HashSet<string>> validOptions = new Dictionary<string, HashSet<string>>()
{
{
"Part", new HashSet<string>
{
"DesignViewRepresentation",
"ModelState",
"DeferFlatPatternUpdate",
"FileVersionOption",
"Password",
"SkipAllUnresolvedFiles"
}
},
{
"Assembly", new HashSet<string>
{
"DesignViewRepresentation",
"PositionalRepresentation",
"ModelState",
"ExpressModeBehavior",
"FileVersionOption",
"Password",
"SkipAllUnresolvedFiles"
}
},
{
"Drawing", new HashSet<string>
{
"DeferUpdates",
"FileVersionOption",
"Password",
"SkipAllUnresolvedFiles",
"ImportNonInventorDWG"
}
}
};
/// <summary>
/// Uses given options
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
/// <returns></returns>
public static List<string> ValidateNameValueMap(string filePath, NameValueMap options)
{
List<string> removedMessages = new List<string>();
string fileType = GetInventorFileType(filePath);
if (!validOptions.ContainsKey(fileType))
{
removedMessages.Add($"Unbekannter Dateityp: {fileType}");
return removedMessages;
}
HashSet<string> allowedKeys = validOptions[fileType];
List<string> keysToRemove = new List<string>();
for (int i = 1; i <= options.Count; i++)
{
string key = options.Name[i];
if (!allowedKeys.Contains(key))
{
keysToRemove.Add(key);
}
}
foreach (string key in keysToRemove)
{
options.Remove(key);
removedMessages.Add($"Ungültiges Schlüssel-Wert-Paar entfernt: '{key}' für Dateityp '{fileType}'");
}
return removedMessages;
}
private static string GetInventorFileType(string filePath)
{
string extension = Path.GetExtension(filePath).ToLowerInvariant();
switch (extension)
{
case ".ipt": return "Part";
case ".iam": return "Assembly";
case ".idw":
case ".dwg": return "Drawing";
default: return "Unknown";
}
}
}
Usage:
var placer = new InteractiveComponentPlacer(inventorApplication, documentFileName, loadOptions);
placer.StartPlacement(() =>
{
// Can be filled with additional methods, which are executed AFTER command finished
});