[C# Connect] Possible to Clone an Element?

Since there is no easy way to access a cell from a library in the new API, I have written my own which goes thru the cell library DGN file(s) and extracts the dgnmodel for the desired cell..  It is recreated child by child and placed in a CellHeaderElement in the active model.

I was recreating the children by using the following to copy from the cells DgnModel to the Active DgnModel:

        public static Element Clone(this Element ele)
        {
            Element newEle;
            using (ElementCopyContext copy = new ElementCopyContext(Ms.GetActiveModel()))
            {
                copy.DisableAnnotationScaling = true;
                newEle = copy.DoCopy(ele);
            }

            return newEle;
        }

All was well, until I noticed that my cell was being duplicated at 0,0,0... This is due to the ElementCopyContext also adding the element to the model.

Any suggestions on how I can make a clone of the element and store in memory without adding it to the DGN active model?

I cannot simply use the Element returned from the Cell DgnModel.
  • Set WriteElements to false on your ElementCopyContext.

    /// <summary> Set the copy context value that determines whether the element descriptor
    /// being copied will get written to the destination model ref.
    /// Regardless of the value passed in, the additional necessary information
    /// (styles, levels, etc.) will be copied to the destination model ref. </summary>
    /// <remarks>This is defaulted to \c true in the constructor.</remarks>
    /// <param name="value">\c true to copy all elements to the destination model ref;
    /// \c false to just copy necessary additional elements.</param>
    property bool WriteElements
    {
    bool get ();
    void set (bool value);
    }



    Answer Verified By: Maury 

  • Thanks! That worked! I am not sure how I missed that.
  • For anyone, like me, reading this years later (now using MicroStation CONNECT API for Update 17.2) and thinking this is a convenient way to replicate the "Clone" function on the Bentley COM Interop interface... it is not. Not in its current form anyway.

    The ElementCopyContext's DoCopy method has the unexpected side effect that it also modifies the original element that was sent to be copied.

    Specifically, it modifies the ElementId, IsPersistent, and IsNew values of the original elementToCopy.

    So, to mimic the Interop Clone method, you can use the following code that also restores the original element, if it had an ElementId and it was Persistent (the element matched the version in the ElementCache).

    If it was a new element passed to be copied then the changes do not matter, but if it was an existing Persistent element with an ElementId and you want to continue using your variable reference that you passed to the Clone function after the call, then you need to restore the original after the copy was made.

            /// <summary>
            /// Copies the element to the active model, but does not add it.
            /// </summary>
            /// <param name="elementToCopy">The <see cref="BDE.Element"/> to create a copy from into the active model.</param>
            /// <returns>Copy of the original element</returns>
            public static BDE.Element Clone(ref BDE.Element elementToCopy)
            {
                BDE.Element newElement;
                var elementRef = elementToCopy.GetNativeElementRef();
    
                using (BD.ElementCopyContext copyContext = new BD.ElementCopyContext(BM.Session.Instance.GetActiveDgnModelRef())
                {
                    WriteElements = false,
                    DisableAnnotationScaling = true,
                    PreserveElementIds = false,
                    AssignNewGraphicGroups = true,
                    ForceDependentsToRemap = true
                })
                {
                    // Beware the original elementToCopy's ElementId, IsPersistent, and IsNew values will be modified by DoCopy.
                    newElement = copyContext.DoCopy(elementToCopy);
                }
                if (IntPtr.Zero != elementRef)
                {
                    //Restore the original element
                    elementToCopy = BDE.Element.GetFromElementRef(elementRef);
                }
                return newElement;
            }

    This function can however not be used as an extension, because it requires the original to be passed by ref so that the reference can be replaced.

    HTH

    Answer Verified By: Maury