Add new EC Symbol provider with custom symbol sets using Managed API's

An expression is a text string that defines the syntax to be evaluated by the expression evaluator. The expression input can comprise of numbers, strings, access strings, symbols, and operators. Once you attach an item type with an expression defined, the corresponding value of the expression will display in the element's Properties dialog. 

This blog provides some code snips that demonstrate “How to add new EC Symbol Provider and make use of it in EC Expression using Managed API's as following:

  • Write new symbol provider to do basic mathematical operation like Addition, Subtraction, Multiplication, Division.
  • Register newly added symbol provider through published EC symbol provider APIs.
  • Create item type, item type property definitions and set EC Expression which consist of newly added symbols.
  • Attach created Item Type to element.
  • Read result of calculated property from attached instance.
  • Unregister newly added symbol provider.

Write Sample Symbol Provider

using ECE = Bentley.ECObjects.Expressions;

/// <summary>SymbolProvider is a class that publishes symbols that can be
/// used in expression and evaluated by the ECEvaluator.
/// Provides a set of Symbols.</summary>
/// IExpressionBuilderPublisher Interface must be implemented by Every Symbol Provider to get list of      
/// symbolset for expression builder.
public class SymbolsProvider : ECE.IECSymbolProvider, ECE.IExpressionBuilderPublisher
    {
    /// <summary>Provider name</summary>
    private string m_providerName;
    
    /// <summary>Symbol set name</summary>
    public const string SymbolSet = "MathsOperation";
    
    /// <summary>Default constructor.
    /// Constructs the SymbolsProvider with the default provider name 
    /// of 'SymbolsProvider'.</summary>
    public SymbolsProvider
    (
    )
        {
        m_providerName = "MathsOperationSymbolProvider";
        }

    /// <summary>Parametric Constructor for the MathsOperationSymbolProvider.
    ///</summary>
    public SymbolsProvider
    (
    string providerName
    )
        {
        m_providerName = providerName;
        }
    
#region Implementing Interface Methods
    
    /// <summary>The name of this provider.
    /// Readonly name property of the property enabler. This string should not
    /// be localized.
    /// </summary>
    public string Name
        {
        get
            {
            return m_providerName;
            }
        }
    
    /// <summary>Provider needs to document the symbols it provides.
    /// Document the provided symbols.
    ///</summary>
    public void DocumentSymbols (XmlTextWriter writer)
        {
        Assembly thisAssembly = Assembly.GetExecutingAssembly();
        string path = Directory.GetCurrentDirectory();
        writer.WriteStartElement("SymbolProvider");
        writer.WriteAttributeString("name", System.IO.Path.GetFileName(thisAssembly.Location));
        ECE.ECSymbolProviderManager.AddSymbolDocumentationFromResource(writer, 
                   Path.GetDirectoryName(thisAssembly.Location) + "\\MathOpSymbolsDoc.xml", 
                   "NewSymbolProviderAtManaged.Resources", thisAssembly);
    
        writer.WriteEndElement(); 
        }
    
    /// <summary>Provides opportunity for symbol provide to free any data that was created
    /// during the symbolpublish call.A no-op because there is nothing to cleanup.
    /// Free/Release any temporary objects that may have been created during
    /// the call to publish symbols.</summary>
    /// <param name="requiredSymbolSets">A list of symbol set names that define the set of published /// symbols.</param>
    /// </summary>
    public void SymbolUsageComplete
    (
    SCS.StringCollection contextStrings
    )
        {
        // no temporary objects created so there is nothing to do
        }
    
    /// <summary>Check if a symbol is provided by this provider.
    /// </summary>
    public bool ProvidesSymbol (string symbol)
        {
        return (symbol == SymbolSet);
        }
    
    /// <summary>Publishes symbols for the context object.If contextObjects is null then only global /// symbols are published.
    /// Publishes symbols to be evaluated.
    /// Publishes symbols for the context object for utility methods.</summary>
    /// <param name="currentContext">The ECContext object that provides a set of names to be 
    /// evaluated.</param>
    /// <param name="contextObject">An object that is passed to the symbol providers so that its 
    /// symbols may be published. This may be null.</param>
    /// <param name="requiredSymbolSets">A list of symbol set names that will be used to publish 
    /// symbols needed to evaulate the expression.</param>
    /// </summary>
    public void PublishSymbols
    (
    ref ECE.ECContext currentContext,
    System.Object contextObject,  // typically BIME::Element
    SCS.StringCollection requiredSymbolSets
    )
        {
        if ( null == requiredSymbolSets || requiredSymbolSets.Contains("MathsOperation") )
            PublishMathsOperationSymbols(ref currentContext);
        else
            return;
        }
    
#endregion
    
    /// Supportive method
    public void PublishMathsOperationSymbols
    (
    ref ECE.ECContext Context
    )
    {
    //  Create a context to hold the MathsOperation methods. It will not be
    //  directly accessible. Instead, programs will need to access
    //  it via the MathsOperation namespace.
    ECE.ECContext currentContext = new ECE.ECContext();
    
    //  Make a namespace symbol Path and add it to the current
    //  context. Make the namespace symbol point to the methods
    //  context.
    ECE.TypeIdentifier type = new ECE.TypeIdentifier(typeof(SymbolsProvider));
    
    //  Now create a symbol that refers to a static method and add
    //  it to the methodsContext
    currentContext.AddSymbol(new ECE.StaticMethodSymbol("Addition", type, "Addition"));
    currentContext.AddSymbol(new ECE.StaticMethodSymbol("Subtraction", type, "Subtraction"));
    currentContext.AddSymbol(new ECE.StaticMethodSymbol("Multiplication", type, "Multiplication"));
    currentContext.AddSymbol(new ECE.StaticMethodSymbol("Division", type, "Division"));
   
    //  Make a namespace symbol and add it to the current
    //  context. Make the namespace symbol point to the methods
    //  context.
    ECE.NamespaceSymbol mathOpsNamespace = new ECE.NamespaceSymbol("MathsOperation", currentContext);
    Context.AddSymbol(mathOpsNamespace);
    }
            
#region implementation of interface IExpressionBuilderPublisher
    
    /// <summary>Interface method to get list of included symbol provider.
    /// Get list of standard providers</summary>
    public IList<String> GetListOfPublishSymbolSet ()
        {//add provider names to get visible in expression builder
        IList<String> includedSymbolProviders = new List<String>();
        includedSymbolProviders.Add("MathsOperation");
        return includedSymbolProviders;
        }
#endregion
    
#region Static Method Symbols
     
    /// <summary>Does Addition of two numbers and returns the results.</summary>
    public static double Addition (double arg1, double arg2)
        {
        return arg1 + arg2;
        }
        
    /// <summary>Does Subtraction of two numbers and returns the results.</summary>
    public static double Subtraction (double arg1, double arg2)
        {
        return arg1 - arg2;
        }
        
    /// <summary>Does Multiplication of two numbers and returns the results.</summary>
    public static double Multiplication (double arg1, double arg2)
        {
        return arg1 * arg2;
        }
        
    /// <summary>Does Division of two numbers and returns the results.</summary>
    public static double Division (double arg1, double arg2)
        {
        return arg1 / arg2;
        }
        
#endregion
}//class SymbolsProvider

