I want to get a .NET Element from a COM Element...
Element
using Bentley.DgnPlatformNET; using Bentley.DgnPlatformNET.Elements; using Bentley.MstnPlatformNET; using BCOM = Bentley.Interop.MicroStationDGN;
Element GetElementFromComElement (BCOM.Element oElement, bool addToModel) { if (addToModel) { BCOM.Application app = Bentley.MstnPlatformNET.InteropServices.Utilities.ComApp; app.ActiveModelReference.AddElement(oElement); } IntPtr pointer = (IntPtr)oElement.MdlElementRef(); Element el = Element.GetFromElementRef(pointer); return el; }
If I call the above function with addToModel True, it works. If I call the function with addToModel False, it returns a null. But I don't want to write the COM element to file: I want an in-memory .NET Element. What's going on?
addToModel
I've marked this thread as solved, because a work-around exists. The question: 'Can we obtain a .NET Element from COM?' remains unanswered.
Jon Summers said:If I call the above function with addToModel True, it works. If I call the function with addToModel False, it returns a null
When an element is first manufactured, underneath the paraphernalia of C++, .NET or VBA, it exists as a C++ ElementDescriptor. Until the element is persisted (added to a DGN model) the elementRef in that descriptor is NULL. Once the element is added to a model, an elementRef is created and (a) stored in the model cache and (b) assigned in the ElementDescriptor. At that point it becomes possible to use the conversion mechanism above to obtain a .NET Element.
ElementDescriptor
elementRef
So, if I want to create a .NET element in memory from a COM source, using the conversion shown above won't work. I must find some other procedure. Is there a way to construct a .NET Element from an MdlElementDescriptor, which is available from a COM element? There is a .NET Element constructor that takes a C++ ElementHandle, but there's no way to obtain an ElementHandle from a COM Element. What I could use is a .NET Element constructor that takes an MdlElementDescriptor, but unfortunately doesn't exist.
MdlElementDescriptor
ElementHandle
Robert Hook said:Does populating the ModelRef via GetFromElementRefAndModelRef work and provide desired results?
No, for the same reason explained above. The elementRef doesn't exist before the element has been added to a DGN model.
Regards, Jon Summers LA Solutions
Jon Summers said:if I want to create a .NET element in memory from a COM source
Just for curiosity, in what situation you need to do this conversion?
Jan
Bentley Accredited Developer: iTwin Platform - AssociateLabyrinth Technology | dev.notes() | cad.point
Jon Summers said:What I could use is a .NET Element constructor that takes an MdlElementDescriptor, but unfortunately doesn't exist.
It seems it exists internally, in Bentley.DgnPlatform.ElementHandle constructor accept element descriptor (I guess it's wrapper around EditElementHandle constructor). But it's true it's not available publicly.
For now, it seems the only way is to write own wrapper / convertor, similar to what is described in the linked blog about C++/CLI :-(
Regards,
Jan Šlegr said: in what situation you need to do this conversion?
Principally to solve the missing .NET create cell instance requirement. That is, use COM CreateCellElement2() and get a .NET CellHeaderElement.
CreateCellElement2()
CellHeaderElement
It works once the cell is added to a model. But I want to show the cell in dynamics, and therefore need an in-memory object.
Jon Summers said:Principally to solve the missing .NET create cell instance requirement.
I agree it's the issue not solved by Bentley for very long time (and asked many times).
When looking into documentation, even in C++ API it's not possible to use handler to load a cell from library, but "old" mdlCell_ functions have to be used.
Jon Summers said:But I want to show the cell in dynamics, and therefore need an in-memory object.
It looks like such simple and valid requirement leads to complex transaction: When displayed in dynamics, the cell and all relevant styles + levels should be loaded (but not stored in active DGN yet). And when placed, also attached data (XAttributes...) have to be copied from the cell library.
Jan Šlegr said:I agree it's the issue not solved by Bentley
The InterOp route suggested by Yongan.Fu in his csAddIn project works well. I've attached some code that implements both a normal cell placement tool and a shared cell placement tool. Both call VBA COM classes and methods.
To my pleasant surprise, it's possible, in a C# implementation, for a class to inherit from a COM interface (IPrimitiveCommandEvents)...
IPrimitiveCommandEvents
class PlaceSharedCellComTool : IPrimitiveCommandEvents { }
That gives us the state engine provided by COM, which works just as it does in VBA.
PlaceCellExample.zip
Answer Verified By: Jon Summers
Jon Summers said:To my pleasant surprise
Honestly, I think there is no reason why to be surprised. It's a standard way how C# works.
Jon Summers said:for a class to inherit from a COM interface (IPrimitiveCommandEvents)...
I don't want to be a stickler for technical accuracy, but when Bentley.Interop.MicroStationDGN.dll assembly is referenced and used, it's not COM interface in fact (which is available in ustation.dll), but classes already transformed to NET API (which is the only reason why COM Interop exists ;-) So all NET features are supported (in contrast with direct referencing and accessing COM library).