Introduction

The MicroStation Development Library (MDL) and MicroStationAPI provide APIs for 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 C++ compiler and linker provided with Visual Studio.

When editing your source code, you can choose whether to use Microsoft Visual Studio, Microsoft Visual Studio Code, or one of your favourite text editors.

When building your app, you can use Visual Studio or the Bentley Systems make (bmake) tools.

Locating Graphic Elements

A common task is to select graphic elements while editing a DGN model. The delivered examples are quite complex. The MicroStationAPI help documentation is concise and not written to help a new developer. I wanted a simple example of element location. In particular, I want to show how to select elements in various ways …

Simple Locate Tool

The Simple Locate Tool is a C++ project that uses the MicroStationAPI. In particular, it shows a simple implementation using the DgnElementSetTool as a base class. DgnElementSetTool provides a class used to locate elements prior to editing or modification.

DgnElementSetTool Base Class

DgnElementSetTool is quite versatile: it is designed to be used as a base class that your custom tool will inherit. It lets you create a location tool with numerous options. Options are invoked by overriding methods in the DgnElementSetTool class.

However, it is not always obvious which methods we should override to obtain a desired functionality. Nor is it always clear what values should be returned by our overrides to obtain the correct behaviour.

Simple Locate Tool Commands

The Simple Locate Tool is small and simple. It has three commands …

Simple Locate Tool Commands
Command Comment
EXAMPLE QUERY ACTIVE User can locate elements in the active model, but not in reference attachments
EXAMPLE QUERY REFERENCE User can locate elements in the active model and in reference attachments
EXAMPLE FILE EXIT Unloads the application

Multiple Element Processing

The application is aware of Selection Sets and Fences. When user has created a fence or selection set, the EXAMPLE QUERY XXX asks for a data point to confirm the operation, then process the elements in the fence or selection set. This gives you the opportunity to examine and modify the selected elements using the overridden DgnElementSetTool::_FilterAgendaEntries.

When you want your tool to accept a user-defined fence, add this to your class …

virtual UsesFence       _AllowFence      () override { return USES_FENCE_Check;     }

When you want your tool to accept a user-defined selection set, add this to your class …

virtual UsesSelection   _AllowSelection  () override { return USES_SS_Check; }

The values returned above tell your tool to check whether a fence or selection set is active. If so, process that multiple selection; otherwise, let the use choose a single element.

When you want your tool to accept a user-drag, add this to your class …

virtual UsesDragSelect 	_AllowDragSelect 	() override { return  USES_DRAGSELECT_Line; }

Available options are …

If you need to know how elements are selected, call DgnElementSetTool::_GetElemSource. Here's an example from the overridden _OnElementModify method …

StatusInt ExampleQueryTool::_OnElementModify (EditElementHandleR eeh)
{
    ElemSource	source	= _GetElemSource  ();
    WString		sourceDescr;
    switch (source)
    {
        case SOURCE_Pick:
        sourceDescr	= L"Pick";
        break;
        case SOURCE_Fence:
        sourceDescr	= L"Fence";
        break;
        case SOURCE_SelectionSet:
        sourceDescr	= L"SelectionSet";
        break;
    }

    const StatusInt&	ElementUnchanged = PermitReference ()? ERROR: SUCCESS;
    return ElementUnchanged;
}

ElementAgenda

This tool, as with other primitive tools you may write, uses an ElementAgenda to store a list of interesting elements. MicroStationAPI help tells us: Typically, ElementAgendas are created by MicroStation from sources that work on multiple elements such as the SelectionSet and Fences. However, as a general-purpose bvector of EditElemHandles, ElementAgendas can be created by applications for other purposes as well. ElementAgendas are themselves reference counted.

DgnElementSetTool::_FilterAgendaEntries provides an opportunity to reject selected elements. For example, a user fence may contain elements in the active model, which you want to modify. That same fence may contain elements in referenced models, which you can't modify. You can invalidate members of the ElementAgenda so that they are not presented to your modification code.

// Return true to tell DgnElementSetTool to removed invalidated entries from the ElementAgenda
bool    ExampleQueryTool::_FilterAgendaEntries()
{
    if (PermitReference	())
        return false;

    EditElementHandleP curr = GetElementAgenda ().GetFirstP ();
    EditElementHandleP end  = curr + GetElementAgenda ().GetCount ();

    bool     changed = false;

    for (; curr != end; ++curr)
    {
        //  For this example, remove elements in reference attachments
        if (mdlModelRef_isReference (curr->GetModelRef ()))
        {
            curr->Invalidate ();
            changed = true;
        }
    }

    return changed;
}

Finding Elements in Reference Attachments

DgnElementSetTool is intended to be the base class for your element modification tool. By default, it lets the user select elements only in the active model. You can override one of its methods to allow the user to choose an element in a reference …

virtual bool _IsModifyOriginal () override { return false; }

That return value false tells DgnElementSetTool that you won't modify a located element.


Additional Comments and Hints

Bentley Systems senior MicroStation developer Brien Bastings provided these additional hints & tips on the MicroStation Programming Forum.

Just wanted to add a couple things that probably aren't obvious.

DgnElementSetTool establishes the locate criteria in _SetLocateCriteria (which is called from _BeginPickElements for pick and _BuildAgenda for fences and selection sets). This is the place to add any tool specific locate criteria as opposed to _OnPostInstall.

Returning false from _IsModifyOriginal allows locked/reference elements to be selected as it puts DgnElementSetTool into copy mode. For a query-only tool this can have the undesirable side-effect of cloning styles, etc. from the source to the destination.

To avoid this, a query tool should override _OnPreElementModify. If you return SUCCESS without calling __super, _OnElementModify will still be called if that's where you want to have your logic to extract information from the selected elements.

// Query tool doesn't modify elements …
virtual StatusInt _OnElementModify (EditElementHandleR eeh) override {return ERROR;}

// Don't copy styles, etc. from reference to active …
virtual StatusInt _OnPreElementModify (EditElementHandleR eeh) override {return SUCCESS;}

// Allow selection of locked/reference elements …
virtual bool _IsModifyOriginal () override {return false;}


Download

Download the Simple Locate Tool Project

You can download the Simple Locate Example Project. The project is built using the Bentley Make build tool (BMake). It uses the C++ compiler and linker installed with Visual Studio 2013.

Questions

Post questions about C++ and the MicroStationAPI to the MicroStation Programming Forum.