MstnPlatformNet |
This article is for C# developers who want to write an AddIn for MicroStation CONNECT. It is an introduction to the coding required to harvest Item Type instance data from a DGN model.
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.
Item Types arrived with MicroStation CONNECT. They enable you to define a library of schemas. Each schema defines an Item Type and its properties. It's analogous to a table in a relational database. Read more about Item Types in MicroStation Help.
Once you defined an Item Type you can attach it to a DGN element, model or file. Once attached, it becomes an instance where you assign values to each property of the Item Type. Use MicroStation tools to examine the properties of an Item Type instance attached to a DGN element.
Typically, you will assign instances of an Item Type to multiple DGN elements. Perhaps you will want to harvest data about those instances for whatever purpose. One example is to create a Report. Alternatively, you might want to perform some task in MicroStation using those data or use the harvested data to write, say, an HTML or XML file.
This article is for MicroStation developers, and assumes that you want to harvest Item Type instance data programmatically. It's a guide, and the accompanying Visual Studio project is intended to help you get started with Item Types rather than to provide a useful tool.
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 following namespaces …
Bentley.MstnPlatformNET
Bentley.DgnPlatformNET
Bentley.DgnPlatformNET.Elements
Bentley.DgnPlatformNET.DgnEC
Bentley.EC.Persistence.Query
You'll find the DLLs associated with those namespaces in the ..\MicroStation\assemblies
folder.
The Item Instance Collector is a Visual Studio 2015 project (you can also use Visual Studio 2017 to open it). The project builds into a modest MicroStation AddIn (DLL). It provides a command table for the AddIn, and shows how to …
ECSchema
object for your Item Type
Use MicroStation key-in command ECX LIST
to see a list of EC Schemas, including Item Type schemas,
in MicroStation's Message Center.
In order to find instances of your Item Type programmatically you need a schema object. To get a schema object, you need to ask the EC manager for a schema by name.
What is the name of your Item Type schema?
Here you will encounter a hurdle created by Bentley Systems: your Item Type schema name is not enough!
You must prefix the name with DgnCustomItemTypes_
.
For example, the schema name of the
AreaAnnotator
application is AreaAnnotator_1_0
, but for the EC manager to find it
I must change it to DgnCustomItemTypes_AreaAnnotator_1_0
.
Here's a function that does that for you …
public static string ComposeItemTypeSchemaName(string name) { StringBuilder s = new StringBuilder(); s.AppendFormat("DgnCustomItemTypes_{0}", name); return s.ToString(); }
Using that decorated schema name, you can ask the EC manager to find your schema …
static public IECSchema GetSchema(string schemaName) { DgnFile file = Session.Instance.GetActiveDgnFile(); bool IncludeAttachments = true; FindInstancesScope scope = FindInstancesScope.CreateScope(file, new FindInstancesScopeOption (DgnECHostType.All, !IncludeAttachments)); String internalSchemaName = ComposeItemTypeSchemaName (schemaName); IECSchema schema = DgnECManager.Manager.LocateSchemaInScope(scope, internalSchemaName, 1, 0, SchemaMatchType.Latest); return schema; }
The EC manager finds instances by executing a query . A query requires a scope, which informs the EC manager where to search. In this example the scope of the query is DgnECHostType.Element, and we may choose to search only the active DGN model, or that model plus its attachments. …
DgnFile file = Session.Instance.GetActiveDgnFile(); bool IncludeAttachments = true; FindInstancesScope scope = FindInstancesScope.CreateScope(file, new FindInstancesScopeOption(DgnECHostType.Element, !IncludeAttachments));
The query wants a list of one or more EC classes, which we find using function GetSearchClasses(schemaName)
…
public static IECClass[] GetSearchClasses (string schemaName) { List<IECClass> classes = new List<IECClass> (); IECSchema schema = GetItemTypeSchema(schemaName); if (null == schema) return classes.ToArray (); foreach (IECClass ecClass in schema.GetClasses()) { classes.Add(ecClass); } int nClasses = schema.ClassCount; return classes.ToArray(); }
With a list of EC classes, we can ask the DgnECManager to query a scope to find DGN elements
tagged with Item instances belonging to that class.
To find DGN elements, the scope we want is DgnECHostType.Element
.
The result of the query is an DgnECInstanceCollection
, which implements
IEnumerable<IDgnECInstance>
.
We could return just that IEnumerable
, but I've chosen to convert it to
IQueryable<IDgnECInstance>
because that gives us greater flexibility
subsequently …
public static IQueryable<IDgnECInstance> GetInstances(IECClass [] classes, string schemaName, bool includeReferences) { ECQuery query = new ECQuery(classes); query.SelectClause.SelectAllProperties = true; DgnECManager manager = DgnECManager.Manager; DgnFile file = Session.Instance.GetActiveDgnFile(); FindInstancesScope scope = FindInstancesScope.CreateScope(file, new FindInstancesScopeOption(DgnECHostType.Element, includeReferences)); DgnECInstanceCollection instances = manager.FindInstances(scope, query); return instances.AsQueryable(); }
Returning a IQueryable<IDgnECInstance>
lets you enumerate the results directly or
compose a
LINQ
query.
MicroStation developer
John Drsek
asked: It seems like if your item type instance is on an element thats inside a cell it isn't returning that in the query.
Any way to get this query to return all instances?
Jan Šlegr responded with this suggestion: I guess to set
FindInstancesScopeOption.SearchPublicChildren
property.
In the context of the example above, that would be something like …
FindInstancesScope scope = FindInstancesScope.CreateScope(file, new FindInstancesScopeOption(DgnECHostType.Element, includeReferences)); scope.SearchPublicChildren = true; DgnECInstanceCollection instances = manager.FindInstances(scope, query);
Here's the simplest way to examine the list of IDgnECInstance
returned by
DgnECManager.FindInstances
…
foreach (IDgnECInstance instance in instances)
{
... do something with instance
}
The IQueryable<IDgnECInstance>
lets you compose a more complex query using
LINQ.
An instance has a number of properties.
You can obtain a property reference using an indexer (instance ["prop_name"]
)
but that requires you to know the name (also known as an access string) of each property.
More generally, you want to enumerate those instances.
An IECInstance
is an IEnumerable<IECPropertyValue>
,
which makes it simple to enumerate …
foreach (IDgnECInstance instance in instances) { s.Clear(); s.AppendFormat("Instance [{0}]", ++i); MessageCenter.Instance.ShowMessage(MessageType.Debug, s.ToString(), s.ToString(), MessageAlert.None); int j = 0; foreach (IECPropertyValue value in instance) { s.Clear(); s.AppendFormat("Property [{0}] name '{1}' value={2}", ++j, value.Property.Name, value.StringValue); MessageCenter.Instance.ShowMessage(MessageType.Debug, s.ToString(), s.ToString(), MessageAlert.None); } }
Often you will need to refer to the DGN element to which the Item instance is attached. It's the simplest code in this example …
Element element = instance.Element;
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 | |
---|---|---|---|
ITEMTYPES | HARVEST | Library Name | Harvest Item Type instances |
ITEMTYPES | LIBRARIES | List Item Type libraries |
Don't forget MicroStation commands starting with ECX
.
These provide information about EC schemas.
For example, ECX SCHEMA LIST
writes a list of EC schema names to the Message Center.
After keying-in one of the above commands, 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 instance data discovered.
My thanks go to Jan Šlegr, a frequent contributor to the MicroStation Programming Forum, and Paul Connelly, a Bentley Systems developer. They both offer indispensible nuggets of advice in response to questions posted to the MicroStation Programming Forum. They helped to demystify the MstnPlatformNET API and provided hints that enabled me to develop the Item Instance Collector and write this article.
You can download the Item Instance Collector Visual Studio project. The project was built using Visual Studio 2015 and .NET Framework 4.6.1 as required by MicroStation CONNECT after Update 5.
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 ItemInstanceCollector.DLL
in your ..\MicroStation\mdlapps
folder.
Start MicroStation and open the key-in window (from the Utilities ribbon group).
Key-in
mdl load ItemInstanceCollector
You should see a message confirming that the application is loaded.
Post questions about MicroStation programming to the MicroStation Programming Forum.