[C# Connect] Retrieving Element Tags

Is there a better way of retrieving a Tag Element that belongs to a specific element other than iterating all of the elements of a model looking for a matching Target Element?   I suppose a little better if doing multiple queries at once would be to stick it in a dictionary.. but in the VBA api, you could just use the .GetTags() method of an element.

  • Your question is not entirely clear, but you are right — I see no equivalent to Element::GetTags() in the DgnPlatformNet API.  There are plenty of other functions concerning tags, but how do we get tags attached to an element?

     
    Regards, Jon Summers
    LA Solutions

  • My question is if we must implement our own Element::GetTags(), and if so, is the best way of doing that by iterating all of the elements in the model and looking for elements with type "Tag".... Then we can do multiple queries on the dictionary for the ElementID we need.

    Example:

    public static Dictionary<ElementId, List<TagElement>> GetTags()
            {
                Dictionary<ElementId, List<TagElement>> results = new Dictionary<ElementId, List<TagElement>>();
                DgnModel activeModel = GetActiveModel();
                ModelElementsCollection elementsCollection = activeModel.GetGraphicElements();
    
                foreach (Element element in elementsCollection)
                {
                    if (element.ElementType != MSElementType.Tag)
                        continue;
                    TagElement tagElement = (TagElement)element;
                    ElementId targetId = tagElement.GetTargetElement().ElementId;
    
                    List<TagElement> tags;
                    if(!results.TryGetValue(targetId, out tags))
                        tags = new List<TagElement>();
    
                    tags.Add(tagElement);
                    results[targetId] = tags;
                }
    
                return results;
            } 


    The problem with my example is that I would need to iterate all of the objects in the model any time I need to refresh this. For very large models, this may be problematic.
  • Hi Maury.

    The C# API does not provide a straightforward way to do this. Even in native code it would not be very straightforward.

    A roundabout way would be to use the DgnECManager API.

    1. Obtain a DgnECInstance for your element
    2. Construct an ECQuery to find related instances using ECRelationship DgnContentRelationshipSchema:AssociativeElementRelationship and target ECClass DgnElementSchema:TagElement
    3. Iterate the resulting ECInstances and pull out their host Elements.

    Note that your example code above will throw an exception if it encounters any non-associative tags (tags with no target element).

    HTH,
    Paul
  • Hi Paul,

    Your 1,2,3 made it sound so easy. Unfortunately this EC framework is the most confusing thing I have ever seen!
    I got as far as

                DgnECManager manager = DgnECManager.Manager;
                var hostType = DgnECHostType.All & ~DgnECHostType.File;
                FindInstancesScope scope = FindInstancesScope.CreateScope(ele, new FindInstancesScopeOption(hostType, false));
    
                IECSchema dgnElementSchema = manager.LocateSchema("DgnElementSchema", 1, 0, SchemaMatchType.LatestCompatible, null, Ms.GetActiveDgnFile());
                IECClass tagClass = dgnElementSchema.GetClass("TagElement");
    
                IECSchema dgnContentRelationshipSchema = manager.LocateSchema("DgnContentRelationshipSchema", 1, 0, SchemaMatchType.LatestCompatible, null, Ms.GetActiveDgnFile());
                IECRelationshipClass relationship = (IECRelationshipClass)dgnContentRelationshipSchema.GetClass("AssociativeElementRelationship");
                QueryRelatedClassSpecifier relatedClassSpecifier = new QueryRelatedClassSpecifier(relationship, RelatedInstanceDirection.Forward, tagClass);
                
                
                ECQuery query = new ECQuery();
                query.AddSearchClass(tagClass);
                //query.AddSearchClass(dgnContentRelationshipSchema.GetClass("AssociativeElementRelationship"));
                query.SelectClause.SelectedRelatedInstances.Add(new RelatedInstanceSelectCriteria(relatedClassSpecifier, false));
    
                using (DgnECInstanceCollection coll = manager.FindInstances(scope, query))
                {
                    foreach (IDgnECInstance instance in coll)
                    {
                        Debug.Print("Test");
                    }
                }

    and am now completely stuck.


    Is there any chance that you could post a simple example for extracting the tags? The examples provided with the SDK do not seem to be very helpful for this case.

  • try something like:

    using Bentley.DgnPlatformNET;
    using Bentley.DgnPlatformNET.Elements;
    using Bentley.DgnPlatformNET.DgnEC;
    using ECQ = Bentley.EC.Persistence.Query;
    using ECS = Bentley.ECObjects.Schema;
    using ECI = Bentley.ECObjects.Instance;
    
    void FindTags(Element el)
    {
        var mgr = DgnECManager.Manager;
    
        var file = el.DgnModel.GetDgnFile();
        var scope = FindInstancesScope.CreateScope(el, new FindInstancesScopeOption(DgnECHostType.Element));
    
        var elemSchema = mgr.LocateDeliveredSchema("DgnElementSchema", 1, 0, ECS.SchemaMatchType.LatestCompatible, file);
        var relSchema = mgr.LocateDeliveredSchema("DgnContentRelationshipSchema", 1, 0, ECS.SchemaMatchType.LatestCompatible, file);
    
        var query = new ECQ.ECQuery(new ECQ.SearchClass (elemSchema["GraphicalElement"], true));
        var relSpec = new ECQ.QueryRelatedClassSpecifier(relSchema["AssociativeElementRelationship"] as ECS.IECRelationshipClass, true, ECI.RelatedInstanceDirection.Backward, elemSchema["TagElement"], true);
        query.SelectClause.SelectedRelatedInstances.Add(new ECQ.RelatedInstanceSelectCriteria(relSpec, true));
    
        foreach (var instance in mgr.FindInstances(scope, query))
            {
            foreach (var relationship in instance.GetRelationshipInstances())
                {
                var tagInstance = relationship.Source as IDgnECInstance;
                System.Console.WriteLine("Tag Element: {0}", tagInstance.Element.ElementId);
                }
            }
    }
    
  • Hi Paul,
    Thanks again for the post, unfortunately, it seems to go fine until instance.GetRelationshipInstances(). It is returning empty.
  • public static void GetTags(this Element el)
            {
                var mgr = DgnECManager.Manager;
    
                var file = Ms.GetActiveDgnFile();
                var scope = FindInstancesScope.CreateScope(el, new FindInstancesScopeOption(DgnECHostType.Element));
    
                var elemSchema = mgr.LocateDeliveredSchema("DgnElementSchema", 1, 0, ECS.SchemaMatchType.LatestCompatible, file);
                var relSchema = mgr.LocateDeliveredSchema("DgnContentRelationshipSchema", 1, 0, ECS.SchemaMatchType.LatestCompatible, file);
    
                var query = new ECQ.ECQuery(new ECQ.SearchClass(elemSchema["GraphicalElement"], true));
                var relSpec = new ECQ.QueryRelatedClassSpecifier(relSchema["AssociativeElementRelationship"] as ECS.IECRelationshipClass, true, ECI.RelatedInstanceDirection.Backward, elemSchema["TagElement"], true);
                query.SelectClause.SelectedRelatedInstances.Add(new ECQ.RelatedInstanceSelectCriteria(relSpec, true));
    
                using (DgnECInstanceCollection coll = mgr.FindInstances(scope, query))
                {
                    foreach (var instance in coll)
                    {
                        IECRelationshipInstanceCollection ecRelationshipInstanceCollection = instance.GetRelationshipInstances();
                        foreach (var relationship in ecRelationshipInstanceCollection)
                        {
                            var tagInstance = relationship.Source as IDgnECInstance;
                            System.Console.WriteLine("Tag Element: {0}", tagInstance.Element.ElementId);
                        }
                    }
                }
            }

                List<Element> selectedElements = Ms.GetSelectedElements();
                foreach (Element selectedElement in selectedElements)
                {
                    selectedElement.GetTags();
                }
    
    
            public static List<Element> GetSelectedElements()
            {
                List<Element> results = new List<Element>();
                ElementAgenda agenda = new ElementAgenda();
                SelectionSetManager.BuildAgenda(ref agenda);
                //agenda.DropInvalidEntries();
    
                uint eleCount = agenda.GetCount();
                for (uint i = 0; i < eleCount; i++)
                {
                    results.Add(agenda.GetEntry(i));
                }
    
                return results;
            }
    

    testx64.dgn

  • I don't see any tag elements in your file...

    Try this one?

    FindTags.dgn