Skip to main content
Skip Navigation LinksHome  Extending the Spotfire Platform  Spotfire SDK  Visual Studio® Macros

©Spotfire 2011

Visual Studio® Macros

The SDK contains a Visual Studio macro simplifying development of document nodes. It injects boiler plate code based on the private fields defining a custom Spotfire document node.

Overview

Macros is a powerful Visual Studio® feature. It enables automation of repetitive tasks, enabling the macro end user to quickly and accurately perform otherwise error prone actions, like creating document nodes in Spotfire.

The SpotfireSDKMacros.vsmacros macro project is available in the VisualStudioMacros folder of the SDK as of version 2.2.

Installing the Spotfire SDK Macros

In Visual Studio®, open the Macro Explorer (Alt + F8). Right-click the Macros icon and select Load Macro Project... Browse to SDK\VisualStudioMacros, select the SpotfireSDKMacros.vsmacros file and click OK.

The Document Model Module

The InsertTemplatecodeBasedOnPrivateFields macro of the DocumentModel macro module is the only module recommended for use. It is convenient when creating document nodes. Since document nodes add complexity and at times may impede performance, even if carefully designed, first consider if you really need a document node. If you do, remember that the macro does not provide design, but simply adds boiler plate code based on private fields.

Spotfire SDK macro creating document nodes

Using the Macro

Suppose you need a document node representing a coordinate. First create a class inheriting from DocumentNode and declare the following fields:

[Serializable]
[PersistenceVersion(1, 0)]
internal partial class MyCoordinate : DocumentNode
{
    #region Private Fields

    private readonly string title;
    private readonly UndoableProperty<int> width;
    private readonly UndoableProperty<int> height;
    private readonly RuntimeProperty<int> diagonal;

    #endregion // Private Fields

    #region Code generated by the macro InsertTemplatecodeBasedOnPrivateFields

    // Place cursor on the line below this line and run the "InsertTemplatecodeBasedOnPrivateFields" macro
    

    #endregion // Code generated by the macro InsertTemplatecodeBasedOnPrivateFields

}

To create the code implementing the document node based on these fields, place the cursor in the position indicated above and run the InsertTemplatecodeBasedOnPrivateFields macro from the Macro Explorer. Result:

[Serializable]
[PersistenceVersion(1, 0)]
internal partial class MyCoordinate : DocumentNode
{
    #region Private Fields

    private readonly string title;
    private readonly UndoableProperty<int> width;
    private readonly UndoableProperty<int> height;
    private readonly RuntimeProperty<int> diagonal;

    #endregion // Private Fields

    #region Code generated by the macro InsertTemplatecodeBasedOnPrivateFields

    // Place cursor on the line below this line and run the "InsertTemplatecodeBasedOnPrivateFields" macro

    #region Classes for property names

    /// <summary>
    /// Contains property name constants for the public properties of <see cref="MyCoordinate"/>.
    /// </summary>
    public new abstract class PropertyNames : DocumentNode.PropertyNames
    {
        /// <summary>
        /// The name of the property Width.
        /// </summary>
        public static readonly PropertyName Width = CreatePropertyName("Width");

        /// <summary>
        /// The name of the property Height.
        /// </summary>
        public static readonly PropertyName Height = CreatePropertyName("Height");

        /// <summary>
        /// The name of the property Diagonal.
        /// </summary>
        public static readonly PropertyName Diagonal = CreatePropertyName("Diagonal");

    }

    private abstract class PrivatePropertyNames : DocumentNode.PropertyNames
    {
        /// <summary>
        /// The name of the property Title.
        /// </summary>
        public static readonly PropertyName Title = CreatePropertyName("Title");

    }

    #endregion // Classes for property names

    #region Public properties

    /// <summary>
    /// Gets or sets Width.
    /// </summary>
    public int Width
    {
        get { return this.width.Value; }
        set { this.width.Value = value; }
    }

    /// <summary>
    /// Gets or sets Height.
    /// </summary>
    public int Height
    {
        get { return this.height.Value; }
        set { this.height.Value = value; }
    }

    /// <summary>
    /// Gets Diagonal.
    /// </summary>
    public int Diagonal
    {
        get { return this.diagonal.Value; }
    }

    /// <summary>
    /// Gets Title.
    /// </summary>
    public string Title
    {
        get { return this.title; }
    }


    #endregion // Public properties

    #region Construction

    /// <summary>
    /// Initializes a new instance of the <see cref="T:MyCoordinate"/> class./// </summary>
    public MyCoordinate()
    {
        CreateProperty(PropertyNames.Width, out this.width, default(int));
        CreateProperty(PropertyNames.Height, out this.height, default(int));
        CreateReadOnlyProperty(PrivatePropertyNames.Title, default(string), out this.title);

        InitRuntimeProperties(out this.diagonal);
    }

    #endregion // Construction

    #region Runtime properties

    private void InitRuntimeProperties(out RuntimeProperty<int> diagonal)
    {
        CreateRuntimeProperty<int>(PropertyNames.Diagonal,
        out diagonal,
        DiagonalTrigger,
        DiagonalCompute);

    }

    private static readonly StatelessDependencyDeclarer DiagonalTrigger = DiagonalDependencyDeclarer;
    private static Trigger DiagonalDependencyDeclarer(DocumentNode node)
    {
        MyCoordinate thisNode = (MyCoordinate)node;

        // TODO: Insert the trigger declaration for the Diagonal property here.
        throw new NotImplementedException();
    }

    private static readonly StatelessPropertyComputer<int> DiagonalCompute = DiagonalPropertyComputer;
    private static int DiagonalPropertyComputer(DocumentNode node)
    {
        MyCoordinate thisNode = (MyCoordinate)node;

        // TODO: Insert the computation code for the Diagonal property here.
        throw new NotImplementedException();
    }

    #endregion // Runtime properties

    #region ISerializable Members

    /// <summary>Implements ISerializable.</summary>
    protected MyCoordinate(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        DeserializeReadOnlyProperty(info, context, PrivatePropertyNames.Title, out this.title);
        DeserializeProperty<Int32>(info, context, PropertyNames.Width, out this.width);
        DeserializeProperty<Int32>(info, context, PropertyNames.Height, out this.height);

        InitRuntimeProperties(out this.diagonal);
    }

    /// <summary>Implements ISerializable.</summary>
    protected override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        SerializeReadOnlyProperty(info, context, PrivatePropertyNames.Title, this.title);
        SerializeProperty<Int32>(info, context, this.width);
        SerializeProperty<Int32>(info, context, this.height);
    }

    #endregion // ISerializable Members


    #endregion // Code generated by the macro InsertTemplatecodeBasedOnPrivateFields

}