Dynamically create shapes

Hello,

Is there a way to dynamically create shapes. I would like to create a ModelElement on loading the .xyz designer. Is it possible to create multiple shapes / connectors on drag and drop of an element from the toolbox. In the ElementAdded method can I create shapes - do we have a method CreateModelElement() or API's to create model elements

Thanks,
Julian Jewel


Answer this question

Dynamically create shapes

  • Tyrion

    Alan,

    Thanks! That was very helpful. How do you create a Connection (in this example - Association) I have EntityA and EntityB. Should I use CreateAssociation() with the roletypes or is there a method like Connect(EntityA, EntityB);

    Or can I add the relationship into the model and automatically that would update the designer, showing the connection between EntityB->EntityA

    Thanks,
    Julian Jewel

  • UZone

    Is there an example of this not based on the "simple architecture chart" which appears not to exist now

    Thanks
    Tom

  • JayaK

    Here's some code I added to create a new element whenever a particular type of link is added.  It's added to Designer\Diagram\ViewFixupRules.cs. I inserted this after creating a new DSL solution from the "Simple Architecture Chart" prototype; the next thing I should do is add this code to ViewFixupRules.dslddt so that it doesn't get blown away when I next hit "Transform All Templates". 

    My addition is under /* Experimental code */.

    ViewFixupRules are responsible for making sure that the displayed diagram keeps in step with the underlying model. So when you create something in the model, it automatically appears in the diagram. (Warning: this may change in future, when diagrams can be partial views of a model.)

    So this code is inserted into the rule that "fixes up" the diagram when a new link of a specific type is created.  It creates a new model element, and initialises it with some attributes - most importantly, a name. (The attributes are of course as defined in the dsldm file; apart from the name attribute, which all elements inherit from NamedElement defined in Core.dsldm.) It then adds the new element to the root Architecture's list of Components: in the dslDD file, you can see that Architecture is the root of any diagram, and its Components list (ie the relation ArchitectureHasComponents) is the set of things that appear on the diagram.
     
    Many operations require "store" as a parameter; you can mostly get that from any convenient element that is to hand.



    /// <summary>

    /// Add a DependencyLink connector when its underlying relationship is created

    /// </summary>

    [RuleOn(typeof(ComponentIsDependentOn), FireTime = TimeToFire.TopLevelCommit, Priority = DiagramFixupConstants.AddShapeRulePriority)]

    internal sealed class ComponentIsDependentOnAddRule : AddRule

    {

       /// <summary>

       /// Called when a ComponentIsDependentOn relationship is created.

       /// </summary>

       /// <param name="e">Argument to event</param>

       public override void ElementAdded(ElementAddedEventArgs e)

       {

          ComponentIsDependentOn relationship = e.ModelElement as ComponentIsDependentOn;

          if (relationship != null)

          {

             IList roots = relationship.Store.ElementDirectory.GetElements(Architecture.MetaClassGuid);

             if (roots.Count == 1)

             {

                Architecture root = roots[0] as Architecture;

                if (root != null)

                {

                   Microsoft.VisualStudio.Modeling.Diagrams.Diagram.FixUpDiagram(root, relationship);

     

                   /* Experimental code */

                   // Grab store from any convenient element

                   Store store = relationship.Store;

                   // Create element and assign its attributes, especially Name

                   Framework extra = Framework.CreateFramework(store);

                   extra.Name = "ExtraFramework";

                   extra.MajorVersion = 1;

                   extra.MinorVersion = 2;

                   extra.ServicePack = 10;

                   // Make new element part of the model.

                   extra.Architecture = root;

                   // the above is equivalent to:  
    root.Components.Add(extra);

                   /* End experiment */

                  }

               }

            }

         }

      }



     


    To try this code after replacing the relevant function in ViewFixupRules.cs, hit F5 (*don't* do Transform All Templates!); open Empty.xyz in the resulting designer; drag a Framework and an OperatingSystem onto the drawing surface; and connect them with a Dependency link. Notice that this last action creates a new Framework.

  • happi.quan

    So, suppose you want that every time the user creates a Framework object (in the Simple Architecture Chart sample), an OperatingSystem node is created too, and they are linked using the Dependency link defined in the Domain Model.

    You add some code into ViewFixup.cs -- actually, you'd put it in the dslddt file -- that looks like this:


    #region Structural Rules

    [RuleOn(typeof(ArchitectureHasComponents), FireTime = TimeToFire.TopLevelCommit, Priority = DiagramFixupConstants.AddShapeRulePriority)]

    public sealed class ArchitectureHasComponentsAddRule : AddRule
    {  
       /// <summary>
       
    /// Called when a ArchitectureHasComponents association is created.
       /// </summary>
       
    /// <param name="e">Argument to event</param>
       
    public override void ElementAdded(ElementAddedEventArgs e)
       {
          
    ArchitectureHasComponents s = e.ModelElement as ArchitectureHasComponents;
          
    if (s.Components != null && s.Architecture != null)
          {
             Microsoft.VisualStudio.Modeling.Diagrams.
    Diagram.FixUpDiagram(s.Architecture, s.Components);

             
    /* Experimental code */
             
    // This code adds and connects an extra OperatingSystem node whenever you create a Framework.
             
    if (s.Components is Framework)
                
    // Don't be fooled by the plural! Although the rolename is Component*s*, each individual link only has one ModelElement at the end of it.
             
    {
                
    // Grab store from any convenient element
                
    Store store = s.Store;

                
    // Create extra element and assign its attributes, especially Name
                
    CompanyName.ProjectName.Language34.DomainModel.OperatingSystem extra = 
                   
    // fully qualified name here because "OperatingSystem" is also the name of some other type
                  
    CompanyName.ProjectName.Language34.DomainModel.OperatingSystem.CreateOperatingSystem(store);
                extra.Name =
    "ExtraOS";
                extra.MajorVersion = 1;
                extra.MinorVersion = 2;
                extra.ServicePack = 10;
                
                
    // Add the new element under the root of the model
                
    extra.Architecture = s.Architecture;
                
                
    // Connect the new element to the Framework using a relation defined in the DM
                
    extra.DependentOn = s.Components;
             }
             
    /* End experiment */
          
    }
       }
    }
    #endregion

     

    Once again, the statutory warning that we're working with a Preview release here, so nothing is yet guaranteed to stay the same.

    Q. Why don't we use the OnCreated() handler on the Framework, like we did with Architecture above

    A. 'Cos it don't work too well. The advantage of the rules is that they fire after everything is in a consistent state.  In the other case, it just happens to be OK and easier; but in general, it's best to create rules to handle changes.



  • Aton A

  • CrioGreen

    No, it's simpler than that. If your DM says:
         (Passenger)
          |-----Rides-1>|*|-----(Car)

    then you can do things like:

       aPassenger.Rides = aCar;


    If your association is a multiple in the direction you're interested in, for example:
       (Person)
          |----------Likes--*>|*|-----(Thing)

    then you can write:

       aPerson.Likes.Add(aThing);

    You can alternatively set up the links in reverse - for example,

       aCar.RiddenBy.Add(aPassenger)

    is the same as the line above, presuming "RiddenBy" is the reverse role of "Rides". (To see the name of the reverse role in the DM editor, click on the rectangular role symbol -- it's a bit difficult sometimes unless you zoom in a bit -- and look at the name in the properties grid.)

  • abbasshaikh

    You also ask how to automatically add an item when a diagram is loaded (do you mean created - rather than every time it's loaded )

    You can add something like this in a separate file, or append it to DomainModel\DomainModelExtras.dsldmt. This example was added to a solution initially created from the Simple Architecture Chart prototype; Architecture is the name of the language root class, and Computer is one of the concept classes.



    public partial class Architecture
    {
       ///<summary>Invoked once when a new model is created. 
       /// This class is the root of the language.
       ///</summary>
       public override void OnInitialized()
       {
          base.OnInitialized();

          // Create an object to be automatically added to the new model.
          
    Computer primary = Computer.CreateComputer(this.Store);

          // Set its attributes (as defined in the .dslDM, plus Name)
          primary.Name = "PrimaryComputer";
          primary.HardDiskSize = 50;
          primary.HardDiskSizeUnit =
    StorageSize.GB;
          primary.MemorySize = 500;
          primary.MemorySizeUnit =
    StorageSize.MB;

          // link the new item to the root of the model
          primary.Architecture = this;
       }
    }

     


    This will fire only when the model is initially created - not when it's loaded after saving. If you really want to create a new thing every time the model is loaded, override OnCreated() instead.


    BTW, OnCreated and OnInitialized are often not too useful -- they don't fire at the right times to do the right things on the diagram. The good thing about the rule-based approach is that the rules fire after all the changes in the model have completed.



  • Dynamically create shapes