January, 2010

Visio Insights
The official blog of the Microsoft Visio product team

January, 2010

  • Visio Insights

    SharePoint Workflow Authoring in Visio Premium 2010 (Part 2)

    • 11 Comments

    Workflow design often takes a lot of communication and collaboration. Business stakeholders may send IT professionals business flowcharts to further automate as workflows. On the flip-side, once the IT professional has implemented the workflow, he/she may want to store the workflow as a Visio diagram so that all stakeholders are clear on what is being implemented. Such diagrams can also serve as copies that can be archived for auditing purposes.

    Such collaboration is made easier with the workflow export and import capabilities in Visio Premium 2010. Export (as described in an earlier blog post) enables business stakeholders to pass flowcharts as business requirements to IT Professionals. With import, IT professionals can document their workflows visually. In this post, we will walk through the following:

    • Importing a workflow from SharePoint Designer
    • Customizing workflow visualization in Visio for presentation
    • Publishing Visio diagram visualization for workflow status tracking on SharePoint server

    First, let’s discuss the workflow import capabilities in Visio 2010.

    From SharePoint Designer 2010 to Visio 2010

    With SharePoint Designer 2010, an IT professional can author an executable SharePoint workflow that publishes directly to SharePoint server. Such a workflow may look like the following:

    clip_image002

    Before a workflow is ready for execution, it can be exported as a Visio diagram for Business Analyst or all process stakeholders to review before publishing. To do so, simply use the Export to Visio command in SharePoint Designer 2010, and a Workflow Visio Interchange (*.vwi) file will be saved out:

    clip_image004

    To visualize this workflow in Visio 2010, import the workflow file by going to New->Microsoft SharePoint Workflow, then go to the Process tab-> Import Workflow:

    clip_image006

    From there, the workflow is visualized in Visio, and the IT Professionals or Business Stakeholders are free to edit and enhance the diagram just the same way as any flowchart using features such as Themes or Auto Align & Space for presentation purposes:

    clip_image008

    The workflow visualization is now ready to be archived or presented to a wider audience.

    Publishing Visio Visualization from SharePoint Designer 2010

    We have discussed how workflows can be imported or exported between Visio Premium 2010 and SharePoint Designer 2010. Now let’s talk about how you can also show the status of a workflow being executed directly on SharePoint. SharePoint Designer 2010 supports publishing the visualization straight to the SharePoint Server along with the executable workflow. To do so, simply enable visualization by going to the workflow settings page, and ensure that the checkbox “Workflow Visualization” is checked:

    clip_image010

    When visualization is published from SharePoint Designer 2010, the status of the workflow execution is also shown as part of the Visio diagram. For example, as shown in the diagram below, not only are there icons indicating tasks “in progress” or “completed”, people assigned to the Tasks are also displayed clearly within the Task shapes:

    clip_image012

    The workflow is not only being executed, but users can now easily track progress of the workflow through visualization!

    Try out our Beta!

    We are very excited to bring you this new functionality and it is avaible for you to try out in the public beta. Do try it out and send us feedback through the Send a Smile feedback tool or comment on this post!

  • Visio Insights

    Custom Containers, Lists and Callouts in Visio 2010

    • 7 Comments

    In previous posts we introduced you to Containers and some of their special capabilities.  We also introduced Lists through their use in Cross-functional Flowchart, Data Graphic Legends and Wireframe shapes.  Finally we introduced Callouts as annotations on Visio diagrams.  Containers, Lists and Callouts can be used in a wide variety of diagram types.  This article explains how shape designers can go beyond the built-in shapes and create their own custom content.

    SD Content examples

     

    Structured Diagrams

    Collectively Containers, Lists and Callouts are referred to as Structured Diagram elements.  They establish relationships with other shapes and those relationships define special behaviors.  For example, shapes placed into a list are automatically arranged adjacent to one another; a callout shape moves whenever its target shape is moved. Structured Diagram elements are shapes themselves, and thus the special behaviors are defined through their ShapeSheet cells and values.

    To designate any shape as a Container, List or Callout you only need to add one User-defined cell called User.msvStructureType.  For the value enter “Container”, “List” or “Callout” as desired.  This setting tells Visio that the shape is a Structured Diagram element and adds many of the Structured Diagrams behaviors to the shape.  In the image below, a rectangle shape is transformed into a container shape by adding the User.msvStructureType cell and setting it to “Container”.  However, there are additional settings available to customize the appearance and behavior of your shape, described in the rest of the article.

    msvStructureType

     

    Container Shape Details

    Any shape with User.msvStructureType = “Container” is treated by Visio as a Container.  The following ShapeSheet cells define additional container properties, several of which can be configured in the Container Tools contextual tab in the Ribbon.

    Cell Name Description
    User.msvSDContainerMargin Distance between container boundary and member shapes
    User.msvSDContainerResize Automatic resize behavior for shape (0 = No automatic resize; 1 = Expand as needed; 2 = Always fit to contents)
    User.msvSDContainerStyle 1-based index value for the current visual style of the container
    User.msvSDContainerStyleCount Total number of visual styles supported by the container
    User.msvSDHeadingStyle 1-based index value for the current visual style of the container heading
    User.msvSDHeadingStyleCount Total number of visual styles supported by the container heading
    User.msvSDContainerLocked Boolean value that prevents membership changes in the container
    User.msvSDContainerRequiredCategories Semi-colon delimited list of category names. Other shapes must have at least one matching name to be allowed as container members.
    User.msvSDContainerExcludedCategories Semi-colon delimited list of category names. Other shapes with at least one matching name are disallowed as container members.
    User.msvSDContainerNoHighlight Boolean value that suppresses the container highlighting when member shapes are selected or added to container
    User.msvSDContainerNoRibbon Boolean value that hides the Container Tools contextual tab in the Ribbon for this container
    User.msvSDContainerHeadingEdge String designating where the interior of the container is from the perspective of the container heading. Must be either “Left”, “Right”, “Top” or “Bottom”.
    User.msvSDMembersOnHiddenLayer Boolean value that determines whether Visio severs container relationships when the container or member is placed on a hidden layer.  If True, Visio allows relationships to exist on the hidden layer.  If False, Visio severs the relationships.

    Creating a visual style

    If you are creating a container shape from scratch, you will notice that by default the container does not have any Container Style or Heading Style available in the Container Tools tab.  Styles are a way to offer different looks for your container through some combination of geometry and formatting changes.  The container shape can define multiple visual styles using the User.msvSDContainerStyle, User.msvSDContainerStyleCount, User.msvSDHeadingStyle and User.msvSDHeadingStyleCount cells (in short, the “Style” cells and the “Count” cells).  Use the Count cells to tell Visio how many styles your shape supports for the overall container or for the heading.  Then determine what ShapeSheet cells should be set for each style.  Put formulas in each of these cells that depend on the value of the Style cells. Visio will check the style count and populate the ribbon galleries with each style defined by the container shape.  When the user chooses a new style from the gallery, Visio puts that style index back into the Style cells to update the look of the container.

    msvSDContainerStyle

    The container shapes in Visio 2010 vary in complexity.  The containers in the Insert Container gallery have many visual styles and lots of formulas to change the appearance of the shapes.  There are some simpler examples in the Wireframe shapes, which define just a few styles each.

    Controlling container membership

    Visio 2010 introduces the concept of Shape Categories to refine the membership behaviors of containers.  This is the mechanism used by features such as Cross-functional Flowchart and Data Graphic Legends to ensure that only the right kinds of shapes participate in the list and container behaviors.  A container shape can restrict membership by defining a required or excluded shape category.  For this to work, a prospective member shape must have a User-defined cell User.msvShapeCategories in its ShapeSheet.  The prospective shape lists one or more category names in a semi-colon delimited string.  To only allow a specific category of member shape, a container can set that name in its User.msvSDContainerRequiredCategories cell.  To allow most shapes as members but specifically exclude a category, a container can set that name in its User.msvSDContainerExcludedCategories cell.  (Prospective shapes with no categories defined will not be allowed in a container with required categories, and they will always be allowed in a container with excluded categories.)

    Creating a heading sub-shape

    The heading of a container is simply the container shape’s text for basic containers.  However, it is possible to achieve more sophisticated visual styles if the heading becomes its own shape.  For this construction the container becomes a group and the heading is added as a sub-shape of the group.  The primary benefit is that Visio can account for the heading sub-shape in sizing and layout operations to avoid putting member shapes on top of the heading.  To designate a sub-shape as a heading for the container, add the cell User.msvStructureType to the sub-shape and give it the value “Heading”.  Also you should properly set the User.msvSDContainerHeadingEdge cell in the sub-shape.  These cells helps Visio understand how the heading is positioned relative to the interior of the container.  For example, if the heading is near the left edge of the container then the correct value for the cell is “Right” (regardless of the heading’s angle).  The interior of the container is on the right side of the heading.

    Showing custom shapes in the Insert Container gallery

    Visio provides several built-in container shapes in the Insert Container gallery located on the Insert tab of the ribbon.  It is possible to override this set of shapes by creating a specially named stencil with other container shapes.  Create a stencil named _CONTAIN.vss and place it in the user’s My Shapes folder.

     

    List Shape Details

    Any shape with User.msvStructureType = “List” is treated by Visio as a List.  Note that Lists are also considered to be Containers.  They simply have the additional capability of ordering and arranging their member shapes.  All of the previously mentioned Container cells apply to list shapes.  The following ShapeSheet cells define additional list properties.

    Cell Name Description
    User.msvSDListAlignment Determines how member shapes are aligned in list (0 = Left; 1 = Center; 2 = Right for vertical lists.  0 = Top; 1 = Middle; 2 = Bottom for horizontal lists.)
    User.msvSDListDirection Direction that list arranges member shapes (0 = Left to Right; 1 = Right to Left; 2 = Top to Bottom; 3 = Bottom to Top)
    User.msvSDListSpacing Distance between list members
    User.msvSDListItemMaster Name or UniqueID of master shape to instance on Insert commands.  Value must be placed inside a USE() function.
    User.msvSDListNoReorder Boolean value that prevents reordering of members.  The list must also be locked via User.msvSDContainerLocked = True for setting to have any effect.
    User.msvSDListRequiredCategories Semi-colon delimited list of category names. Other shapes must have at least one matching name to be allowed as list members.
    User.msvSDListExcludedCategories Semi-colon delimited list of category names. Other shapes with at least one matching name are disallowed as list members.

    Specifying a shape to insert into lists

    There are several ways to add a shape to a list: dragging and dropping the shape, clicking the blue insertion arrow that appears near the list edge or right-clicking an existing member and inserting a shape.  Clicking the insertion arrow and right-clicking to insert both use the User.msvSDListItemMaster cell to determine what shape to add to the list.  The name of the shape is placed in quotes inside a USE() function, such as USE(“Member shape”).  It is also possible to automatically populate the list with some member shapes when the list is first dropped on the page.  To do this put the following formula in the EventDrop cell of the list, repeating the DOCMD(2270) once for each member to be added:

    IF(LISTMEMBERCOUNT()=0,DOCMD(2270)+DOCMD(2270)+DOCMD(2270),0)

    Controlling list membership

    Lists have their own cells to govern list membership.  Use the User.msvSDListRequiredCategories and User.msvSDListExcludedCategories cells to restrict what shapes can become list members.  Because lists are also containers, it is possible for shapes to become container members of the list.  The standard  User.msvSDContainerRequiredCategories  and User.msvSDContainerExcludedCategories cells determine this behavior.  By default Visio will attempt to add a shape to a list as a list member, but if that fails it may try to add it as a container member.  You should manage both sets of cells to ensure the right results.

     

    Callout Shape Details

    Any shape with User.msvStructureType = “Callout” is treated by Visio as a Callout.  Callout shapes must also have a control handle with the Controls row named Controls.Association.  Visio manages the relationship with the callout’s target shape through this row in the ShapeSheet.  The following ShapeSheet cells define additional callout properties.

    Cell Name Description
    User.msvSDCalloutNoHighlight Boolean value that suppresses the highlighting on the callout target shape
    User.msvSDTargetIntersection Location in page coordinates of the intersection between the geometric boundary of the target shape and a virtual line drawn from the center of the callout to the center of the target shape. This is a read-only cell set by Visio.

    Showing custom callout shapes in the Insert Callout gallery

    Visio provides several built-in callout shapes in the Insert Callout gallery located on the Insert tab of the ribbon.  It is possible to override this set of shapes by creating a specially named stencil with other callout shapes.  Create a stencil named _CALLOUT.vss and place it in the user’s My Shapes folder.

     

    Summary

    This post gives shape designers the detailed information needed to create their own Containers, Lists and Callouts.  Please tell us what you think by using the Send a Smile feedback tool or by commenting on this post.

  • Visio Insights

    The Point Along Path ShapeSheet Functions in Visio 2010

    • 4 Comments

    In a previous blog post about new ShapeSheet functions, we introduced a set of new functions called the Point Along Path functions. These functions allow interactions with geometry paths of shapes. This post provides more detail about these new functions.

    The following functions open up a broad set of shape interactions for shape and solution developers:

    Function/Syntax

    Description

    ANGLEALONGPATH(section,travel [,segment]) Returns the angle of the tangent to the path at a given point.
    DISTTOPATH(section,x,y) Returns the shortest distance from the point represented by the specified coordinates to a point on the path.
    NEARESTPOINTONPATH(section,x,y) Returns the percentage of the distance along the path of the point that is nearest to the specified coordinates, as a value between 0 and 1.
    PATHLENGTH(section[,segment]) Returns the length of the path that is defined in the specified Geometry section.
    PATHSEGMENT(section,travel) Returns the 1-based segment number at the specified percentage mark along the specified path.
    POINTALONGPATH(section,travel[,offset][,segment]) Returns the coordinates of a point on, or offset from, the path.
    SEGMENTCOUNT(pathRef) Returns the number of line segments that make up the path.

    In the above functions:

    • Arguments in brackets [ ] are optional
    • Section always refers to a Geometry path. The correct way to reference a geometry path section is to enter the section reference followed by “.Path” (for example, Sheet.1!Geometry2.Path)
    • Travel is a measure of the position along the path between the beginning and the end points, defined as a percentage. It is always represented by a number between 0 and 1, where 0 represents the beginning point, and 1 represents the end point
    • Segment is a 1-based index of a line segment in the path that corresponds to a row in the geometry section.

    To give you an idea of what you can do with these functions, we'll explore three examples.

    Adorning a Connector

    We've seen shape developers create connector adornments to convey additional information. With the Point Along Path functions, this is now easier than ever to do.

    Here's a simple triangle shape that sits at the midpoint of the connector, and changes direction with the connector. It works with curved and right angle connectors:

    triangle

    To create this adornment, you only need a few ShapeSheet formulas:

    • First, make sure that the adornment shape will be ignored by the Visio routing engine. To do this, select the shape, and click "Behavior" from the Developer tab. In the ensuing dialog, click on the "Placement" tab, and ensure that placement behavior is set to "Do not lay out and route around".
    • Create a user cell in the adornment shape (we'll call it User.ConnectorGluePoint, and use the POINTALONGPATH() function and reference the connector that the shape will adorn:
      • POINTALONGPATH(Dynamic connector.23!Geometry1.Path,0.5)
      • This returns a point in local coordinates to the connector
    • Create another user cell, User.PageCoord, and use the LOCTOPAR() function to translate the local coordinates to page coordinates:
      • LOCTOPAR(User.ConnectorGluePoint,Dynamic connector.23!User.msvThemeColors,User.msvThemeColors)
      • The LOCTOPAR function needs cell references for the source and destination of the translation. Here we arbitrarily use User.msvThemeColors because the property exists in both the source and destination.
    • Now, set PinX,PinY, and Angle cells on the adornment shape accordingly (found in the Shape Transform section):
      • PinX: GUARD(PNTX(User.PageCoord))
      • PinY: GUARD(PNTY(User.PageCoord))
      • Angle: ANGLEALONGPATH(Dynamic connector.23!Geometry1.Path,0.5)-PI()/2
        • We subtract PI/2 because we’re using a triangle and the point is not aligned with the 0 angle. The ANGLEALONGPATH() function returns the tangent angle to the specified point on the path.

    Finding the Nearest Point on a Path

    You can use the NEARESTPOINTONPATH() function to find the coordinates of a point along a path that is closest to a given point. In the picture below, the triangle shape is showing the nearest point along the path to the center of the circular shape:

    nearest point

    Here’s how we setup the triangle to do this:

    • Create a user cell in the triangle shape to store the point of the circle shape (we’ll call it User.LocalPoint) Use the following formula to transform the LocPin point of the circle into local coordinates relative to the curve:
      • LOCTOLOC(PNT(Circle!LocPinX,Circle!LocPinY),Circle!Height,ArcLine!Height)
      • We use the PNT function to turn the LocPinX and LocPinY into a point
    • Create another user cell in the triangle (we’ll call it User.Travel) to store the percentage along the path (the travel) that is nearest to the circle. Use the following formula:
      • NEARESTPOINTONPATH(ArcLine!Geometry1.Path,PNTX(User.LocalPoint),PNTY(User.LocalPoint))
      • This returns the percentage along ArcLine!Geometry1.Path that has the nearest point to the center of the circle shape
    • Create another user cell (we’ll call it User.ArcGluePoint) to store the point along the path of the arc that is closest to the circle. Use the following formula:
      • POINTALONGPATH(Sheet.1!Geometry1.Path,User.Travel)
      • This will return the point on the arc where the triangle should be glued, in local coordinates relative to the arc.

    Just like the example above, you then need to transform the local coordinates, and set the PinX and PinY of the triangle so that its glued to the arc.

    Curved Timelines

    The above two examples illustrate how you can use the Point Along Path functions. As an application of the same concepts above, we built a curved timeline:
    curvy timeline

    As you change the curve of the timeline, the milestone shapes stay attached to the curve, which allows you to create a great looking visual.

    The main difference between this example and the previous one is that we’ve introduced a mechanism for automatically attaching adornments to the arc geometry. Here we turned the arc shape into a custom container to give the milestone shapes a universal reference. Since they are members of the container, we use the CONTAINERSHEETREF() function to reference the geometry of the arc. When you make multiple copies of the milestone shape, their reference to the timeline arc geometry is preserved as long as they are members of the container. (For more info on custom containers, see our previous post ).

    To place the milestones accurately on the timeline arc, we used the POINTALONGPATH() function. Each timeline shape stores its own date. The timeline arc contains the “begin” and “end” dates of the timeline.

    The attached VSD file includes the curved timeline, and the other two examples, so you can take a look at the formulas and play around with them.

    We think these new functions will open up a new set of scenarios for shape developers. Some things you might try to create with them are:

    • Placing text or adornments at fixed distances from the beginning or end of a connector
    • Detecting whether a point is inside or outside a closed path
    • Calculating the lengths of curved paths in a diagram
    • Drawing a line that terminates on a complex path

    As usual, please tell us what you think by using the Send a Smile feedback tool or by commenting on this post.

  • Visio Insights

    Container, List and Callout API in Visio 2010

    • 4 Comments

    This post examines the programmability features for Containers, Lists and Callouts in Visio 2010.  It supplements an earlier post that describes how these special shapes are constructed and how they can be customized.  Collectively these shapes are known as Structured Diagram elements, and the part of the Visio API that manages these elements is known as the Structured Diagram API.  This API enables developers to use Structured Diagram elements in their solutions.  Developers can identify the relationships between these elements and other shapes, they can add or change the relationships with other shapes, and they can detect when the user makes changes to the relationships with other shapes.

     

    Structured Diagram API Overview

    Here are the key objects, properties and methods in the Structured Diagrams API:

    image

    There are two new objects in the API.  ContainerProperties is an extension of the Shape object.  It encapsulates the special properties and behaviors of containers and lists.  RelatedShapePairEvent is an object used with the Structured Diagram API events, where Visio can describe a relationship being formed or broken between two shapes.  The remaining parts of the API are additions to existing Visio objects.

    Note that lists are just another type of container as far as the API is concerned.  Therefore, lists use all the same objects, properties and methods as containers; and lists have a few additional properties and methods as well (those with “List” in their name).

     

    Enabling Structured Diagram Behaviors in Solutions

    Visio 2010 introduces a new feature called Diagram Services that manages what diagramming behaviors are enabled in the document.  There are diagram services that control the behavior of Auto Size Page and diagram services that control the behaviors of Containers, Lists and Callouts.  These services are turned on and off at the document level.  When a service is off, changes made in the diagram through automation will not trigger the diagramming behaviors related to that service.  (Changes made through the user interface are not subject to the diagram service state.)

    For example, the Auto Size Page feature will normally grow the page size if a shape is placed outside the page boundary.  However, when a shape is placed outside the page via automation, the Auto Size Page feature will only respond if the Auto Size Page diagram service is enabled.  Similarly, dropping a shape on top of a container will normally make it a member of the container and cause the container to resize to fit it.  However, when the shape is dropped via automation, the Containers feature will only respond if the Structured Diagram service is enabled.

    The reason Visio 2010 includes this capability is that solutions may not always want these diagramming behaviors to get triggered while they are manipulating shapes in the diagram.  This may especially be true for existing solutions that have no knowledge of the new Visio 2010 behaviors and have expectations that shapes respond in ways consistent with Visio 2007.  In order for existing solutions to work as originally designed, all diagram services in Visio 2010 are disabled by default.  Solutions must opt the document in to the new diagramming behaviors.  Note that diagram service states apply to automation properties and methods that existed in Visio 2007.  When a new Visio 2010 automation method is explicitly invoked by a solution - such as any of the examples below – the service state is ignored.  The presumption is that the solution wants the Visio 2010 behavior associated with that method.

    Diagram service states are checked or changed using the Document.DiagramServicesEnabled property.  The value of this property is a mask of all the services currently enabled.  Available services and values are listed in the table below.  It is possible for a solution to opt into just one service, all the services supported in Visio 2010, or even all existing and future services.

    VisDiagramServices values:

    Enum Value Description
    visServiceAll -1 All diagram services
    visServiceVersion140 7 Diagram services that exist in Visio 2010
    visServiceNone 0 No diagram services (default)
    visServiceAutoSizePage 1 AutoSize page behaviors
    visServiceStructureBasic 2 Behaviors that maintain existing Structured Diagram relationships but do not create new relationships
    visServiceStructureFull 4 Structured Diagram behaviors that match the behaviors in the user interface

    There are two services for Structured Diagram behaviors.  The StructureBasic service maintains relationships but will not form new ones.  This might be appropriate for a solution that wants to respect the user’s usage of Containers, Lists and Callouts but does not want the solution itself to inadvertently form relationships when shapes are moved around the page.  The StructureFull service maintains relationships and will form new relationships as well.  This matches the behaviors that are triggered in the user interface.  If both services are enabled, then Visio uses the StructureFull set of behaviors.

     

    Common Tasks with the Structured Diagram API

    Let’s look at some typical Structured Diagram tasks to explore the API in greater detail.  For a complete list of the special flags that can be passed into the methods, look at the Object Browser within the VBA editor in Visio.

    Add a container to the page

    Containers can be added to a page by calling the traditional Page.Drop method, which will add the shape at coordinates you specify without affecting the membership of existing shapes on the page.  However, there is a new Page method – Page.DropContainer - that will not only drop the container but will also size it around a set of shapes and make those shapes members of the container.  This is the behavior in the UI when using Insert > Container when a selection exists.  DropContainer needs an object for the container shape.  If you want to use one of the shapes in the Insert Container gallery, you can use the GetBuiltInStencilFile method to retrieve the hidden stencil where these containers are stored.

    Dim vsoDoc1 As Visio.Document
    Set vsoDoc1 = Application.Documents.OpenEx(Application.GetBuiltInStencilFile(visBuiltInStencilContainers, visMSUS), visOpenHidden)
    Application.ActivePage.DropContainer vsoDoc1.Masters.ItemU("Container 1"), Application.ActiveWindow.Selection
    vsoDoc1.Close

    Add a shape to a container

    Shapes are added to a container by moving or dropping them onto the container (if the StructureFull diagram service is enabled).  Shapes can be explicitly added to a container using the AddMember method.  This is useful when the shape already overlaps the container and is not yet a member.  It is also helpful if you want to force the container to expand to encompass the new member.

    vsoContainerShape.ContainerProperties.AddMember vsoShape, visMemberAddExpandContainer

    Find the containers on a page

    To discover what containers exist in a document, Visio provides a direct way to get the set of containers in a selection or on a page.  The GetContainers method returns an array of Shape IDs for the containers.  Containers nested within other containers can be included or excluded using flags.

    For Each containerID In vsoPage.GetContainers(visContainerIncludeNested)
        Set vsoContainerShape = vsoPage.Shapes.ItemFromID(containerID)
        '...
    Next

    Get the shapes in a container

    Solutions can identify the members of a container using the GetMemberShapes method, which returns an array of Shape IDs for the member shapes.  The flags allow certain kinds of member shapes to be filtered out of the array returned.

    For Each memberID In vsoContainerShape.ContainerProperties.GetMemberShapes(visContainerFlagsDefault)
        Set vsoShape = vsoPage.Shapes.ItemFromID(memberID)
        '...
    Next

    Reorder a list

    Every member of a list is placed in a specific position, and that ordinal value can be retrieved with the ContainerProperties.GetListMemberPosition method.  To reorder a member, you can call the ContainerProperties.ReorderListMember method.  Both methods use 1 to indicate the first position in the list.

    vsoListShape.ContainerProperties.ReorderListMember vsoShape, 2

    Add a callout to the page

    Callouts can be added to a page by calling the traditional Page.Drop method, which will add the shape at coordinates you specify.  However, there is a new Page method – Page.DropCallout - that will not only drop the callout but will associate it with a target shape and position it near the target shape.  This is the behavior in the UI when using Insert > Callout when a selection exists.  As with DropContainer, DropCallout needs an object for the callout shape.  If you want to use one of the shapes in the Insert Callout gallery, you can use the GetBuiltInStencilFile method to retrieve the hidden stencil where these containers are stored.

    Dim vsoDoc1 As Visio.Document
    Set vsoDoc1 = Application.Documents.OpenEx(Application.GetBuiltInStencilFile(visBuiltInStencilCallouts, visMSUS), visOpenHidden)
    Application.ActivePage.DropCallout vsoDoc1.Masters.ItemU("Callout 1"), vsoTargetShape
    vsoDoc1.Close

    Get the target shape for a callout

    A shape can have multiple callouts, but a callout can have only one target shape at a time.  The Shape.CalloutsAssociated property returns an array of callout shape IDs.  You can get or set the target shape of a callout using the Shape.CalloutTarget property.

    Set vsoShape = vsoCalloutShape.CalloutTarget

    Structured Diagram Events

    In addition to manipulating the containers, lists and callouts in a document, you can also respond to user actions that relate to these shapes.  Containers, lists and callouts work by establishing relationships with other shapes.  Visio fires an event whenever one of these relationships is formed or broken.  For example, adding a shape to a container forms a new relationship between the shape and the container.

    When a relationship event fires, Visio specifies the details in a RelatedShapePairEvent object.  The FromShapeID property of this object indicates the container, list or callout involved in the relationship.  The ToShapeID property indicates the other shape involved in the relationship.  Thus when adding a shape to a container, the ToShapeID would refer to the new member shape, and when associating a callout with a target shape, the ToShapeID would refer to the target shape.

    The following events are available for Application, Documents, Pages and Page event lists:

    ContainerRelationshipAdded

    ContainerRelationshipDeleted

    CalloutRelationshipAdded

    CalloutRelationshipDeleted

    Also the ShapeChanged event will now fire when members of a list shape are reordered.  The event passes the list shape as an argument and includes the string “/ListReorder” in the EventInfo argument.

     

    Feedback

    The Structured Diagrams feature set – Containers, Lists and Callouts – offers both end users and developers significant new diagramming capabilities in Visio 2010.  We’re interested to hear what developers think of this API functionality, so please use the Send a Smile feedback tool or leave a comment below.

  • Visio Insights

    New ShapeSheet Cells and Functions in Visio 2010

    • 2 Comments

    Our previous post introduced the improvements we made to the ShapeSheet window for shape developers.  In this post, we will continue with ShapeSheet development and dig deeper to examine the new ShapeSheet cells and functions available in Visio 2010.

    New Cells

    A number of new cells were added to both the PageSheet and the ShapeSheet to support new features in Visio 2010 and to expand the possibilities for shape development.  We will examine each one in turn.

    New PageSheet cells in Visio 2010:

    Section Cell
    Page Layout AvoidPageBreaks
    Page Properties DrawingResizeType

    New ShapeSheet cells in Visio 2010:

    Section Cell
    Shape Layout DisplayLevel
    Actions FlyoutChild
    Geometry NoQuickDrag
    Shape Layout Relationships

    Recall that you can view the PageSheet for a page or the ShapeSheet for a shape using the Developer tab.

    image 

    AvoidPageBreaks cell

    This cell takes a TRUE or FALSE value and determines whether the Auto Align and Space features attempt to avoid placing shapes on page breaks.  This corresponds to the Space Shapes > Avoid Page Breaks setting under the Position button on the Home tab.

    image

     DrawingResizeType cell

    This cell corresponds to the Page Auto Size feature, which is found on the Design tab.  It takes three values.  Values 1 and 2 correspond to Auto Size on and off, respectively.

    image

    Zero is “undefined,” which is the default state for a document created in Visio 2007 or prior, since this cell doesn’t exist in those versions.  This value allows Visio to determine whether Auto Size is enabled for the user.  It makes a best guess by looking at the page size relative to common paper sizes and deciding whether the page size appears to have been customized, or left at a default size.  If the page is at a default size, Visio enables Auto Size so users can benefit from it; if customized, Visio assumes that a specific page size was chosen for a reason and disables Auto Size.  In any case, the user can change the setting by toggling the Auto Size button on the Design tab.

    DisplayLevel cell

    This cell defines “bands” of Z-order and is used to determine the default global Z-order position for a shape when it is added to the page.  Visio uses this to place containers behind the shapes they contain, regardless of what order they are added to the page.  Shapes with a higher DisplayLevel value are displayed on top of shapes with a lower value.  Each value of DisplayLevel, which ranges from –32767 to +32767, defines a band.

    As an example, consider a diagram with three masters, each with the DisplayLevel value shown.  Regardless of what order shapes with DisplayLevel 10, 20 or 30 are dropped, the 10s will always be behind the 20s and 30s, and so forth.  The blue shape shown below is at the bottom of the Z-order and was dropped before the other two shapes at DisplayLevel 10.  DisplayLevel bands do not interfere with the Z-order commands on the Home tab – Bring Forward / Send Backward and Bring to Front / Send to Back.  Using Bring to Front or Send to Back will initially only move the shape to the front or back of the Z-order for its band.  A subsequent use will move it to the global front or back of the Z-order.

    image   image   image
    Start with these shapes, with the given DisplayLevel values   After pressing Bring to Front on the blue shape   After pressing Bring to Front on the blue shape again

    Notice the special –32768 value, which means that the shape has been pulled out of its band.  Visio stores the previous band in a formula in the DisplayLevel cell so it can be restored.  Note that changing the value of the DisplayLevel cell does not change the shape’s Z-order, but the band will be taken into account the next time Visio needs to manipulate the shape’s Z-order.

    FlyoutChild cell

    This cell allows Actions, or custom right-click menu items, to be nested.  Any menu item whose FlyoutChild value is TRUE will appear in a flyout menu of the first row above it whose FlyoutChild is FALSE.  This allows one level of nesting.

    The Actions section below will show the following custom items on the right-click menu.

     image image

    If the value of FlyoutChild for B and C is TRUE, then those items appears in a flyout menu under A.

    image 

    NoQuickDrag cell

    This cell allows a shape developer to control how click and drag inside a given geometry section of a shape works.  Typically, this picks up and moves a shape.  By setting this cell to TRUE, you can create a non-clickable (or non-selectable) filled geometry area that prevents picking up and moving the shape.  The container shapes new to Visio 2010 use this cell to allow click and drag to select shapes in the container rather than move the container.

    Relationships cell

    This cell stores the relationships among containers, lists, callouts and shapes.  It uses a series of DEPENDSON functions, one for each different type of relationship the object has.  Note that changes to this cell will not trigger actual relationship changes; Visio only uses this as a means to store the relationship information.  This cell is not intended to be modified by users or shape developers.

    The types of relationships are listed below.

    Value Meaning
    1 Shapes that are members of this container
    2 Shapes that are members of this list
    3 Callouts that are associated with this shape
    4 Containers that this shape is a member of
    5 List that this list item is a member of
    6 Shape associated with this callout
    7 Container on the left boundary edge of which this shape sits
    8 Container on the right boundary edge of which this shape sits
    9 Container on the top boundary edge of which this shape sits
    10 Container on the bottom boundary edge of which this shape sits
    11 List that this list overlaps

    A shape named Process that is a member of a container named Container 1 would have a Relationships cell formula of this form: =SUM(DEPENDSON(4,Container 1!SheetRef())).  The container’s Relationship cell would look like: =SUM(DEPENDSON(1,Process!SheetRef())).

    If the Process shape were pinned to the left edge of the container, its Relationships cell would be: =SUM(DEPENDSON(7,Container 1!SheetRef()),DEPENDSON(4,Container 1!SheetRef())).  The container’s cell would remain as listed.

    A shape that is a member of two containers would look like: =SUM(DEPENDSON(7),DEPENDSON(4,Container 1!SheetRef(),Container 2!SheetRef())), and so forth.

    New Functions

    We also added ShapeSheet functions that enable new developer scenarios, particularly for integrating with new Visio 2010 features.

    Containers and Lists

    A number of functions are designed to enable interaction with the new container and list features.

    The following functions return a Sheet reference, or a reference to the shape.  (Such functions exist in Visio 2007 and previous versions, such as NAME and ID.)  This return value can then be used to call another function.  For example, CALLOUTTARGETREF()!HASCATEGORY(“Category”).

    Function Description
    CALLOUTTARGETREF() Returns a Sheet reference to the target shape that this callout is associated with
    CONTAINERSHEETREF(index, category) Returns a Sheet reference to the container shape that this shape is a member of
    -- The 1-based Index parameter specifies which parent container to return, where the topmost container is ordered first
    -- If category is specified, the container must have that category in order to be returned
    LISTSHEETREF() Returns a Sheet reference to the list container shape that this shape is a member of

    The following functions return the number of associated shapes.

    Function Description
    CALLOUTCOUNT() Returns the number of callout shapes associated with the shape
    CONTAINERCOUNT() Returns the number of containers the shape is a member of
    CONTAINERMEMBERCOUNT() Returns the number of member shapes in the container shape
    LISTMEMBERCOUNT() Returns the number of member shapes in the list container shape

    The following functions  

    Function Description
    HASCATEGORY(string) Returns TRUE if the specified string is found in the shape's categories list
    LISTORDER() Returns the 1-based order for the shape within a list

    In the example below, the rectangular process shape belongs to a container.  It shows the total number of shapes in the container using a text field with the formula CONTAINERSHEETREF(1)!CONTAINERMEMBERCOUNT().

    image 

    Geometry Paths

    Another set of functions enable detailed interaction with individual geometry paths among different shapes.  Each of these functions requires a specific Geometry section to be specified – e.g., PATHSEGMENT(Sheet.1!Geometry2.Path, 0.4).  Points on a path are given as a percentage of the distance along the path.

    Function Description
    ANGLEALONGPATH(section, percent, segment) Returns the tangent angle of a point on the path defined in a geometry section
    DISTTOPATH(section, x, y) Returns the shortest distance from the specified coordinates to a point on the path defined in a geometry section
    NEARESTPOINTONPATH(section, x, y) Returns the point along the path defined in a geometry section that is nearest the specified coordinates
    PATHLENGTH(section, segment) Returns the length of the path defined in a geometry section
    PATHSEGMENT(section, percent) Returns the 1-based segment number containing a point on the path defined in a geometry section
    POINTALONGPATH(section, percent, [offset], [segment]) Returns the coordinates of a point on or offset from the path defined in a geometry section
    SEGMENTCOUNT(section, percent) Returns the number of line segments that make up the path defined in a geometry section

    These functions open up a broad set of interesting shape interactions that we’re sure shape and solution developers will love.  We will write a more detailed post focusing on these functions soon.

    Miscellaneous

    The last group of functions are various helpers that either support the new functions or fill in gaps.  The first four operate on a Sheet reference.

    Function Description
    BOUNDINGBOXDIST(index) Returns the measurement for the part of the shape's bounding box specified by the Index enumeration
    BOUNDINGBOXRECT(index) Returns the coordinate of an edge of the shape's bounding box specified by the Index enumeration
    IS1D() Returns TRUE if the shape is one-dimensional
    SHEETREF() Returns a Sheet reference for the specified shape
    IFERROR(expression, altExpression) Returns the evaluated result of the expression if it is not an error; otherwise returns the evaluated result of the alternate expression
    MSOSHADE(color, deltaLum) Modifies the color by decreasing its luminosity by the amount specified
    MSOTINT(color, deltaLum) Modifies the color by increasing its luminosity by the amount specified
    VERSION() Returns an integer value matching the current version of the Visio application

     

    Index enumeration for BOUNDINGBOXDIST:

    Value Meaning
    0 Width
    1 Height
    2 Left edge to shape pin
    3 Shape pin to right edge
    4 Shape pin to top edge
    5 Bottom edge to shape pin
    6 Center of bounding box to PinX
    7 Center of bounding box to PinY

    Index enumeration for BOUNDINGBOXRECT:

    Value Meaning
    0 Left edge
    1 Right edge
    2 Top edge
    3 Bottom edge

    We also modified the following functions that existed in Visio 2007 and prior versions.  You can continue to use these as you have in the past – e.g., NAME() – or you can use them with a Sheet reference, such as Sheet.4!NAME() or CONTAINERSHEETREF(1)!NAME().

    • DATA1, DATA2, DATA3
    • ID
    • MASTERNAME
    • NAME
    • PAGENAME, BKGPAGENAME
    • PAGENUMBER, BKGPAGENUMBER
    • TYPE, TYPEDESC

    We hope you will find these useful in opening new opportunities for shapes and making your shape development tasks easier.  As always, we’re interested in your feedback and suggestions via a comment on the blog or using Send a Smile.

  • Visio Insights

    The Diagram Validation API

    • 2 Comments

    Diagram Validation is a new Visio 2010 feature that provides a way for users to check their diagrams for common errors and for companies to ensure that employees are following certain diagramming standards. The basics of diagram validation and creating custom validation rules have been previously discussed on this blog. In this post, we focus on the details of using the validation API to create validation rules, trigger validation, and manage validation issues.

    Visio provides an extensive Diagram Validation API that allows companies to develop custom validation rules based on their own needs. For example, you can build rules to check that a network diagram includes mandatory components, or that a process diagram complies with company policies. The ability to verify the correctness of a diagram and raise issues to end-users is also crucial for solutions that need a certain diagram structure to work. For example, Visio uses validation for Microsoft SharePoint Workflow diagrams to ensure that SharePoint workflows are structured correctly before exporting them. As a developer, you can leverage Diagram Validation to support diagram verification for the diagram types and the issues that are important to you.

    Validation API overview

    The key objects, methods and properties for validation are shown below.

    Validation API

    The validation API is based on three main concepts: rule sets, rules and issues. A validation rule, or simply a rule, represents one type of error that can occur in your diagram. Each rule has some underlying business logic which determines when the rule has been broken. An issue is one case in your diagram where the validation rule has been broken. Depending on your diagram, there may be multiple issues associated with the same rule. For example, if the rule requires that all shapes be labeled, then validation will display an issue for each shape without a label. Rule sets are logical grouping of rules, such as the BPMN and flowchart rule sets.

    Key validation objects and properties

    Rules sets, rules and issues each have corresponding API objects, namely ValidationRuleSet, ValidationRule and ValidationIssue. Below we explain the key properties for each of these objects.

    ValidationRuleSet

    Every rule set has a unique NameU property representing the universal name of the rule set. You should also specify a Description for each rule set. Other properties are set by default, and only need to be modified if a different behavior is desired. The key properties of the ValidationRuleSet object are shown below.

    Property Description
    Description Specifies the description of the rule set.
    Enabled Determines whether the rule set is active or inactive. Only rules belonging to active rule sets are checked when validation is triggered. By default, rule sets are enabled.
    Name Specifies the name of the rule set that appears in the UI. By default, it is the same as NameU.
    NameU Specifies the universal name of the rule set.
    Rules Itemizes the rules in the rule set.
    RuleSetFlags Determines whether the rule set appears in the UI. By default, rule sets are visible through the UI.

    ValidationRule

    Every rule has a unique NameU property representing the universal name of the rule. You should also specify a Category and Description for each rule set, as these properties are used in the UI. The Category should inform the user about the type of issue, and may be used to identify the rule set that triggered the issue. The Description should be explicit enough to explain the issue so that a user can address it.

    The blog post on creating custom validation rules describes two approaches for creating custom validation rules: you can store validation logic in a Visio template, or you can express validation logic in code and deploy this logic as part of a Visio solution. If you decide to store validation logic in a Visio template, the FilterExpression, TestExpression and TargetType are the fundamental properties for detecting and reporting issues during validation. If you decide to write validation logic in code, these fields should be left blank. The FilterExpression, TargetType and TestExpression properties are described in more detail in the section titled Defining ValidationRule.FilterExpression and ValidationRule.TestExpression.

    The key properties of the ValidationRule object are shown below.

    Property Description
    Category Represents the text displayed in the Category column of the Issues window.
    Description Specifies the description of the rule that appears in the Issues window.
    FilterExpression Specifies the logical expression that determines whether the validation rule should be applied to a target object.
    Ignored Determines whether the validation rule is currently ignored. By default, rules are not ignored.
    NameU Specifies the universal name of the rule.
    RuleSet Returns the rule set that contains the rule.
    TargetType Determines the target type of the rule. A rule can target documents, pages, or shapes.
    TestExpression Specifies the logical expression that determines whether the target object satisfies the rule.

    ValidationIssue

    Every issue has an associated Rule which specifies the description and category that is displayed in Issues window. When a user clicks on an issue in the Issues window, Visio will navigate to the page of the issue (if the issue targets a page or shape) and will select the target shape (if the issue targets a shape).The TargetPage, TargetPageID and TargetShape properties are used determine the page to display and the shape to select.    The key properties of the ValidationIssue object are shown below.

    Property Description
    Ignored Determines whether the issue is currently ignored.
    Rule Specifies the rule that generated the issue.
    TargetPage Specifies the page that is associated with the issue.
    TargetPageID Specifies the ID of the page that is associated with the validation issue.
    TargetShape Specifies the shape that is associated with the validation issue.

    Validation methods for adding rule sets and rules

    Validation methods can be divided into different groups. We will start by describing the first group of methods, which allows developers to add validation rule sets and rules to a document. Typically, these methods are executed once to populate a template or diagram with validation rules. In fact, the rules can be pre-populated in a template, and then the template can be deployed to end-users without any solution code.

    For each of the following API methods, we give a brief description on what the method does, along with an explanation of the method’s arguments.

    ValidationRuleSets.Add(NameU)

    Adds a new, empty ValidationRuleSet object to the ValidationRuleSets collection of the document.

    • NameU: The universal name to assign to the new validation rule set.

    ValidationRules.Add(NameU)

    Adds a new, empty ValidationRule object to the ValidationRules collection of the document.

     

    Example

    The following VBA code adds a rule set and a rule that targets a shape to the active document.

     

      Set vsoDocument = Visio.Activedocument
       
      'Add a validation rule set to the document
      Set vsoValidationRuleSet = vsoDocument.Validation.RuleSets.Add("Connectivity")
      vsoValidationRuleSet.Description = "Verify that shapes are correctly connected in the document."
      vsoValidationRuleSet.Enabled = True
      vsoValidationRuleSet.RuleSetFlags = Visio.VisRuleSetFlags.visRuleSetDefault
       
      'Add a validation rule to the document
      Set vsoValidationRule = vsoValidationRuleSet.Rules.Add(“Unglued2DShape”)
      vsoValidationRule.Category = "Shapes"
      vsoValidationRule.Description = "This 2-dimensional shape is not connected to any other shape."
      vsoValidationRule.Ignored = False
      vsoValidationRule.TargetType = Visio.VisRuleTargets.visRuleTargetShape
       
      'The validation function Is1D() returns a Boolean value indicating whether the shape is
      '1D (True) or 2D (False)
      vsoValidationRule.FilterExpression = "NOT(Is1D())"
       
      'The validation function GLUEDSHAPES returns a set of shapes glued to the shape.
      'It takes as input one parameter indicating the direction of the glue.
      'The direction values are equivalent to members of VisGluedShapesFlags:
      '0 = visGluedShapesAll1D and 3 = visGluedShapesAll2D
      'The validation function AGGCOUNT takes a set of shapes as its input, and returns
      'the number of shapes in the set.
      vsoValidationRule.TestExpression = "AGGCOUNT(GLUEDSHAPES(0)) + AGGCOUNT(GLUEDSHAPES(3)) > 0"

    Validation methods for managing issues

    When you set the TargetType, FilterExpression and TestExpression of a rule, Visio will manage issues associated with the rule for you. For very complex validation rules, it will be easier to omit these properties and write the validation logic in solution code. For this approach, the solution should listen for the appropriate RuleSetValidated event and use its own logic to determine the list of issues to add to the document.

    We give a brief description of the two key methods that you will use to manage issues, along with an explanation of the method’s arguments.

    ValidationRule.AddIssue([TargetPage],[TargetShape])

    Creates a new validation issue that is based on the validation rule, and adds it to the document.

    • TargetPage(Optional): The page that either has the issue or has the shape with the issue.
    • TargetShape(Optional): The shape that has the issue.

    ValidationIssue.Delete()

    Deletes the ValidationIssue object from the document.

     

    Example

    The following VBA code adds an issue to an existing rule. It assumes that vsoValidationRule is a valid Visio.ValidationRule object, vsoShape is a valid Visio.Shape object and vsoPage is a valid Visio.Page object.

      'Add a custom issue to the vsoValidationRule validation rule and associate it with
      'shape vsoShape on page vsoPage
      Set vsoValidationIssue = vsoValidationRule.AddIssue(vsoPage, vsoShape)
      vsoValidationIssue.Ignored = False

    Using the API to validate a document

    If you have a custom solution that needs a certain diagram structure to function properly, you can use the Validation.Validate method to validate the diagram and raise issues to end-users. This method validates a particular validation rule set (if specified) and updates the Validation. LastValidatedDate property. It will also trigger the RuleSetValidated event. It is recommended that you omit the rule set parameter, and validate against all active rule sets. This gives end-users a clear and consistent view of the issues currently in their document.

    Validation.Validate([RuleSet As ValidationRuleSet], [Flags As VisValidationFlags])

    Validates the specified validation rule set.

    • RuleSet (Optional): The rule set to validate across the entire document.
    • Flags (Optional): Whether to open the Issues window after validation.

     

    Example

    The following VBA code validates all rule sets in the document and launches the Issues window.

      'Validate the document
      Call Visio.Activedocument.Validation.Validate(, Visio.VisValidationFlags.visValidationDefault)

    Defining ValidationRule.FilterExpression and ValidationRule.TestExpression

    When you validate a diagram by calling the Validation.Validate method or by clicking Check Diagram on the Process tab, Visio will automatically use any validation logic stored in the document to detect errors. This validation logic is expressed in the ValidationRule.TargetType, ValidationRule.FilterExpression and ValidationRule.TestExpression properties. The FilterExpression and TestExpression should be written as Boolean expressions that can be evaluated on every object of type TargetType. During validation of a rule, for every object of type TargetType, Visio uses the FilterExpression to determine whether the object must satisfy the validation rule. If the filter expression evaluates to True, Visio uses the TestExpression to determine whether to generate an issue for the object. If the filter expression evaluates to False, Visio does not apply the validation rule to the object.

    The syntax for the FilterExpression and TestExpression properties are the same as that of a ShapeSheet expression (you can get more details here and here if you're unfamiliar with the ShapeSheet). For example, since NOT(IS1D()) is a valid Boolean expression for the ShapeSheet of a shape, "NOT(Is1D())" is a valid FilterExpression or TestExpression for a validation rule with TargetType = Visio.VisRuleTargets.visRuleTargetShape. In addition to the standard ShapeSheet functions, the following validation functions can be used in a FilterExpression or TestExpression.

    Function Description
    Role() Returns an integer indicating the shape role: {Element = 0, Connector = 1, Container = 2, Callout = 4}.
    OnLayer(LayerName) Returns a Boolean indicating whether the shape is a member of the specified layer. Returns a Boolean indicating whether layer exists on page if called on a Page.
    ConnectedShapes(Direction) Returns the set of shapes, matching the Direction criteria, connected to the shape.
    GluedShapes(Direction) Returns the set of shapes, matching the Direction criteria, glued to the shape.
    ContainerMembers() Returns the set of shapes that are members of the container / list shape.
    ListMembers() Returns the set of shapes that are members of the list shape.
    Callouts() Returns the set of shapes that are callouts on the shape.
    ParentContainers() Returns the set of containers that the shape belongs to.
    ShapesOnPage() Returns the set of top-level shapes on page. If no page specifier precedes the function, the shape’s containing page is assumed.
    AggCount(Set) Counts the number of shapes in a set.
    FilterSet(Set,FilterExpression) Returns the subset of shapes in a set that match an expression.
    OnBoundaryOf() Returns the set of containers such that the shape is on the boundary of these containers.

    The validation expression functions ConnectedShapes and GluedShapes correspond to connectivity API functions with the same names. Similarly, the possible values of the Direction input parameter for ConnectedShapes and GluedShapes correspond to the VisConnectedShapesFlags and VisGluedShapesFlags enumerations, respectively.

    Feedback welcome!

    We hope that this overview of the validation API provides the necessary details to start writing your own validation rules. We’re interested to hear what developers think of this API functionality, so please use the Send a Smile feedback tool or leave a comment below.

Page 1 of 1 (6 items)