[CONNECT .net c#] How to copy ECInstance from cell to all its subelements

need a little bit of direction/help. I have a dgn file with 10000s of elements that came from different shape files. to be clear these are elements in the model. It is not a shape file reference. 

the attributes from the shape file turned into an item on the element. 

my problem is the shape file did some weird things when importing it. some of the linear line strings came in as a cell comprised of several line strings. i need to drop those cells but i don't want to lose the attribute data that came from the shape file.

So i want to get the item on the cell and then loop the sub elements and apply that item to all the sub elements.

finding the cells and looping the sub-elements is not a problem, its how to copy the item.

i normally deal with item types but quickly found out these items are not an item type and i cant use the sdk calls im used it using.

im able to see the item on a given cell by looping the ECInstances.

but im struggling with the next step. 

im thinking i need to get the schema for this item and then attach it as a new ECInstance to each sub-element and then apply the property values from the item on the cell to each new ec instance on each sub-element.

if i was dealing with item types i would create a customitemhost and applycustomitem. but not sure how do to this at at the ec level???

using (DgnECInstanceCollection dgnECInstances = DgnECManager.Manager.GetElementProperties(el, ECQueryProcessFlags.SearchAllClasses))
                {
                    foreach (IDgnECInstance ecInstance in dgnECInstances)
                    {
                        if (ecInstance.ClassDefinition.Name == "OhioRailLinesSelect")
                        {
                            //get schema from instance
                            IECSchema schema = ecInstance.ClassDefinition.Schema;
                            //
                            ChildElementCollection subElements = (el as CellHeaderElement).GetChildren();
                            foreach (Element subElement in subElements)
                            {
                                //add new EC instance to subelement??

                                //loop and apply value to each property 
                                
                            }
                        }
                    }
                }

any help/direction would be great! thanks

Parents
  • Hi John,

    some of the linear line strings came in as a cell comprised of several line strings.

    It's probably done to maintain features collection, which is standard GIS functionality ... and often is translated to MicroStation as "group elements to a cell" ;-)

    So i want to get the item on the cell and then loop the sub elements and apply that item to all the sub elements.

    A question is whether to:

    • attach EC data to elements inside cell and to drop it afterwards
    • read EC data from the cell, remember it, drop the cell and to attach data to result

    The first way is of course simpler, but there are some limitations in current NET API (it is not possible to modify a cell content), but I assume it does not apply to EC instance attachment (because it does not modify the element itself).

    i normally deal with item types but quickly found out these items are not an item type and i cant use the sdk calls im used it using.

    Yes, SHP import creates (from V8i era, when Item Types did not exist) normal EC data.

    but im struggling with the next step. 

    Did you read EC CRUD Operations blog? All tasks are described there, as well as in several examples, delivered with MicroStation SDK.

    and then apply the property values from the item on the cell to each new ec instance on each sub-element.

    The looping EC property, as mentioned in your code snippet, is wrong idea. Technically correct, but useless (and leads to plenty of extra code). There is ECInstanceHelper class available, allowing to copy instance data at once.

    Regards,

      Jan

    Answer Verified By: John Drsek 

Reply
  • Hi John,

    some of the linear line strings came in as a cell comprised of several line strings.

    It's probably done to maintain features collection, which is standard GIS functionality ... and often is translated to MicroStation as "group elements to a cell" ;-)

    So i want to get the item on the cell and then loop the sub elements and apply that item to all the sub elements.

    A question is whether to:

    • attach EC data to elements inside cell and to drop it afterwards
    • read EC data from the cell, remember it, drop the cell and to attach data to result

    The first way is of course simpler, but there are some limitations in current NET API (it is not possible to modify a cell content), but I assume it does not apply to EC instance attachment (because it does not modify the element itself).

    i normally deal with item types but quickly found out these items are not an item type and i cant use the sdk calls im used it using.

    Yes, SHP import creates (from V8i era, when Item Types did not exist) normal EC data.

    but im struggling with the next step. 

    Did you read EC CRUD Operations blog? All tasks are described there, as well as in several examples, delivered with MicroStation SDK.

    and then apply the property values from the item on the cell to each new ec instance on each sub-element.

    The looping EC property, as mentioned in your code snippet, is wrong idea. Technically correct, but useless (and leads to plenty of extra code). There is ECInstanceHelper class available, allowing to copy instance data at once.

    Regards,

      Jan

    Answer Verified By: John Drsek 

Children
  • Thanks Jan,

    this is all very helpful. i was able to get a new instance added to the sub elements. but its only for the current session of microstation. once i close and reopen the sub elements no longer have the item attached. 

    also im struggling with the copy instance Data method. with getting the IEnumerable<string> propertyAccessors. i saw there is a a GetAsPropertyAccessors method in the ECInstanceHelper class. i figured thats what i needed to use to the propertyAccessors for the CopyInstanceData method. but im doing something wrong because it just crashes microstation.

    using (DgnECInstanceCollection dgnECInstances = DgnECManager.Manager.GetElementProperties(el, ECQueryProcessFlags.SearchAllClasses))
                    {
                        foreach (IDgnECInstance ecInstance in dgnECInstances)
                        {
                            if (ecInstance.ClassDefinition.Name == "OhioRailLinesSelect")
                            {
                                IECClass ecClass = ecInstance.ClassDefinition;
                                //this line is crashing MicroStation...
                                IEnumerable<string> properties = ECInstanceHelper.GetAsPropertyAccessors((IEnumerable<IECProperty>)ecClass.GetEnumerator());
                                IDgnECInstance widgetInstance;
                                
                                DgnECManager dgnECManager = DgnECManager.Manager;
                                ChildElementCollection subElements = (el as CellHeaderElement).GetChildren();
                                foreach (Element subElement in subElements)
                                {
                                    DgnECInstanceEnabler widgetEnabler = dgnECManager.ObtainInstanceEnabler(Session.Instance.GetActiveDgnFile(), ecClass);
                                    ECDInstance widgetWipInstance = widgetEnabler.SharedWipInstance;
                                    widgetInstance = widgetEnabler.CreateInstanceOnElement(subElement, widgetWipInstance, false);
    
                                    ECInstanceHelper.CopyInstanceData(ecInstance, widgetInstance, properties);
                                }
                            }
                        }
                    }

  • Hi John,

    but its only for the current session of microstation. once i close and reopen the sub elements no longer have the item attached. 

    I am not sure. You can try to rewrite the instance, and when it does not help, it can be caused by API itself.

    Or, of course, it can be cause by the model itself, but I do not expect the problem is here. Is it possible to share an example, just with a few cells (with EC data attached)?

    with getting the IEnumerable<string> propertyAccessors.

    I do not understand why you use this method.

    CopyInstance takes one EC instance and copy all data to another EC instance of the same EC class. I do not see any reason to use accessors and other features.

    but im doing something wrong because it just crashes microstation.

    I would write the code in a different way. I do not know why you do not enumerate cells in normal way. To use EC approach does not bring any advantage in my opinion in the discussed situation. It would probably lead to different code.

    With regards,

      Jan

  • looks like widgetInstance.WrtieChanges() was needed to get it to stay.

    also i see not i was using the wrong method, i thought i needed to use CopyInstanceData which required the property accessors, but i now see there is a CopyValues methods that i should have used. after switching to that method i get the property values copied.

    I do not know why you do not enumerate cells in normal way.

    what is the normal way? the cells do not have a cell name, so i loop the classes to figure out if its a cell that i need to copy the items down to the sub-elements or not.

    here is my code...

    using (DgnECInstanceCollection dgnECInstances = DgnECManager.Manager.GetElementProperties(el, ECQueryProcessFlags.SearchAllClasses))
                    {
                        foreach (IDgnECInstance ecInstance in dgnECInstances)
                        {
                            if (ecInstance.ClassDefinition.Name == "OhioRailLinesSelect")
                            {
                                IECClass ecClass = ecInstance.ClassDefinition;
                                //this line is crashing MicroStation...
                                //IEnumerable<string> properties = ECInstanceHelper.GetAsPropertyAccessors((IEnumerable<IECProperty>)ecClass.GetEnumerator());
                                IDgnECInstance widgetInstance;
                                
                                DgnECManager dgnECManager = DgnECManager.Manager;
                                ChildElementCollection subElements = (el as CellHeaderElement).GetChildren();
                                foreach (Element subElement in subElements)
                                {
                                    DgnECInstanceEnabler widgetEnabler = dgnECManager.ObtainInstanceEnabler(Session.Instance.GetActiveDgnFile(), ecClass);
                                    ECDInstance widgetWipInstance = widgetEnabler.SharedWipInstance;
                                    widgetInstance = widgetEnabler.CreateInstanceOnElement(subElement, widgetWipInstance, false);
                                    ECInstanceHelper.CopyValues(ecInstance, widgetInstance);
                                    widgetInstance.WriteChanges();
                                    
                                }
                                //drop cell
                                Bentley.Interop.MicroStationDGN.Application MSApp = new Bentley.Interop.MicroStationDGN.ApplicationClass();
                                MSApp.CadInputQueue.SendKeyin("select byelemid" + el.ElementId + "; xy=0,0; Select None");
                            }
                        }
                    }

  • what is the normal way?

    For me the normal way is iterate model content , filtering cells, not using EC transformation. I assume it is faster, but I did not do any benchmarks to compare what is better.

    And when I would decide to use EC approach only, I think about writing ECquery in more complex way to decrease number of necessary checks later.

    Regards,

      Jan

  • in .net i have looked at scanning and enumeration but i dont see much filtering options like i had in vba. right now my code is in the scan delegate. and i check if the element is a cell first. So i am iterating the model elements. after i get the cell, thats when i then get the ec data to add it to the subelements.

    I guess i could switch to a EC query instead. 

  • like i had in vba.

    To think in terms of VBA and used object model is wrong generally in NET context. NET API is structured differently, in more OOP way.

    right now my code is in the scan delegate

    Using scanning delegate is slow way, simple enumeration is better (with an exception of scanning based on element range).

    I guess i could switch to a EC query instead. 

    I am not quite sure what is better (which for me is at first clear and robust code, at second performance), and in my experience it is hard to decide without writing and playing with code a bit.

    Of course, also depends on context and DGN data structure (you have not shared anything yet).

    Regards,

      Jan

  • Thanks Jan,

    this is for a process thats only gonna be run once a year or so by just me to clean up a file after we update it with updated data from the GIS side. 

    ill move my stuff over to enumeration, if i have time i might go back and switch it over to an ec query, im sure that will be faster with the huge amount of elements in this dgn file.

    i didnt share the dgn file because the code is working and i shared that. didnt want to take up more of your time. if you think i should post a slimmed down copy of the dgn file i will.

    as always i really do appreciate all the help you provide.