DSL Tools #4 - Add and Change Rules

Extending the previous question about dynamical default values, there is a scenario on my domain model that requires a different approach to achieve the same kind of behavior.

The domain model includes an embedding relation between 2 domain properties:

Click to see full size image

This relation is presented to the user in the resulting model as a compartment, where Contract is a compartment shape and ContractProperty is a compartment named properties:

Click to see full size image

I wanted to achieve two special behaviors:

  • When adding a new property, if the user doesn't specify its name, then it should default to "Property".
  • When modifying the name of an existing property, if the user specifies a new empty name, it should also default to "Property".

Both behaviors can be achieved using two interesting constructs of the DSL Tools: Add Rules and Change Rules.

1. Create a new AddRule for the Property class

You need to create a class that derives from AddRule and specify the RuleOn attribute that defines to which domain class the rule should be applied.

This class should override the ElementAdded method that is always called when a new element of that domain class is created:

using System;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace MyModel.Processes
{
    /// <summary>
    /// Implements one add rule for the Property domain class.
    /// </summary>
    [RuleOn(typeof(Property), FireTime = TimeToFire.TopLevelCommit)]
    public class PropertyAddRule : AddRule
    {
        #region Public Methods

        public override void ElementAdded(ElementAddedEventArgs e)
        {
            // Validations

            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            // Ignore change

            if (GeneralHelper.IgnoreChange(e.ModelElement)) return;

            // Ensure the name is defined

            Property property = e.ModelElement as Property;
            if (property != null)
            {
                if (string.IsNullOrEmpty(property.Name))
                {
                    property.Name = Properties.Resources.Property;
                }
            }
        }

        #endregion

    }
}

2. Create a new ChangeRule for the Property Class

This is basically the same of the previous, except that this class should derive from ChangeRule:

using System;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace MyModel.Processes
{
    /// <summary>
    /// Provides change rules for the Property domain class.
    /// </summary>
    [RuleOn(typeof(Property), FireTime = TimeToFire.TopLevelCommit)]
    public class PropertyChangeRule : ChangeRule
    {
        #region Public Methods

        /// <summary>
        /// Raised when a property of the model element is changed.
        /// </summary>
        /// <param name="e">Event arguments.</param>
        public override void ElementPropertyChanged(
ElementPropertyChangedEventArgs e) { // Validations if (e == null) { throw new ArgumentNullException("e"); } // What property is being changed? if (e.DomainProperty.Id.Equals
(Property.NameDomainPropertyId)) { HandleNamePropertyChanged(e.ModelElement); } } #endregion #region Private Methods /// <summary> /// Invoked when the Name property of the model element
/// is changed.
/// </summary> /// <param name="modelElement">Model element being
/// changed.</param>
private void HandleNamePropertyChanged
(ModelElement modelElement) { // Ignore change? if (GeneralHelper.IgnoreChange(modelElement)) return; // Add a default value Property property = (Property)modelElement; if (string.IsNullOrEmpty(property.Name)) { property.Name = Properties.Resources.Property; } } #endregion } }

3. Add the 2 new custom types to the domain model definition

In order for these new custom classes to be recognized by the DSL Tools runtime environment you will need to customize another class.

So, I created a new partial class named BusinessProcessesDesignerDomainModel and added the implementation of GetCustomDomainModelTypes:

using System;

namespace MyModel.Processes
{
    /// <summary>
    /// Custom BusinessProcessesDesignerDomainModel methods.
    /// </summary>
    public partial class BusinessProcessesDesignerDomainModel
    {
        /// <summary>
        /// Returns the non-generated domain model types.
        /// </summary>
        /// <returns>An array of types.</returns>
        protected override Type[] GetCustomDomainModelTypes()
        {
            // Return the rules that should be evaluated for
// the model
return new System.Type[] { typeof(PropertyAddRule),
typeof(PropertyChangeRule) }; } } }

Notice that this class is defined in DomainModel.cs and will have a different name depending on the name of your domain model (property Name of the root DSL definition). Something like <YourDomainModelName>DomainModel.

Published 15 August 07 04:53 by hgr
Filed under: ,

Comments

# Hugo Ribeiro said on August 15, 2007 4:55 PM:

Last weekend I found some time to mess with the Microsoft DSL Tools to learn how this thing really works.

# Hugo Ribeiro said on July 15, 2008 6:43 PM:

Since I've been doing a number of posts on the DSL Tools, I thought it would be helpful to have a list

Anonymous comments are disabled