[CONNECT C#] Element.ReplaceInModel

While investigating this problem, I came across another.

The ManagedFenceExample app (delivered with the SDK) builds an ElementAgenda of the contents of the fence.  Then it enumerates the ElementAgenda and applies a transform to each element. Lastly, it replaces the element in the DGN model...

element.ApplyTransform(tInfo);
element.ReplaceInModel(element);

While testing, the above call crashes MicroStation with an internal fault (i.e. no message or error no. that I can report).  I replaced the last call to use a null instead of this...

element.ApplyTransform(tInfo);
element.ReplaceInModel(null);

Now the code creates a copy of the element (but no longer crashes MicroStation).

The documentation tells us that we can use this or null as the argument to ReplaceInModel(Element toReplace): If toReplace is null or equal to this, the current state of the element replaces the persistent state in the model. The documentation doesn't tell us that MicroStation will crash if we use this or copy the element if we use null.

Is the behaviour I observe a consequence of the element being a member of an ElementAgenda?

  • Hi,

    Is the behaviour I observe a consequence of the element being a member of an ElementAgenda?

    Well, there is no dependency between ReplaceInModel (which is quite simple wrapper around native EditElementHandle::ReplaceInModel) and ElementAgenda. On the other hand, when it's not "element type dependent issue" (see comment below), I can imagine it can be the consequence, visible on in this special case.

    Now the code creates a copy of the element

    It's expected behavior. When you will check how ReplaceInModel is implemented (or more correctly "to what code the implementation is compiled" ;-), you will see (using .NET Reflector Pro):

    public unsafe StatusInt ReplaceInModel(Element toReplace)
    {
        StatusInt num2;
        FinalizeAdjuster adjuster;
        EditElementHandle* handlePtr2 = (EditElementHandle*) this.ElementHandle[0];
        *((long*) &adjuster) = ((IntPtr) GCHandle.Alloc(this)).ToPointer();
        try
        {
            if (toReplace == null)
            {
                num2 = this.AddToModel();
            }
            else
            {
    ...

    So when the parameter is null, element is to be added to the model, not replaced.

    While testing, the above call crashes MicroStation with an internal fault

    For what element type MicroStation crashes? It was discussed in the past that e.g. Tag replacement does not work and leads to error.

    If it's not "type dependent", it's probably (have no time to test it now) issue of specific code (with a potential relation to ElementAgenda), because ReplaceInModel works fine.

    With regards,

      Jan

  • there is no dependency between ReplaceInModel (which is quite simple wrapper around native EditElementHandle::ReplaceInModel) and ElementAgenda

    I'm surmising that there might be an unexpected link. Perhaps a dangling pointer or other mal-formed internal code.

    The underlying MicroStationAPI classes work as expected. It may be that the .NET wrappers have created an unexpected diversion.

    It's expected behavior

    It's not: semantically 'Replace in Model' doesn't mean 'Replace if I do this' or 'Copy if I do that', which derives from C-style decisions based on null pointers.  There's room for an Element.CreateCopyInModel() method which is semantically explicit. 

    The documented behaviour of Element.ReplaceInModel() is not what I observe.  Your spelunking using the .NET Reflector Pro reveals that the implementation differs from the documentation.  Looking at that code, the behaviour matches what I observe — but it doesn't match the documentation.

    For what element type MicroStation crashes?

    I tested with lines and ellipses; nothing special.  I'm investigating ElementAgenda and found this problem along the way.  Build the delivered ManagedFenceExample and see what it does for you.

     
    Regards, Jon Summers
    LA Solutions

  • FYI. Friday I tried a couple other tests and was seeing a disconnect. Also, I received an update that a developer in this area was asked provide a review and update on this as soon as possible that I will pass along once available.

    Thank you,
    Bob



  • The documented behaviour of Element.ReplaceInModel() is not what I observe.

    I agree, the method implementation is very different from what is described in documentation. Because it's also different from C++ documentation of the same method (which is typically correct), for me it's just confirmation of "do not trust and depend on NET help files" (EC objects docs are exception).

    Your spelunking using the .NET Reflector Pro

    I do not like this word in the current context.

    To be able to use managed code decompiler is treated as standard skill in NET development. with a variety of usage: Before a majority of NET Framework libraries have become open source, it was often necessary to check the real implementation of some parts to understand bugs or to tune performance. Now, it's probably more often about a real understanding how Roslyn optimize the source code and how IL is created, regardless commercial solution (like .NET Reflector Pro) or some from free version or open source products (e.g. ILSpy) are used.

    BTW The reason why I invested into the commercial one is that trial saved my life in the past on several projects: A combination of ability to see the code (including debugging / stepping 3rd party code with PDB files) and performance + memory profiling (ANTS profiles) is just great ;-)

    Regards,

      Jan

  • Hi Jon,

    When I tried to move a parametric cell element, I also encountered the same situation(MS crashes). So please try below C# code snippet. It seems work for any cases.

    private void moveElemTest()
            {
                DTransform3d  trans = DTransform3d.FromTranslation(10000, 10000, 0);
                TransformInfo transInfo = new TransformInfo(trans);
    
                DgnModel  activeModel = Session.Instance.GetActiveDgnModel();
                Element   myElem = activeModel.FindElementById((ElementId)500514L);
                Element oldElem = Element.GetFromElementRef(myElem.GetNativeElementRef());
                myElem.ApplyTransform(transInfo);
                myElem.ReplaceInModel(oldElem);
            }



    Answer Verified By: Jon Summers 

  • I too am encountering a crash on using the ReplaceInModel.  I am calling within a scan callback.  

    If I use the example code from Yongan to "translate" an element (even by 0,0,0) it works fine.  But if I remove the ApplyTransform and basically leave the element unchanged, it crashes. Seems like replacing an element with an exact copy of itself crashes.

    Works

    private void moveElemTest(Element myElem)
    	{
    	DTransform3d trans = DTransform3d.FromTranslation(0, 0, 0);
    	TransformInfo transInfo = new TransformInfo(trans);
    
    	Element oldElem = Element.GetFromElementRef(myElem.GetNativeElementRef());
    	myElem.ApplyTransform(transInfo);
    	myElem.ReplaceInModel(oldElem);
    	}

    This seems to fail

    private void UpdateElement(Element myElem)
    	{
    	Element oldElem = Element.GetFromElementRef(myElem.GetNativeElementRef());
    	myElem.ReplaceInModel(oldElem);
    	}
    

    It's been a while since Jon's original post. I am using MicroStation update 16 and SDK to match.  Is this still expected behavior?

  • If I use the example code from Yongan

    Try getting the original element by its ID...

    Element oldElem = activeModel.FindElementById(myElem.ElementId);

     
    Regards, Jon Summers
    LA Solutions

  • Hi,

    because this thread is more than a year and half old (and as you mentioned also, MicroStation and SDK versions are different), I recommend to ask in a new post.

    I too am encountering a crash on using the ReplaceInModel

    It's too vague information. What is the source element (simple, complex, an element inside complex element...) and where it comes from (active model, another model opened at background...).

    Is this still expected behavior?

    As far as I remember, ReplaceInModel work fine usually, the only exception where it fails always is when an element inside cell (maybe in complex element generally) is updated.

    With regards,

      Jan