DgnPlatformNet |
This article is for C# developers who want to write an AddIn for MicroStation CONNECT. It is an introduction to the coding required to acquire tag elements in a DGN model by scanning. We show two approaches that obtain similar results …
TagElement
s
TagElement
s that have an association relationship with their host element
This is a complete, working example with C# source code. You can download the Visual Studio project.
If you want to ask questions about C# development for MicroStation CONNECT, post your question to the MicroStation Programming Forum.
A DGN model is a container. It contains graphic elements, such as lines, arcs and shapes. If you want your code to do anything with MicroStation elements, you must understand ways to obtain those elements.
If you want to read an introduction to harvesting elements from a DGN model, take a look at our previous articles about element enumeration and scanning using the DgnPlatformNet API …
This article offers a more advanced example of scanning.
In this example, we want to find elements (termed 'host elements' here) annotated with MicroStation TagElement
s.
When we find those host elements we present a list in a Windows Form that is part of the example application.
The project's Scanner
class implements a traditional idiom to obtain host elements.
We scan a DGN model for certain element types (MSElementType.Tag
), and for each TagElement
find
its host element.
The host element is stored in a dictionary keyed by its ElementId
.
That way, we don't store any duplicates.
The purpose of this approach is to show how we can use ECSchema relationships.
A TagElement
has an association relationship with its host.
We exploit classes that support ECSchemas DgnElementSchema
and DgnContentRelationshipSchema
.
Both schemas are delivered with MicroStation.
In this example, the scanner is instructed to obtain any graphical element that isn't a MSElementType.Tag
.
For each candidate element found by the scanner, we check to see if a TagElement
is associated with it.
If we find that association, we add the host to our list of found elements.
Here's the code that set up the relationship test for each candidate element. It may not be clear what all this means — the DgnPlatformNet documentation could be more helpful …
// Add Visual Studio project references to these assemblies using Bentley.DgnPlatformNET.DgnEC; using Bentley.DgnPlatformNET.Elements; using Bentley.DgnPlatformNET; using Bentley.MstnPlatformNET; using ECI = Bentley.ECObjects.Instance; using ECS = Bentley.ECObjects.Schema; // Bentley.ECObjects3.dll using ECQ = Bentley.EC.Persistence.Query; // Bentley.EC.Persistence3.dll
// Set the EC scope to find graphic elements
FindInstancesScopeOption opts = new FindInstancesScopeOption(DgnECHostType.Element);
opts.ExposesHidden = true;
FindInstancesScope.CreateScope(host, opts);
// Read the ECSchemas delivered with MicroStation
var file = session.GetActiveDgnFile();
var mgr = DgnECManager.Manager;
var elemSchema = mgr.LocateDeliveredSchema("DgnElementSchema", 1, 0, ECS.SchemaMatchType.LatestCompatible, file);
var relSchema = mgr.LocateDeliveredSchema("DgnContentRelationshipSchema", 1, 0, ECS.SchemaMatchType.LatestCompatible, file);
// Create an ECQuery for graphical DGN elements
var query = new ECQ.ECQuery(new ECQ.SearchClass(elemSchema["GraphicalElement"], true));
// Create a ECRelationship for an element associated with a TagElement
var relSpec = new ECQ.QueryRelatedClassSpecifier(relSchema["AssociativeElementRelationship"]
as ECS.IECRelationshipClass,
true,
ECI.RelatedInstanceDirection.Backward, elemSchema["TagElement"], true);
// Add the ECRelationship clause to the ECQuery
query.SelectClause.SelectedRelatedInstances.Add(new ECQ.RelatedInstanceSelectCriteria(relSpec, true));
// Invoke the query to find EC instances on the host DGN element using (DgnECInstanceCollection instances = mgr.FindInstances(FindInstancesScope.CreateScope(host, opts), query)) { ... do something with DgnECInstanceCollection }
// Evaluate each EC instance
foreach (var instance in instances)
{
DgnECRelationshipCollection ecRelationshipInstanceCollection =
(DgnECRelationshipCollection)instance.GetRelationshipInstances();
foreach (var relationship in ecRelationshipInstanceCollection)
{
var tagInstance = relationship.Source as IDgnECInstance;
TagElement tag = (TagElement)tagInstance.Element;
if (0 == String.Compare(setName, tag.TagSetName, true))
{
StringBuilder s = new StringBuilder();
s.AppendFormat("Tag Element: {0} '{1}' '{2}'", tag.ElementId, tag.TagName, tag.GetTagValue().ToString());
TagScanner.ShowMessage(s);
++nTags;
}
}
}
The dialog shown above has an option button that displays a list of tag sets defined in the active DGN model. That button shows tag set example …
The screenshot above shows the result of scanning for elements that host tag set example. The ListView control shows a list of element IDs (the ID of each host) and the host's element type. The technique for acquiring that list is described above.
We use the Dictionary
populated by the scanner as the data source for the ListView control
The dialog has two controls that provide feedback to the user …
ListView
control,
the corresponding element in the DGN model is highlighted.
Read this article about element
highlighting to see how that's done.
ListView
control.
Read this article about
focussing on an element.
There are classes that implement these techniques in the downloadable project.
MicroStation .NET code lives in the Bentley
namespace, or a namespace within the scope of Bentley
.
In this example we're using classes and methods in the
Bentley.DgnPlatformNET
and Bentley.DgnPlatformNET.Elements
namespaces.
Put the following using
statements in any C# code module that uses a class in those namespaces …
using Bentley.DgnPlatformNET; using Bentley.DgnPlatformNET.Elements;
You can read more about the mechanics of scanning a model elsewhere …
Overview of scanning | Model Scanning |
Setting your scan criteria | Scan Criteria |
Writing a scan delegate (callback function) | Scan Delegate Method |
Element Type Test | Setting the type test bit-mask |
In the legacy scanning example, we're looking specifically for tag elements. We set the scan criteria like this …
ScanCriteria criteria = new ScanCriteria();
criteria.SetDrawnElements();
criteria.SetModelRef(model_);
// We're interested only in tag elements
MSElementType[] types = new MSElementType[1];
types[0] = MSElementType.Tag;
criteria.AddElementTypes(types);
For each TagElement
that our scan discovers, we want its parent or host element.
From a user perspective, that's the element to which the tag is attached.
We're interested in only those tags that belong to a named tag set.
In our scan delegate function, we need to perform these tasks …
Dictionary
of elements.
The key used in the Dictionary
is the unique Element ID
The Dictionary
is a list of Element
s keyed by element ID …
Dictionary <ElementId, Element> hosts_;
Here's the code in the scan delegate that implements those requirements …
if (MSElementType.Tag == el.ElementType) { ++nTags_; TagElement tag = (TagElement)el; if (0 == string.Compare(tag.TagSetName, tagSetName_, true)) { Element host = tag.GetTargetElement(); if (!hosts_.ContainsKey(host.ElementId)) hosts_.Add(host.ElementId,host); } }
The result of the tag scan is a Dictionary
of host elements (not tag elements),
keyed by the host's ID.
That list is added to the dialog's ListView control …
This MicroStation AddIn has a small command table, in file Commands.xml
.
The command handlers are in class KeyinCommands
.
You can key-in the commands below in MicroStation's key-in dialog.
Commands are not case-sensitive …
Command | Option | Comment | |
---|---|---|---|
TAGSCANNER | SCAN | Scan for TagElement s | |
TAGSCANNER | ECSCAN | Scan for anything but a TagElement , then find the associated TagElement |
After keying-in the above command, observe MicroStation's Message Center. Make sure that the debug option is enabled (right-click in the Message Center to see its options). You will see a list of the element IDs and types discovered. That list is presented in the Tag Scanner dialog above.
You can download the Tag Scanner Project Visual Studio project. The project was built using Visual Studio 2013 and .NET Framework 4.5 as required by MicroStation CONNECT prior to Update 5. It should work with MicroStation CONNECT Update 5 and later but has not been tested.
The project is complete: it includes all source code, the command table XML file,
the Visual Studio solution file and is set up to build a DLL.
The DLL is placed in your ..\MicroStation\mdlapps
folder.
It's similar, in that respect, to the .NET examples delivered with the MicroStation CONNECT SDK.
Build the project, which will place file TagScanner.DLL
in your ..\MicroStation\mdlapps
folder.
Start MicroStation and open the key-in window (from the Utilities ribbon group).
Key-in
mdl load TagScanner
You should see a message confirming that the application is loaded.
The Tag Scanner dialog will pop.
Post questions about MicroStation programming to the MicroStation Programming Forum.