Register Sample Symbol Provider

Bentley.ECObjects.Expressions.ECSymbolProviderManager.GlobalSymbolProviderManager.AddSymbolsProvider(new SymbolsProvider());

Create item type, item type property definitions and set EC Expression which consist of newly added symbols

//create item type,properties,expression
Bentley.DgnPlatformNET.DgnFile dgnFile = Session.Instance.GetActiveDgnFile();
System.Diagnostics.Debug.Assert(null != dgnFile);

Bentley.DgnPlatformNET.ItemTypeLibrary library = Bentley.DgnPlatformNET.ItemTypeLibrary.Create("Library", dgnFile);
System.Diagnostics.Debug.Assert(null != library);

item = library.AddItemType("Itemtype");
System.Diagnostics.Debug.Assert(null != item);

Bentley.DgnPlatformNET.CustomProperty property = item.AddProperty("arg1");
property.Type = Bentley.DgnPlatformNET.CustomProperty.TypeKind.Double;
property.SetExpression("MathsOperation.Addition(2,3)");

Bentley.DgnPlatformNET.CustomProperty property1 = item.AddProperty("arg2");
property1.Type = Bentley.DgnPlatformNET.CustomProperty.TypeKind.Double;
property1.SetExpression("MathsOperation.Subtraction(2,3)");

Bentley.DgnPlatformNET.CustomProperty property2 = item.AddProperty("arg3");
property2.Type = Bentley.DgnPlatformNET.CustomProperty.TypeKind.Double;
property2.SetExpression("MathsOperation.Multiplication(2,3)");

Bentley.DgnPlatformNET.CustomProperty property3 = item.AddProperty("arg4");
property3.Type = Bentley.DgnPlatformNET.CustomProperty.TypeKind.Double;
property3.SetExpression("MathsOperation.Division(2,3)");  
library.Write();

Attach created Item Type to Element

