Introduction

The DgnPlatformNet API helps developers wanting to create custom applications for MicroStation® from Bentley Systems. We create a MicroStation application as a DLL, written using C# and built with the Microsoft tools provided with Visual Studio.

Can't Place a Cell using .NET

Unfortunately there is no class or method in the MicroStation .NET API to place a cell. That absence has been lamented many times over the years since the launch of MicroStation CONNECT. This article describes a work-around. We call on the VBA/COM API from C# using a .NET InterOp.

Let me explain the previous sentence, which looks as if we made a bulk purchase of acronyms from Dictionary.com …

Glossary of Terms and Acronyms
Word Expansion Comment
.NET Microsoft's operating system extension and programming toolset pronounced Dot Net
API Application Programming Interface
C# A Programming Language Invented and promoted by Microsoft
VBA Visual Basic for Applications Invented and promoted by Microsoft, licensed by Bentley Systems for use in MicroStation
InterOp Interoperability C# Programming Guide

Vote for Place a Cell using .NET

You can visit the Be Communities and look at the Ideas section. There you can vote for Place Cell using .NET idea.

Using VBA/COM from .NET

Both VBA and .NET are Microsoft technologies. Microsoft also developed the InterOp technology, which allows us to write .NET code that calls VBA/COM classes or methods. The Bentley Systems APIs extend that concept with their own InterOp.

Here are the namespaces that should be referenced when we want to call VBA/COM from a .NET project …

using Bentley.MstnPlatformNET.InteropServices;
using Bentley.Interop.MicroStationDGN;
//  This lets us use VBA/COM objects with an abbreviated prefix …
using BCOM = Bentley.Interop.MicroStationDGN;

We get at VBA/COM objects through the VBA Application object. Put this statement in your .NET class …

private BCOM.Application _app = Utilities.ComApp;

Now you can use the public methods of Application in your .NET code. For example …

BCOM.Point3d scale = _app.Point3dOne();

IPrimitiveCommandEvents Interface

The secret sauce to a place cell tool in .NET is to write a class that inherits the COM IPrimitiveCommandEvents interface …

class PlaceCellComTool : IPrimitiveCommandEvents

Now you can write .NET code that implements that interface. Because it's an interface, you must implement all of its methods, even though you may not need them all …

public void Cleanup() {}
public void DataPoint(ref BCOM.Point3d point, BCOM.View view) {}
public void Dynamics(ref BCOM.Point3d point, BCOM.View view, MsdDrawingMode drawMode) {}
public void Keyin(string Keyin) {}
public void Reset() {}
public void Start() {}

Place Cell Tool

Now you have all the ingredients, including the secret sauce, to write a place cell tool. The code is very similar to that which you would write in VBA. However, you must use C# syntax. Here's an example class …

/// This Place Shared Cell tool is implemented mostly using COM classes.
class PlaceSharedCellComTool : IPrimitiveCommandEvents
{
  private BCOM.Application _app = Utilities.ComApp;
  private string CellName { get; set; }
  /// This Place Cell tool is implemented mostly using COM classes.
  /// cellName: Name of cell to place.
  PlaceSharedCellComTool(string cellName) { CellName = cellName; }
  /// Cleanup is not used in this tool.
  public void Cleanup()
  {
  }
  ///  Make an in-memory cell.
  /// point: Location of the cell origin.
  /// view: Datapoint was received in this view.
  /// Returns: Reference to a new BCOM element.
  private SharedCellElement MakeCell (ref BCOM.Point3d point, BCOM.View view)
  {
    //  Rotate the element by the inverse of view rotation so that it appears as expected
    BCOM.Matrix3d rotation = _app.Matrix3dInverse(view.get_Rotation());
    BCOM.Point3d scale = _app.Point3dOne();
    const bool TrueScale = true;
    return _app.CreateSharedCellElement2(CellName, point, ref scale, TrueScale, rotation);
  }
  ///  User-supplied datapoint.
  /// point: Where the user clicked.
  /// view: User clicked in this view.
  public void DataPoint(ref BCOM.Point3d point, BCOM.View view)
  {
    SharedCellElement oCell = MakeCell(ref point, view);
    _app.ActiveModelReference.AddElement(oCell);
  }
  /// Called by the state machine for each mouse move event.
  /// point: Current cursor location.
  /// view: Cursor is in this view.
  /// drawMode: Draw mode supplied by the drawing engine.
  public void Dynamics(ref BCOM.Point3d point, BCOM.View view, MsdDrawingMode drawMode)
  {
    SharedCellElement oCell = MakeCell(ref point, view);
    oCell.Redraw(drawMode);
  }
  /// Key-in is not used in this app.
  /// Keyin: User-supplied key-in while command is active.
  public void Keyin(string Keyin)
  {
  }
  /// Restart this tool.
  public void Reset()
  {
      _app.CommandState.StartPrimitive(this);
  }
  /// Start this command.  For a cell placement tool there's little to be done.
  public void Start()
  {
    _app.CommandState.StartDynamics();
  }
  /// Static function to install and start this cell placement tool.
  /// cellName: Name of cell to place.
  public static void Install(string cellName)
  {
    BCOM.Application app = Utilities.ComApp;
    CellHelper helper = new CellHelper();
    CellInfo cellInfo = helper.FindCellInLibrary(cellName, Bentley.MstnPlatformNET.Settings.CellLibraryName);
    if (null != cellInfo)
    {
      _app.CommandState.StartPrimitive(new PlaceSharedCellComTool(cellName));
    }
    else
    {
      string warn = $"Cell '{cellName}' is not available in the attached cell library";
      Bentley.MstnPlatformNET.MessageCenter.Instance.ShowMessage(MessageType.Warning, warn, warn, MessageAlert.Balloon);
      app.CommandState.StartDefaultCommand();
    }
  }
}

The above code creates a shared cell instance. A tool to place a normal cell is similar, except it substitutes CellElement for SharedCellElement.

The tool has a static Install method. It sets the cell name to be placed, then starts the tool

Cell Helper

The CellHelper provides some utilities for cell management. In this tool, CellHelper checks that the named cell is available in the attached cell library.

Download

Download the Place Cell Example

This is not a complete working example. Rather, is a package of C# source code. The package includes …

You can download the Place Cell source code.

Questions

Post questions about C# and the DgnPlatformNet API to the MicroStation Programming Forum.