[Connect C++] How to read custom properties (no standard properties) on elements

Hi Experts, I want to know if there is a direct way to get MicroStation element custom properties. For example, Below first image is full properties of one element:

Then all custom properties which I want to read (no standard categories):

Right now I am able to use EC Property iterate full properties from one given Element, however the results are mixed of standard and custom properties. One of the possible way I think is to perform a further filter to ignore standard properties by checking every property's category information, will that work? Is it possible custom properties having standard category also?

On the other side, I notice there is an 'Item' associated with the element, and inside of the item it contains many custom properties, will it be enough to read the 'Item" object of every element to get all custom properties? And if so can you kindly advice which parts of API I should use to read this type objects?

Thanks a lot,

Danny

Parents
  • Hi Danny,

    your terminology is confusing for me a bit and not in parallel with MicroStation or MicroStation API terminology.

    To make it clearer, can you confirm what element data you are interested in (not using "standard" and "custom" words that can have different meaning for every user)?

    In my opinion, MicroStation element can have (or always have in some cases):

    • Element attributes: Mandatory settings like level, color, line style etc. They are all mandatory (every graphical element has them), so they can be names as "standard element properties".
    • User data: Old style of binary data attached directly to element. Use both by MicroStation (mslink, SmartSolid structure data...) and applications. Has to be accessed by special tools, otherwise they are just binary blobs.
    • XAttributes: Custom data stored on element. A recommended way how data should be stored, used now widely including EC data.
    • EC properties: Technically XAttributes, but defined using EC Schemas and accessed by EC API. Displayed in Element properties dialog, but not in Items list.
    • Item Types: Based on EC technology, but implemented specifically as simple user tool. Internally it's special EC Schema created not using API or Class Editor, but through user interface.

    The situation is a bit more complicated, because I think (but have not tested it and it's my assumption only) applications can dynamically extend element properties in such way, that data stored in custom format (user data, XAttributes) is displayed in Element properties dialog together with EC data.

    So are you intested in general EC data or Item types?

    With regards,

      Jan

  • Hi Jan,

    Thanks for the awesome clarification.

    My initial request is try ignore properties from these categories: "General"/"Extended"/"Raw Data"/"Geometry"/"Material". The reason is those attributes are mandatory as you mentioned and not including any user defined properties (which is my guess so I asked if user are able to create any properties under those categories). Basing on your groups they should belong to the Element attributes I think. Is it possible to filter it out?

    Thanks,
    Danny

  • user data, XAttributes, XMLFragments

    Such data are useless when you are not author of them and they should always be accessed by originall application only. When you are not author, user data is just binary blob and XAttributes and XML Fragments are well formated, but content is unknown.

    Regards,

      Jan

  • So I am interested in all EC data

    Maybe you should better explain what is your main target. Typically developers access standard element properties only through standard API (to change level, get geometry data, attach material...) and store custom data using selected technology (XAttrbiutes are recommended, but more complex EC Schema can make sense in many scenarios). Rarely anybody need to access everything.

    Regards,

      Jan

  • ... but maybe they are accessible through EC API

    Yes it is. The EC api returns not only EC data(Item types, general EC data) but also mandatory Element Attributes. I don't know if there is a way to access only Item type or general EC data, just because the API I used returned me everything. 

  • Maybe you should better explain what is you main target

    Yes. I am working on property extraction for data translation purpose. "Standard element properties"  in most case don't include custom data so it's less interested from property translation perspective (we already translated geometry data and it's attributes like color, level, material in other manners).   on the other side, these standard element properties amount is huge if the design including a lot of geometries, which is a burden for property translation. 

    huge and meaningless let us want to filter/ignore them in my work. hopefully my explanation helps clarify a little bit. 

    Thanks,

    Danny

  • if there is a way to access only Item type or general EC data

    I recommend to search this (and BDN) community. How to access Item Types data and general EC data defined by EC Schema has been discussed several times.

    E.g. in this discussion Paul mentioned that to access only Item Types data, Item Types API is recommended to use.

    When using general API / approach, when everything is returned, to evaluate Schema name can be the way how to filter the source of data.

    Regards,

      Jan

  • When using general API / approach, when everything is returned, to evaluate Schema name can be the way how to filter the source of data.

    Thanks a lot.  I will do a search to see what's the relationship between schema name and the source of data. Appreciate for your promptly response!

    Regards,

    Danny

  • Hi Jan,

    I tried export one model's schema and got following schemas, from the name I can't see it's source, do you have suggestions?

    Thanks,

    Danny

  • I did not think to do it this way, but to use API to check from what source (EC schema) a particular property come from.

    As Paul wrote in the mentioned discussion, e.g. when the schema is DgnCustomItemTypes_, EC property comes from Item Types definition. I don't know what Schema is set for standard or extended element properties like level or attached material.

    With regards,

      Jan

  • do you have suggestions?

    Here's some code to get EC Schemas...

    #include <EcHeaders.h>
    
    USING_NAMESPACE_BENTLEY_DGNPLATFORM;
    USING_NAMESPACE_BENTLEY_ECOBJECT;
    
    WCharCP	SchemaFactory::BaseElementSchemaName		= 
    L"BaseElementSchema"; WCharCP SchemaFactory::DgnElementSchemaName =
    L"DgnElementSchema"; WCharCP SchemaFactory::UnitsSchemaName =
    L"Units_Schema"; WCharCP SchemaFactory::MstnPropertyFormatterSchemaName =
    L"MstnPropertyFormatter"; /////////////////////////////////////////////////////////////////////// // static bool SchemaFactory::GetNamedSchema (ECN::ECSchemaPtr& pSchema,
    WCharCP name) { DgnFileP pDgnFile =
    ISessionMgr::GetActiveDgnFile (); DgnPlatform::SchemaInfo schemaInfo (ECN::SchemaKey (name, 1, 0),
    *pDgnFile); DgnECManagerR ecMan = DgnPlatform::DgnECManager::GetManager (); pSchema = ecMan.LocateSchemaInDgnFile (schemaInfo, ECN::SchemaMatchType::SCHEMAMATCHTYPE_LatestCompatible); return pSchema.IsValid (); } /////////////////////////////////////////////////////////////////////// // static bool SchemaFactory::GetMstnPropertyFormatterSchema (ECSchemaPtr& pSchema) { return GetNamedSchema (pSchema, MstnPropertyFormatterSchemaName); } /////////////////////////////////////////////////////////////////////// // static bool SchemaFactory::GetBaseElementSchema (ECSchemaPtr& pSchema) { return GetNamedSchema (pSchema, BaseElementSchemaName); } /////////////////////////////////////////////////////////////////////// // static bool SchemaFactory::GetUnitsSchema (ECSchemaPtr& pSchema) { return GetNamedSchema (pSchema, UnitsSchemaName); } /////////////////////////////////////////////////////////////////////// // static DgnECManagerR SchemaFactory::GetDgnEcManager () { return Bentley::DgnPlatform::DgnECManager::GetManager(); } /////////////////////////////////////////////////////////////////////// // static ECN::ECClassCR SchemaFactory::GetEcClass (ECSchemaPtr& pSchema, WCharCP elementClassname) { if (!pSchema.IsValid ()) { CMessageTracer msg ("SchemaFactory::GetEcClass "); msg.IsValid (L"pSchema", pSchema.IsValid ()); msg.Advisory (); } return *pSchema->GetClassCP (elementClassname); }

    Here's a suggestion about how you might use them...

    ECN::ECSchemaPtr  pSchema;
    if (SchemaFactory::GetBaseElementSchema (pSchema))
    {
      FindInstancesScopeOption option  (DgnECHostType::Element);
      FindInstancesScopePtr scope   = FindInstancesScope::CreateScope (elementHandle, option);
      DgnECManagerR         manager = Bentley::DgnPlatform::DgnECManager::GetManager();
      const bool&           Polymorphic { true };
      DgnElementECInstancePtr instance = manager.FindInstanceOnElement  (elementHandle,
    				SchemaFactory::GetEcClass (pSchema, className), Polymorphic);
    }
    

     
    Regards, Jon Summers
    LA Solutions

  • Hi Jon.

    Thanks for the codes. Looks like the code is searching one instance on an element, and the scope is limited in specified schema. 

    I am using similar codes which returns ECInstances for one element,

        DgnECManagerR dgnECManager = DgnECManager::GetManager();
        bool includeReferenceAttachments = true;
        FindInstancesScopeOption scopeOption(DgnECHostType_ElementAndDesignLink, includeReferenceAttachments);
        FindInstancesScopePtr scope = FindInstancesScope::CreateScope(eh, scopeOption);
        ECQueryPtr  findAll = ECQuery::CreateQuery(ECQUERY_PROCESS_SearchAllClasses); // Finds ALL ECInstances, regardless of their ECClass
    
    
        for each (DgnECInstancePtr instance in dgnECManager.FindInstances(*scope, *findAll))
        {
            // The DgnECManager does not find and "load" all of the ECInstances "up front" during the FindInstances call
            // but rather it incrementally scans the files as the for-each loop iterates over the InstancesIterable
            // returned by FindInstances. Thus you can iterate over thousands of them, while only loading one-at-a-time into memory
            // see if the instance is hosted by an element
            DgnElementECInstancePtr spElementECInstance = instance->GetAsElementInstance();
            if (spElementECInstance.IsValid())
            {
                // iterate all properties
            }
        }

    The challenge I met is can't get the Schema name like what you showed in below image,

    My dump codes like this:

            WString schemaName = p->GetClass().GetSchema().GetName();
            WString fullSchemaName = p->GetClass().GetSchema().GetFullSchemaName();
            WString nsprefix = p->GetClass().GetSchema().GetNamespacePrefix();
            WString description = p->GetClass().GetSchema().GetDescription();
            WString displaylable = p->GetClass().GetSchema().GetDisplayLabel();

    And the output of schema name is same as the exported schema file name.

    As a result, I don't know how to recognize the source of the property by getting the schema name. 

    -Danny

Reply
  • Hi Jon.

    Thanks for the codes. Looks like the code is searching one instance on an element, and the scope is limited in specified schema. 

    I am using similar codes which returns ECInstances for one element,

        DgnECManagerR dgnECManager = DgnECManager::GetManager();
        bool includeReferenceAttachments = true;
        FindInstancesScopeOption scopeOption(DgnECHostType_ElementAndDesignLink, includeReferenceAttachments);
        FindInstancesScopePtr scope = FindInstancesScope::CreateScope(eh, scopeOption);
        ECQueryPtr  findAll = ECQuery::CreateQuery(ECQUERY_PROCESS_SearchAllClasses); // Finds ALL ECInstances, regardless of their ECClass
    
    
        for each (DgnECInstancePtr instance in dgnECManager.FindInstances(*scope, *findAll))
        {
            // The DgnECManager does not find and "load" all of the ECInstances "up front" during the FindInstances call
            // but rather it incrementally scans the files as the for-each loop iterates over the InstancesIterable
            // returned by FindInstances. Thus you can iterate over thousands of them, while only loading one-at-a-time into memory
            // see if the instance is hosted by an element
            DgnElementECInstancePtr spElementECInstance = instance->GetAsElementInstance();
            if (spElementECInstance.IsValid())
            {
                // iterate all properties
            }
        }

    The challenge I met is can't get the Schema name like what you showed in below image,

    My dump codes like this:

            WString schemaName = p->GetClass().GetSchema().GetName();
            WString fullSchemaName = p->GetClass().GetSchema().GetFullSchemaName();
            WString nsprefix = p->GetClass().GetSchema().GetNamespacePrefix();
            WString description = p->GetClass().GetSchema().GetDescription();
            WString displaylable = p->GetClass().GetSchema().GetDisplayLabel();

    And the output of schema name is same as the exported schema file name.

    As a result, I don't know how to recognize the source of the property by getting the schema name. 

    -Danny

Children