LineElement elem = CreateLine(0, 0, -100, 100);
Bentley.DgnPlatformNET.CustomItemHost itHost = new Bentley.DgnPlatformNET.CustomItemHost(elem, false);
dgnECInstance = itHost.ApplyCustomItem(item);
dgnECInstance.WriteChanges();

Read result of calculated property from attached instance

IECPropertyValue result = dgnECInstance[arg];
if ( result == null || result.IsNull )
return;
MessageCenter.Instance.StatusMessage = result.StringValue;

Unregister Sample Symbol Provider           

Bentley.ECObjects.Expressions.ECSymbolProviderManager.GlobalSymbolProviderManager.RemoveSymbolsProvider("MathsOperationSymbolProvider");
MessageCenter.Instance.StatusMessage = NewSymbolProviderAtManaged.rm.GetString("Success_Unregister");

Please refer expression related links:

Find EC expression blog:

Item Types' EC Expressions - New in MicroStation CONNECT Edition Update 12

Also,  find below document which lists all available Expression symbol sets till Update 13:

[Technology Preview] Item Types EC Expressions.pdf

Below is the link for SDK blog for EC Expression published API(upcoming in Update 14):

Working with ItemType EC Expression using Managed, Native and COM API’s [Upcoming feature in MicroStation CONNECT Edition Update 14]

  • Hi John,

    Sorry for late reply. I am attaching sample xml here. Just to inform you, that we already delivered it with managed SDK sample. \MstnExamples\DgnEC\SymbolProviderExample\ManagedExample

    <?xml version="1.0" encoding="utf-8" ?>
    <root>
        <Symbol>
            <Set>MathsOperation</Set>
            <Name>Addition</Name>
            <Returns>Double</Returns>
            <Description>_[MathsOperation.Addition.Description]_</Description>
            <Parameter>
                <Name>1st_no</Name>
                <Type>Double</Type>
                <Description>_[MathsOperation.Addition.1st_no.Description]_</Description>
            </Parameter>
            <Parameter>
                <Name>2nd_no</Name>
                <Type>Double</Type>
                <Description>_[MathsOperation.Addition.2nd_no.Description]_</Description>
            </Parameter>
            <Example>
                <Expression>MathsOperation.Addition(1st_no,2nd_no)</Expression>
                <Result>Addition of two number in Double.</Result>
            </Example>
        </Symbol>
    
        <Symbol>
            <Set>MathsOperation</Set>
            <Name>Subtraction</Name>
            <Returns>Double</Returns>
            <Description>_[MathsOperation.Subtraction.Description]_</Description>
            <Parameter>
                <Name>1st_no</Name>
                <Type>Double</Type>
                <Description>_[MathsOperation.Addition.1st_no.Description]_</Description>
            </Parameter>
            <Parameter>
                <Name>2nd_no</Name>
                <Type>Double</Type>
                <Description>_[MathsOperation.Addition.2nd_no.Description]_</Description>
            </Parameter>
            <Example>
                <Expression>MathsOperation.Subtraction(1st_no,2nd_no)</Expression>
                <Result>Subtraction of two number in Double.</Result>
            </Example>
        </Symbol>
    
        <Symbol>
            <Set>MathsOperation</Set>
            <Name>Multiplication</Name>
            <Returns>Double</Returns>
            <Description>_[MathsOperation.Multiplication.Description]_</Description>
            <Parameter>
                <Name>1st_no</Name>
                <Type>Double</Type>
                <Description>_[MathsOperation.Addition.1st_no.Description]_</Description>
            </Parameter>
            <Parameter>
                <Name>2nd_no</Name>
                <Type>Double</Type>
                <Description>_[MathsOperation.Addition.2nd_no.Description]_</Description>
            </Parameter>
            <Example>
                <Expression>MathsOperation.Addition(1st_no,2nd_no)</Expression>
                <Result>Multiplication of two number in Double.</Result>
            </Example>
        </Symbol>
    
        <Symbol>
            <Set>MathsOperation</Set>
            <Name>Division</Name>
            <Returns>Double</Returns>
            <Description>_[MathsOperation.Division.Description]_</Description>
            <Parameter>
                <Name>1st_no</Name>
                <Type>Double</Type>
                <Description>_[MathsOperation.Addition.1st_no.Description]_</Description>
            </Parameter>
            <Parameter>
                <Name>2nd_no</Name>
                <Type>Double</Type>
                <Description>_[MathsOperation.Addition.2nd_no.Description]_</Description>
            </Parameter>
            <Example>
                <Expression>MathsOperation.Division(1st_no,2nd_no)</Expression>
                <Result>Division of two number in Double.</Result>
            </Example>
        </Symbol>
        
        
    </root>

    Regards,
    Sanjivani

  • can you post an example xml file that the DocumentSymbols method is reading? or what the format should be?