DgnPlatformNet |
This article is for C# developers who want to write an application for MicroStation CONNECT. It describes a way to use DGNLib data in your own app. This is not a complete application: rather, it describes what might otherwise be a non-intuitive approach to solve a problem.
A MicroStation configuration often stores libraries of data in read-only design libraries, also known as DGNLibs. A set of DGNLibs is usually available as part of a MicroStation workspace. An administrator will often allocate different DGNLibs to store different kinds of data …
Because those data are stored independently of a user's active DGN file, your app may want to copy data from a DGNLib. This example shows how to harvest DGNLib data programmatically for use in your own .NET app.
If you want to ask about development for MicroStation, post your question to the MicroStation Programming Forum.
The Visual Studio project available for download contains three DGNLib Harvester classes: one gets a list of MicroStation Text Styles, another a list of MicroStation Levels, and the third a list of Display Rule Sets. Those concrete classes have a common abstract base class. The DGNLib Harvester is not limited to those classes — but that's all I wanted in a demonstration project.
The DGNLib Harvester is part of the Settings Manager Example. You can see ComboBoxes (Text Styles and Levels) in the screenshot below that are populated by the harvester …
Add the following references to your .cs
file …
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using Bentley.DgnPlatformNET; using Bentley.MstnPlatformNET;
/// Base class for data harvester that gets information from DGNLibs. /// Param name="T": The data type handled by a harvester e.g. DgnTextStyle. abstract public class DgnLibHarvester<T> { /// List of data harvested from active DGN file or DGN Lib. public List<T> _data; /// Internal list of data. protected IEnumerable<T> _rawData; /// Property to get/set the internal list of raw data. protected IEnumerable<T> RawData { get { return _rawData; } set { _rawData = value; } } /// Property to get the type-safe list of data. /// Returns List of type T data (e.g. DgnTextStyle). public List<T> Data { get { return _data; } } /// Returns the count of data. public int Count { get { return null == _data ? 0 : _data.Count(); } } /// Copy data from an IEnumerable of type T to a type safe list of data. /// Returns count of objects in data list after copy. protected int CopyRawData () { foreach (T data in _rawData) { _data.Add(data); } return Count; } /// Inheriting classes must provide the Names property. /// Returns string array of names. public abstract string [] Names { get; } /// Populate a combo box with list of names. /// Param: ComboBox to populate /// Returns: Count of items added to ComboBox public int PopulateComboBox(ComboBox cbo) { int nItems = 0; cbo.Items.Clear(); foreach (string name in Names) { cbo.Items.Add(name); ++nItems; } cbo.SelectedIndex = 0; return nItems; } /// Source flags instruct a harvester to look in the active DGN file, visible DGNLibs, or both. [Flags] public enum Source { None = 0, ActiveDgnFile = 1, DGNLibs = 2, All = ActiveDgnFile | DGNLibs }; }
This class inherits from the above base class and is responsible for harvesting DgnTextStyle
data.
The work of extracting data from DGNLibs is performed by HarvestDgnLibs()
.
/// TextStyleHarvester wraps the APIs that get TextStyles from DGNLibs. public class TextStyleHarvester : DgnLibHarvester<DgnTextStyle> { /// Return the number of text styles found. public int TextStyleCount { get { return Count; } } /// Harvest TextStyles from the active DGN file, all DGNLibs or both. /// It's possible that the active DGN file has no text styles and that visible text styles originate in one or more DGNLibs. /// Param 'source': ActiveDgnFile, DGNLibs or All. /// Returns: count of styles found. public int Harvest (Source source = Source.All) { _data = new List<DgnTextStyle>(); if (source.HasFlag (Source.ActiveDgnFile)) { _rawData = SettingsExample.GetActiveDgnFile().GetTextStyles(); CopyRawData(); foreach (DgnTextStyle style in _data) { MessageCenter.Instance.StatusMessage = $"DgnLib text style: {style.Name}"; } } if (source.HasFlag (Source.DGNLibs)) { HarvestDgnLibs(); } return _data.Count(); } /// Return an array of names of text styles. public override string [] Names { get { string[] names = new string[Count]; int i = 0; foreach (DgnTextStyle style in _data) { names[i] = style.Name; ++i; } return names; } } /// Trace the text styles in the Message Center debug window. public void Trace() { string msg = null; foreach (DgnTextStyle style in _data) { msg = $"Text style: {style.Name}"; MessageCenter.Instance.ShowDebugMessage(msg, msg, false); } } /// Harvest text styles from visible DGNLibs. /// Returns: count of text styles in list. private int HarvestDgnLibs() { DgnLibIterator iterator = new DgnLibIterator(DgnLibSelector.ElementStyles); foreach (DgnFile lib in iterator) { _rawData = lib.GetTextStyles(); CopyRawData(); } return Count; } }
This class inherits from the above base class and is responsible for harvesting DisplayRuleSet
data.
The work of extracting data from DGNLibs is performed by HarvestDgnLibs()
.
However, the DisplayRuleSet
is a
disposable class
(it implements IDisposable
).
Consequently, we have to operate slightly differently to the base class when copying instances of those classes.
/// DisplayRuleHarvester wraps the APIs that get display rules from DGNLibs. public class DisplayRuleHarvester : DgnLibHarvester{ /// DisplayRuleHarvester constructor. public DisplayRuleHarvester() : base(DgnLibSelector.DisplayStylesOnly) { } /// DisplayRuleHarvester destructor is required to dispose its list of DisplayRuleSet. ~DisplayRuleHarvester() { foreach (DisplayRuleSet set in _data) { set.Dispose(); } } /// Return the number of rule sets found. public int RuleCount { get { return Count; } } /// Return an array of names of display rule sets. public override string[] Names { get { string[] names = new string[Count]; int i = 0; foreach (DisplayRuleSet set in _data) { names[i] = set.Name; ++i; } return names; } } /// Harvest display rules from the active DGN file, all DGNLibs or both. /// Param: Source - ActiveDgnFile, DGNLibs or All. /// Count of rules found. public int Harvest(Source source = Source.All) { _data = new List (); if (source.HasFlag (Source.ActiveDgnFile)) { DgnFile dgn = Session.Instance.GetActiveDgnFile(); using (IDisposableEnumerable sets = DisplayRulesManager.GetDisplayRuleSetsInFile(dgn)) { _rawData = sets; CopyRawData(dgn); } foreach (DisplayRuleSet set in _data) { MessageCenter.Instance.StatusMessage = $"Harvested display rule set '{set.Name}' from active DGN file"; } } if (source.HasFlag(Source.DGNLibs)) { HarvestDgnLibs(); } return Count; } /// Trace the levels in the Message Center debug window. public void Trace() { string msg = $"Harvested {Count} display rule sets"; MessageCenter.Instance.ShowDebugMessage(msg, msg, false); foreach (DisplayRuleSet set in _data) { msg = $"Display Rule Set: {set.Name}"; MessageCenter.Instance.ShowDebugMessage(msg, msg, false); } } /// Harvest display rule sets from visible DGNLibs. /// Returns: Count of rule sets in list. private int HarvestDgnLibs() { DgnLibIterator iterator = new DgnLibIterator(_selector); foreach (DgnFile lib in iterator) { using (IDisposableEnumerable sets = DisplayRulesManager.GetDisplayRuleSetsInFile(lib)) { _rawData = sets; CopyRawData(lib); } } return Count; } /// Copy data from an IEnumerable of type T to a type safe list of data. /// The raw data is obtained from each DGNLib and the active file, so the visible data is the concatenation of the harvest from each file. /// Returns: Count of objects in data list after copy. protected int CopyRawData(DgnFile dgn) { foreach (DisplayRuleSet set in _rawData) { _data.Add(set.Clone(dgn)); } return Count; } }
This class inherits from the above base class and is responsible for harvesting LevelHandle
data.
The work of extracting data from DGNLibs is performed by HarvestDgnLibs()
.
/// LevelHarvester wraps the APIs that get level definitions from DGNLibs. public class LevelHarvester : DgnLibHarvester<LevelHandle> { /// Return the number of levels found public int LevelCount { get { return Count; } } /// Return an array of names of levels. public override string[] Names { get { string[] names = new string[Count]; int i = 0; foreach (LevelHandle handle in _data) { names[i] = handle.Name; ++i; } return names; } } /// Harvest levels from the active DGN file, all DGNLibs or both. /// Param "source": ActiveDgnFile, DGNLibs or All. /// Returns: count of level definitions found. public int Harvest(Source source = Source.All) { _data = new List<LevelHandle>(); if (source.HasFlag (Source.ActiveDgnFile)) { _rawData = SettingsExample.GetActiveDgnFile().GetLevelCache().GetHandles (); CopyRawData(); foreach (LevelHandle handle in _data) { MessageCenter.Instance.StatusMessage = $"DgnLib level: {handle.Name}"; } } if (source.HasFlag (Source.DGNLibs)) { HarvestDgnLibs(); } return _data.Count(); } /// Trace the levels in the Message Center debug window. public void Trace() { string msg = null; foreach (LevelHandle level in _data) { msg = $"Level: {level.Name}"; MessageCenter.Instance.ShowDebugMessage(msg, msg, false); } } /// Harvest levels from visible DGNLibs. /// Returns: count of levels in list. private int HarvestDgnLibs() { DgnLibIterator iterator = new DgnLibIterator(DgnLibSelector.ElementStyles); foreach (DgnFile lib in iterator) { _rawData = lib.GetLevelCache ().GetHandles (); CopyRawData(); } return Count; } }
This article was written as a summary of my own experience in developing the DGNLib Harvester. I was helped on my way by hints & tips on the MicroStation Programming Forum. Special thanks go to Jan Šlegr, a regular contributor to Bentley Communities, for his suggestions.
The code for the DGNLib Harvester is available in this Visual Studio solution. Unpack the ZIP archive and copy the source code to a suitable location for Visual Studio.
The solution contains two Visual Studio projects: UserSettingsManager and the Settings Example.
It's Settings Example that contains the DGNLib Harvester.
When you build the solution two DLLs are created, hopefully in ..\MicroStation\mdlapps
.
You may need to edit the Visual Studio project settings to set the correct location on your computer.
Post questions about MicroStation programming to the MicroStation Programming Forum.