Nesting Shapes

You can define a domain-specific language (DSL) in which one shape can be nested inside another. This lets you design DSLs that show diagrams similar to state charts. You have to write a small amount of customization code.

Defining a DSL that has Nested Shapes

This procedure creates shapes that can be nested to any depth.

To define a DSL that has nested shapes

  1. In the DSL Definition, create a class named OuterContainer, embedded under the root class.

  2. Create a class named Container, and in the Properties window, set its Inheritance Modifier to abstract. Container is not the target of an embedding.

  3. Set Container as the base class for OuterContainer. To do this: Click the Inheritance tool, click OuterContainer and then Container.

  4. Create a class named InnerContainer embedded under Container: Click the Embedding Relationship tool, click Container, and then click an empty part of the diagram.

    Set Container as the base class of InnerContainer: Click the Inheritance tool, click InnerContainer and then Container.

    (InnerContainer is now both derived from and embedded under Container.)

  5. Add a domain property named Title to Container and in the Properties window, set Is Name Element.

  6. Add a geometry shape, add a text decorator to the shape, and map both OuterContainer and InnerContainer to the shape. In the DSL Details window for each mapping, map the text decorator to the Title domain property.

  7. Add two element tools, and set the class of the tools to OuterContainer and InnerContainer. Set the icons of the tools.

  8. Select the diagram element map for InnerContainer. In the DSL Details window, in the General tab, check Has custom parent element.

  9. Click Transform All Templates in the toolbar of Solution Explorer.

  10. Build the solution. An error will be reported.

  11. In the Dsl project, create a new code file and add the following code:

    using Microsoft.VisualStudio.Modeling;
    namespace Company.NestedShapesSample // Change to your namespace
    {
     partial class FixUpDiagram 
     {
      private ModelElement GetParentForInnerContainer
            (InnerContainer exampleElement)  
      {
        return exampleElement.Parent;
    }}}
    

    For more information about customizing the model with program code, see Navigating and Updating a Model in Program Code.

  12. Build and run the solution.

  13. In the experimental instance of Visual Studio, drag the OuterContainer tool onto the diagram. Enlarge the shape.

  14. Drag the InnerContainer tool onto the OuterContainer shape. Notice that you cannot drop it onto the diagram, but only onto the OuterContainer.

  15. Enlarge the shape, and drag another InnerContainer in the previous element. Verify that when you move any shape, the shapes inside it also move.

To avoid having to create separate outer and inner tools, you can use the root of your model instead of OuterContainer.

You can also define reference links and map them to connectors.

Constraining the movement of nested shapes

At this stage, the nested shapes can be moved outside the container, and the size of the container can be reduced so that a child is left outside. You can constrain a nested shape to be inside its container.

Add the following code in a new code file:

using Microsoft.VisualStudio.Modeling.Diagrams;
namespace Company.NestedShapesSample // Change to your namespace.
{
  partial class ContainerShape 
  {
    /// <summary>
    /// Cannot move the children outside their children shape.
    /// Parent will always expand to enclose children.
    /// </summary>
    public override bool AllowsChildrenToResizeParent
    {
      get   {    return true;   }
    }
    /// <summary>
   /// Cannot shrink the parent shape if it would leave
   /// the child shapes outside the parent's boundary.
   /// </summary>
   public override SizeD MinimumResizableSize  
   {
     get { return this.CalculateMinimumSizeBasedOnChildren(); } }
}}

For more information about customizing the model with program code, see Navigating and Updating a Model in Program Code.

Collapsing Containers to Hide their Children

Add an Expand/Collapse decorator on ContainerShape.

Add the following code in the custom code file:

using Microsoft.VisualStudio.Modeling.Diagrams; ...
partial class ContainerShape
{
  /// <summary>
  /// Keeps the size of the expanded bounds of the shape
  /// </summary>
  protected RectangleD ExpandedBounds;
  /// <summary>
  /// Store the current bounds and set the size.
  /// </summary>
  protected override void Collapse()
  {
    base.Collapse();
    this.ExpandedBounds = this.Bounds;
    this.Bounds = this.AbsoluteBounds;
    this.AbsoluteBounds = new RectangleD
           (this.Location, new SizeD(1.5, 0.3));
  }
  /// <summary> 
  /// When we expand the shape, we restore the expanded bounds
  /// </summary>
  protected override void Expand()
  {
    base.Expand();
    this.Bounds = this.ExpandedBounds;
  }
}

See Also

Concepts

Navigating and Updating a Model in Program Code

Other Resources

Writing Code to Customise a Domain-Specific Language

Change History

Date

History

Reason

March 2011

Separated from parent topic.

Added samples.

Information enhancement.