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
Hi John,
John Drsek said: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" ;-)
John Drsek said: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:
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).
John Drsek said: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.
John Drsek said: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.
John Drsek said: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
Bentley Accredited Developer: iTwin Platform - AssociateLabyrinth Technology | dev.notes() | cad.point
Answer Verified By: John Drsek
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); } } } }
John Drsek said: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)?
John Drsek said: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.
John Drsek said: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,
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.
Jan Šlegr said: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"); } } }
John Drsek said: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.
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.
John Drsek said: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.
John Drsek said: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).
John Drsek said: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).
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.