<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Hugo Ribeiro's Blog</title>
	
	<link>http://hugoribeiro.blog.com</link>
	<description>Software architecture, model-driven development, and a few other things</description>
	<lastBuildDate>Thu, 23 Dec 2010 18:51:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2-bleeding</generator>
	
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/HugoRibeiro" /><feedburner:info uri="hugoribeiro" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://hugoribeiro.blog.com/?pushpress=hub" /><geo:lat>41.55377</geo:lat><geo:long>8.4338</geo:long><creativeCommons:license>http://creativecommons.org/licenses/by-sa/2.0/</creativeCommons:license><image><link>http://creativecommons.org/licenses/by-sa/2.0/</link><url>http://creativecommons.org/images/public/somerights20.gif</url><title>Some Rights Reserved</title></image><item>
		<title>DSL Tools #23 – Preventing Repeated Names</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/j39iJMEpWvM/</link>
		<comments>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-23-preventing-repeated-names/#comments</comments>
		<pubDate>Thu, 23 Dec 2010 18:48:50 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/12/23/dsl-tools-23-preventing-repeated-names/</guid>
		<description><![CDATA[Even more interesting than validating user errors is to prevent him from doing those errors. You can prevent the user from creating two model elements with the same name using custom change rules. That is, when the user tries to change the name of an element to the same name of another existing element, you [...]]]></description>
			<content:encoded><![CDATA[<p>Even more interesting than validating user errors is to prevent him from doing those errors.</p>
<p>You can prevent the user from creating two model elements with the same name using <a href="http://hugoribeiro.blog.com/2007/08/15/dsl-tools-4-add-and-change-rules/" target="_blank">custom change rules</a>. That is, when the user tries to change the name of an element to the same name of another existing element, you just show him a message and rollback the current modeling transaction so the name rolls back to its previous (valid) value.</p>
<p>This is very easy to achieve using the NamedElement domain class I’ve been talking about and the extension methods described in the <a href="http://hugoribeiro.blog.com/2010/12/23/dsl-tools-22-validating-repeated-names/" target="_blank">previous post</a>.</p>
<p><strong>1. Add the Change Rule to NamedElement</strong></p>
<p>This rule acts on any change to the Name property:</p>
<pre>using System;
using Microsoft.VisualStudio.Modeling;

namespace Experimental.Library
{
    /// &lt;summary&gt;
    /// Defines a change rule for the Entity domain class.
    /// &lt;/summary&gt;
    [RuleOn(typeof(NamedElement), FireTime = TimeToFire.TopLevelCommit)]
    public class NamedElementChangeRule : ChangeRule
    {
        #region Public Methods

        /// &lt;summary&gt;
        /// Alerts listeners that a property for an element has changed.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;e&quot;&gt;Provides data for the ElementPropertyChanged event.&lt;/param&gt;
        public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
        {
            // Validate arguments

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

            // Property being changed

            if (e.DomainProperty.Id.Equals(NamedElement.NameDomainPropertyId))
            {
                this.HandleNameChange(e);
            }

            // Default behavior

            base.ElementPropertyChanged(e);
        }

        #endregion

        #region Private Methods

        /// &lt;summary&gt;
        /// When the Name property changes.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;e&quot;&gt;The &lt;see cref=&quot;Microsoft.VisualStudio.Modeling.ElementPropertyChangedEventArgs&quot;/&gt; instance containing the event data.&lt;/param&gt;
        private void HandleNameChange(ElementPropertyChangedEventArgs e)
        {
            // Ignore change?

            if (RuleHelper.IgnoreChange(e.ModelElement))
            {
                return;
            }

            // Something changed?

            string oldName = (string)e.OldValue;
            string newName = (string)e.NewValue;

            if ((string.IsNullOrEmpty(oldName) &amp;&amp; !string.IsNullOrEmpty(newName)) ||
                (!newName.Equals(oldName, StringComparison.CurrentCulture)))
            {
                RuleHelper.PreventRepeatedName&lt;NamedElement&gt;(e.ModelElement as NamedElement, newName, oldName);
            }
        }

        #endregion
    }
}</pre>
<p>Here I’m using a static helper method (PreventRepeatedName) so that I can share this behavior between NamedElement and ReadOnlyNamedElement.</p>
<p><strong>2. Implement the Rule Logic</strong></p>
<p>The custom logic goes into PreventRepeatedName and it involves basically getting the siblings of the element that is being modified and checking if any of them has the same name. When that occurs, I just rollback the current transaction and show an error message to the user.</p>
<pre>/// &lt;summary&gt;
/// Checks if the specified model element has any sibling with the same name. If so it rolls back
/// the current transaction and shows a message to the user.
/// &lt;/summary&gt;
/// &lt;typeparam name=&quot;T&quot;&gt;The type of the model element.&lt;/typeparam&gt;
/// &lt;param name=&quot;modelElement&quot;&gt;The model element whose name will be checked.&lt;/param&gt;
/// &lt;param name=&quot;newName&quot;&gt;The new name of the model element.&lt;/param&gt;
/// &lt;param name=&quot;oldName&quot;&gt;The old name of the model element.&lt;/param&gt;
/// &lt;remarks&gt;
/// This method is designed to be called from a change rule on the Name property of the
/// model element.
/// &lt;/remarks&gt;
public static void PreventRepeatedName&lt;T&gt;(T modelElement, string newName, string oldName)
    where T : ModelElement, INamedModelElement
{
    // Validation

    if (modelElement == null)
    {
        throw new ArgumentNullException(&quot;modelElement&quot;);
    }

    // Domain class

    DomainClassInfo domainClass = modelElement.GetDomainClass();

    // Get the siblings for this element

    IEnumerable&lt;T&gt; siblings = modelElement.GetSiblings&lt;T&gt;();
    if (siblings != null)
    {
        // Search any element that has the same name

        foreach (T sibling in siblings)
        {
            if (sibling.Name.Equals(modelElement.Name, StringComparison.CurrentCulture))
            {
                // Rollback transaction to cancel change

                modelElement.Store.TransactionManager.CurrentTransaction.Rollback();

                // Show message

                string message = string.Format(CultureInfo.CurrentCulture, &quot;Cannot change {0} name from '{1}' to '{2}'. Another element with that name already exists in the model. The change was cancelled.&quot;, domainClass.DisplayName, oldName, newName);
                Dialogs.ShowWarning(&quot;Element Name...&quot;, message);
                return;
            }
        }
    }
}</pre>
<p>Notice that this shows a technique of rolling back changes by rolling back the current transaction which is much better than modifying the Name property to its previous value, which, in turn, will trigger the rule again. It is better in this case but you should be ware that rules in the DSL Tools are cascading, in the sense that a change rule can be triggered by other rules and/or custom code that modifies the related property. When the current transaction is rollback, ALL changes to the model will be rolled back, not only the change to the property evaluated by the change rule.</p>
<p><strong>3. Build All</strong></p>
<p>Then you’ll just need to build the library, all dependent DSL projects and it’s done. No more repeated names in elements of the same type.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/Validation02.PNG" width="416" height="265" /></p>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-23-preventing-repeated-names/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-23-preventing-repeated-names/</feedburner:origLink></item>
		<item>
		<title>DSL Tools #22 – Validating Repeated Names</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/pe3mA6GyXJ4/</link>
		<comments>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-22-validating-repeated-names/#comments</comments>
		<pubDate>Thu, 23 Dec 2010 18:48:26 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/12/23/dsl-tools-22-validating-repeated-names/</guid>
		<description><![CDATA[When you have model elements with names the next thing you will probably need is to prevent the user from having two elements of the same type with the same name. The first way to prevent this is by presenting validation errors when that happens. And that can be easily implemented when you have a [...]]]></description>
			<content:encoded><![CDATA[<p>When you have <a href="http://hugoribeiro.blog.com/2010/12/20/dsl-tools-20-dsllibraries/" target="_blank">model elements with names</a> the next thing you will probably need is to prevent the user from having two elements of the same type with the same name.</p>
<p>The first way to prevent this is by presenting validation errors when that happens. And that can be easily implemented when you have a DslLibrary that defines the NamedElement (and ReadOnlyNamedElement for that matter).</p>
<p>Assuming that you know how to implement <a href="http://hugoribeiro.blog.com/2007/08/16/dsl-tools-5-implementing-custom-validations/" target="_blank">validation rules</a>, the steps are the following:</p>
<p><strong>1. Add a Validation Method to the NamedElement domain class in the DslLibrary</strong></p>
<p>The code is quite simple and it will be triggered when the Name is defined (there is another validation rule that is triggered when that is not defined):</p>
<pre>/// &lt;summary&gt;
/// Name cannot be repeated between siblings.
/// &lt;/summary&gt;
/// &lt;param name=&quot;context&quot;&gt;The validation context.&lt;/param&gt;
[ValidationMethod(ValidationCategories.Menu | ValidationCategories.Open | ValidationCategories.Save)]
private void ValidateRepeatedNames(ValidationContext context)
{
    // Name is defined?

    if (!string.IsNullOrEmpty(this.Name))
    {
        ValidationHelper.ValidateRepeatedNames&lt;NamedElement&gt;(context, this, ValidationError);
    }
}</pre>
<p><strong>2. Implement the Validation Logic</strong></p>
<p>I have created a more generic validation logic that can be shared between NamedElement and ReadOnlyNamedElement. It goes to the ValidateRepeatedNames method in a ValidationHelper static class.</p>
<p>Basically it involves getting all the siblings elements of the model element that is being validated and checking if any of them has the same as the current element. Siblings are model elements of the same type of the current element that are involved in the same embedding relationship as that element.</p>
<pre>/// &lt;summary&gt;
/// Checks if the specified model element name is repeated in the containing embedding relationship.
/// &lt;/summary&gt;
/// &lt;typeparam name=&quot;T&quot;&gt;The type of the model element.&lt;/typeparam&gt;
/// &lt;param name=&quot;context&quot;&gt;The validation context.&lt;/param&gt;
/// &lt;param name=&quot;modelElement&quot;&gt;The model element that should be validated.&lt;/param&gt;
/// &lt;param name=&quot;validationCode&quot;&gt;The validation error code.&lt;/param&gt;
/// &lt;remarks&gt;
/// This method is designed to be called from a validation method of the model element domain class.
/// &lt;/remarks&gt;
public static void ValidateRepeatedNames&lt;T&gt;(ValidationContext context, T modelElement, string validationCode)
    where T : ModelElement, INamedModelElement
{
    // Validation

    if (context == null)
    {
        throw new ArgumentNullException(&quot;context&quot;);
    }

    if (modelElement == null)
    {
        throw new ArgumentNullException(&quot;modelElement&quot;);
    }

    // Get the domain class

    DomainClassInfo domainClass = modelElement.GetDomainClass();

    // Get the siblings

    IEnumerable&lt;NamedElement&gt; siblings = modelElement.GetSiblings&lt;NamedElement&gt;();
    if (siblings != null)
    {
        // Search for any other element that has the same name

        IEnumerable&lt;NamedElement&gt; repeated = from sibling in siblings
                                                where sibling.Name.Equals(modelElement.Name, StringComparison.CurrentCulture)
                                                select sibling;
        if (repeated != null)
        {
            int count = repeated.Count();

            if (count &gt; 0)
            {
                string error = string.Format(CultureInfo.CurrentCulture, &quot;{0} name '{1}' is repeated {2} times.&quot;, domainClass.DisplayName, modelElement.Name, count + 1);
                context.LogError(error, validationCode, modelElement);
            }
        }
    }
}</pre>
<p>Notice that this generic method enforces a type rule that requires type T to implement the INamedModelElement interface. This is a custom interface – shared by NamedElement and ReadOnlyNamedElement – created to define common behavior – the Name property in this case – between both classes.</p>
<p>The interfaces involved are the following:</p>
<pre>using System;

namespace Experimental.Library
{
    /// &lt;summary&gt;
    /// Defines the interface of a model element.
    /// &lt;/summary&gt;
    public interface IModelElement
    {
        #region Properties

        /// &lt;summary&gt;
        /// The identifier of the model element.
        /// &lt;/summary&gt;
        Guid Id
        {
            get;
        }

        #endregion
    }
}</pre>
<pre>using System;

namespace Experimental.Library
{
    /// &lt;summary&gt;
    /// Defines the interface of a named model element.
    /// &lt;/summary&gt;
    public interface INamedModelElement : IModelElement
    {
        #region Properties

        /// &lt;summary&gt;
        /// The name of the model element.
        /// &lt;/summary&gt;
        string Name
        {
            get;
            set;
        }

        #endregion
    }
}</pre>
<p>To have the NamedElement and ReadOnlyNamedElement implement them requires only that you add a partial class for each of them to your DslLibrary project:</p>
<pre>using System;

namespace Experimental.Library
{
    /// &lt;summary&gt;
    /// Defines custom code for the NamedElement domain class.
    /// &lt;/summary&gt;
    public partial class NamedElement : INamedModelElement
    {
    }
}</pre>
<pre>using System;

namespace Experimental.Library
{
    /// &lt;summary&gt;
    /// Defines custom code for the ReadOnlyNamedElement domain class.
    /// &lt;/summary&gt;
    public partial class ReadOnlyNamedElement : INamedModelElement
    {
    }
}</pre>
<p><strong>3. Build All</strong></p>
<p>Then you’ll just need to build the library, all dependent DSL projects and it’s done. No more repeated names in elements of the same type.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/Validation01.PNG" width="374" height="43" /> </p>
<p><strong>The Magic</strong></p>
<p>The actual magic in this same is done with some extension methods to the ModelElement class that add two interesting features to the DSL Tools. One is the ability to get “the model element that contains a given model element” (GetContainer) and the other is the ability of “given a model element, getting all the other sibling model elements in an embedding relationship” (GetSiblings).</p>
<p>Here is the code for those extensions:</p>
<pre>using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.VisualStudio.Modeling;

namespace Experimental.Core.Extensions
{
    /// &lt;summary&gt;
    /// Provides extension methods for the ModelElement class.
    /// &lt;/summary&gt;
    public static class ModelElementExtensions
    {
        #region Public Methods

        /// &lt;summary&gt;
        /// Gets the model element that contains this model element in an embedding relationship.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;element&quot;&gt;The model element whose container will be returned.&lt;/param&gt;
        /// &lt;returns&gt;The model element that contains this model element in an embedding relationship.&lt;/returns&gt;
        /// &lt;remarks&gt;Returns null if there is not container.&lt;/remarks&gt;
        public static ModelElement GetContainer(this ModelElement element)
        {
            // Validation

            if (element == null)
            {
                throw new ArgumentNullException(&quot;element&quot;);
            }

            // Get the embedding domain role

            DomainRoleInfo embeddedDomainRole = GetEmbeddingDomainRole(element);
            if (embeddedDomainRole != null)
            {
                // Opposite domain role

                DomainRoleInfo oppositeDomainRole = embeddedDomainRole.OppositeDomainRole;

                // Get the container

                ReadOnlyCollection&lt;ElementLink&gt; elementLinks = embeddedDomainRole.GetElementLinks(element);
                if (elementLinks != null &amp;&amp; elementLinks.Count &gt; 0)
                {
                    return oppositeDomainRole.GetRolePlayer(elementLinks[0]);
                }
            }

            // Default result

            return null;
        }

        /// &lt;summary&gt;
        /// Gets the model element that contains this model element in an embedding relationship.
        /// &lt;/summary&gt;
        /// &lt;typeparam name=&quot;T&quot;&gt;The type of the container model element.&lt;/typeparam&gt;
        /// &lt;param name=&quot;element&quot;&gt;The model element whose container will be returned.&lt;/param&gt;
        /// &lt;returns&gt;The model element that contains this model element in an embedding relationship.&lt;/returns&gt;
        /// &lt;remarks&gt;Returns null if there is no container or if the container is not of the specified type.&lt;/remarks&gt;
        public static T GetContainer&lt;T&gt;(this ModelElement element)
            where T : ModelElement
        {
            return GetContainer(element) as T;
        }

        /// &lt;summary&gt;
        /// Gets all the model elements that are siblings in an embedding relationship of the specified model element.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;element&quot;&gt;The model element whose siblings will be returned.&lt;/param&gt;
        /// &lt;returns&gt;All the model elements that are siblings in an embedding relationship of the specified model element.&lt;/returns&gt;
        /// &lt;remarks&gt;Returns null if the specified element is not part of any embedding relationship (has no container).&lt;/remarks&gt;
        public static IEnumerable&lt;ModelElement&gt; GetSiblings(this ModelElement element)
        {
            // Validation

            if (element == null)
            {
                throw new ArgumentNullException(&quot;element&quot;);
            }

            // Get the container and the embedding domain role

            ModelElement container = element.GetContainer();
            DomainRoleInfo embeddedDomainRole = GetEmbeddingDomainRole(element);

            // Continue?

            if (container != null &amp;&amp; embeddedDomainRole != null)
            {
                // Get all the elements contained by container

                LinkedElementCollection&lt;ModelElement&gt; linkedElements = embeddedDomainRole.OppositeDomainRole.GetLinkedElements(container);

                // Ignore the specified element and return

                IEnumerable&lt;ModelElement&gt; result = from linkedElement in linkedElements
                                                   where !linkedElement.Id.Equals(element.Id)
                                                   select linkedElement;
                return result;
            }

            // Default result

            return null;
        }

        /// &lt;summary&gt;
        /// Gets all the model elements that are siblings in an embedding relationship of the specified model element.
        /// &lt;/summary&gt;
        /// &lt;typeparam name=&quot;T&quot;&gt;The type of the siblings model elements.&lt;/typeparam&gt;
        /// &lt;param name=&quot;element&quot;&gt;The model element whose siblings will be returned.&lt;/param&gt;
        /// &lt;returns&gt;All the model elements that are siblings in an embedding relationship of the specified model element.&lt;/returns&gt;
        /// &lt;remarks&gt;Returns null if the specified element is not part of any embedding relationship (has no container).&lt;/remarks&gt;
        public static IEnumerable&lt;T&gt; GetSiblings&lt;T&gt;(this ModelElement element)
            where T : ModelElement
        {
            return GetSiblings(element).Cast&lt;T&gt;();
        }

        #endregion

        #region Private Methods

        /// &lt;summary&gt;
        /// Gets the domain role that defines the specified model element as the target of an embedding relationship.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;element&quot;&gt;The model element whose embedding domain role will be returned.&lt;/param&gt;
        /// &lt;returns&gt;The domain role that defines the specified model element as the target of an embedding relationship.&lt;/returns&gt;
        private static DomainRoleInfo GetEmbeddingDomainRole(ModelElement element)
        {
            // Validation

            if (element == null)
            {
                throw new ArgumentNullException(&quot;element&quot;);
            }

            // Get the domain class

            DomainClassInfo domainClass = element.GetDomainClass();
            if (domainClass != null)
            {
                // All domain roles played

                ReadOnlyCollection&lt;DomainRoleInfo&gt; allDomainRolesPlayed = domainClass.AllDomainRolesPlayed;

                // Get the container

                int count = allDomainRolesPlayed.Count;
                for (int i = 0; i &lt; count; i++)
                {
                    DomainRoleInfo embeddedDomainRole = allDomainRolesPlayed[i];
                    DomainRoleInfo oppositeDomainRole = embeddedDomainRole.OppositeDomainRole;

                    if (oppositeDomainRole.IsEmbedding)
                    {
                        return embeddedDomainRole;
                    }
                }
            }

            // Default result

            return null;
        }

        #endregion
    }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-22-validating-repeated-names/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-22-validating-repeated-names/</feedburner:origLink></item>
		<item>
		<title>DSL Tools #21 – Default Names for Read-only Named Elements</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/E9soneK2who/</link>
		<comments>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-21-default-names-for-read-only-named-elements/#comments</comments>
		<pubDate>Thu, 23 Dec 2010 18:48:06 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/12/23/dsl-tools-21-default-names-for-read-only-named-elements/</guid>
		<description><![CDATA[Continuing the “saga” of having model elements with name properties, there is an interesting behavior that the DSL Tools will offer you at no cost. As soon as you specify a domain property (Name in this case) to be the element name, when you add a class of that type to the diagram, the DSL [...]]]></description>
			<content:encoded><![CDATA[<p>Continuing the “saga” of <a href="http://hugoribeiro.blog.com/2010/12/20/dsl-tools-20-dsllibraries/" target="_blank">having model elements with name properties</a>, there is an interesting behavior that the DSL Tools will offer you at no cost.</p>
<p>As soon as you specify a domain property (Name in this case) to be the element name, when you add a class of that type to the diagram, the DSL Tools will generate a default name based on the existing classes of that type (through the ElementNameProvider class). For example, if you have a domain class called Entity and that class includes a domain property marked with “Is Element Name” the value of that property will be by default Entity1, Entity2, and so forth. This will also work for my NamedElement abstract domain class, meaning that you can share that behavior along with sharing the Name property.</p>
<p>So far so good but there is a problem with the ReadOnlyNamedElement because the Name property in that class is marked with “Is UI Read Only” and in that case the default name will not be generated. I suppose that the default implementation assumes that if the user cannot change that value in the designer, there is no reason to generate a default name as it will probably be created by custom code.</p>
<p>Although that is reasonable, I still want a default name to prevent validation errors relating with the class name before the user as the possibility of defining the other domain property(ies) that will change the name.</p>
<p>There is a simple customization that you can do to override this default behavior. Here’s how you can do it in the DslLibrary so that it affects all classes that will derive from ReadOnlyNamedElement.</p>
<p><strong>1. Create the Custom Element Name Provider</strong></p>
<p>First you will need to create a custom element name provider and have inherit from ElementNameProvider. In this case I will name it ReadOnlyNamedElementNameProvider.</p>
<p>In this new class just override SetUniqueNameCore and implement the logic to generate the default name.</p>
<pre>using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Design;

namespace Experimental.Library
{
    /// &lt;summary&gt;
    /// Provides a custom element name provider for the ReadOnlyNamedElement domain class.
    /// &lt;/summary&gt;
    public class ReadOnlyNamedElementNameProvider : ElementNameProvider
    {
        #region Protected Methods

        /// &lt;summary&gt;
        /// Sets a unique name for the model element based on the base name.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;element&quot;&gt;The model element.&lt;/param&gt;
        /// &lt;param name=&quot;baseName&quot;&gt;The base name.&lt;/param&gt;
        /// &lt;param name=&quot;siblingNames&quot;&gt;The names in use by sibling model elements.&lt;/param&gt;
        protected override void SetUniqueNameCore(ModelElement element, string baseName, IDictionary&lt;string, ModelElement&gt; siblingNames)
        {
            // Is it a ReadOnlyNamedElement?

            ReadOnlyNamedElement namedElement = element as ReadOnlyNamedElement;
            if (namedElement != null)
            {
                // Get the last number in use

                int lastNumber = 0;

                foreach (string name in siblingNames.Keys)
                {
                    if (name.StartsWith(baseName, StringComparison.CurrentCulture))
                    {
                        string sufix = name.Remove(0, baseName.Length);

                        int value = 0;
                        if (int.TryParse(sufix, NumberStyles.Integer, CultureInfo.CurrentCulture, out value))
                        {
                            lastNumber = value;
                        }
                    }
                }

                // Update the name

                string defaultName = baseName + (++lastNumber).ToString(CultureInfo.CurrentCulture);
                namedElement.Name = defaultName;

                return;
            }

            // Default behavior

            base.SetUniqueNameCore(element, baseName, siblingNames);
        }

        #endregion
    }
}</pre>
<p>Note that I’ve designed this class so that it will only do something different from the default implementation if it is applied to a ReadOnlyNamedElement.</p>
<p><strong>2. Register the External Type</strong></p>
<p>Before you can use this new type in the DslLibrary model you will need to register it:</p>
<ol>
<li>Open DslDefinition.dsl. </li>
<li>Select the root node in the DSL Explorer. </li>
<li>Select “Add New External Type” from the context menu. This will create a new node under “Domain Types”. </li>
<li>Select that node and, in the properties window, set the Name (equal to the class name) and the Namespace. </li>
</ol>
<p><img src="http://dl.dropbox.com/u/140742/Blog/ElementNameProvider01.PNG" width="321" height="344" /></p>
<p><strong>3. Specify the Custom Element Name Provider</strong></p>
<p>Now select the Name property of the domain class in the DSL designer – ReadOnlyNameElement in this case. In the properties window, for the “Element Name Provider” property chose the external type that you created from the list.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/ElementNameProvider02.PNG" width="298" height="154" /></p>
<p><strong>4. Transform All &amp; Re-build</strong></p>
<p>To finish you will need to transform all templates in the DSL Library, rebuild it and rebuild all dependent DSL projects. Now you have a default name even for domain classes where the name domain property is read-only.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/ElementNameProvider03.PNG" width="180" height="154" /></p>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-21-default-names-for-read-only-named-elements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/12/23/dsl-tools-21-default-names-for-read-only-named-elements/</feedburner:origLink></item>
		<item>
		<title>DSL Tools #20 – DslLibraries</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/ZCAHM2Lu_7I/</link>
		<comments>http://hugoribeiro.blog.com/2010/12/20/dsl-tools-20-dsllibraries/#comments</comments>
		<pubDate>Mon, 20 Dec 2010 18:56:05 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/12/20/dsl-tools-20-dsllibraries/</guid>
		<description><![CDATA[DslLibraries are a great new feature of the DSL Tools that can be used to share model concepts and behavior between different DSL models. If you want to learn the basics about DslLibraries check this article: Sharing Classes between DSLs by using a DSL Library. One common behavior that all the DSL models that I’ve [...]]]></description>
			<content:encoded><![CDATA[<p>DslLibraries are a great new feature of the DSL Tools that can be used to share model concepts and behavior between different DSL models.</p>
<p>If you want to learn the basics about DslLibraries check this article: <a href="http://msdn.microsoft.com/en-us/library/ff521396.aspx" target="_blank">Sharing Classes between DSLs by using a DSL Library</a>.</p>
<p>One common behavior that all the DSL models that I’ve created have is this concept that most domain classes have one property called Name. In some cases I let the user specify it, in other cases I don’t because the element name is derived from another domain property.</p>
<p>A good implementation of such common behavior can be achieve using a simple DslLibrary and it involves creating two domain classes – NamedElement and ReadOnlyNamedElement – that are used as the base classes for all the specific domain classes where I want to have that behavior.</p>
<p>Here’s how you can implement such a thing easily.</p>
<p><strong>1. Create the DslLibrary</strong></p>
<p>First you will need to create a new project for the DslLibrary.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/DslLibrary01.PNG" width="450" height="312" /></p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/DslLibrary02.PNG" width="450" height="283" /></p>
<p>Be careful with the language name and with the root namespace that you specify in this wizard. These will be used when you import the library in your DSL models.</p>
<p><strong>2. Model the Base Classes</strong></p>
<p>Open the DslDefinition.dsl file and model the two abstract domain classes: NamedElement and ReadOnlyNamedElement.</p>
<p>NOTE: The Name domain property of the ReadOnlyNamedElement should have the “Is UI Read Only” property set to true.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/DslLibrary03.PNG" width="300" height="195" /></p>
<p><strong>3. Transform All &amp; Build</strong></p>
<p>Finish the library definition by running “Transform All Templates” and building the project. This will generate the assembly for your model, which will be required by each DSL that references this library.</p>
<p><strong>4. Import the DslLibrary</strong></p>
<p>The next step is to open each DSL that will use the domain classes defined in the library and importing it.</p>
<p>To do that you should open the DslDefinition.dsl file, go to the DSL Explorer, select the root node in the tree (corresponding to the model root) and select “Add New Dsl Library Import”.</p>
<p>This will create a new node under “Dsl Library Imports”. Select it and point the “File Path” property to the DslDefinition.dsl file of the DslLibrary project.</p>
<p>At this point you can reference the domain classes defined in the library in the current DSL definition.</p>
<p><strong>5. Change the Model</strong></p>
<p>In one particular model where I wanted to implement this “named element behavior” I have the following domain classes:</p>
<ul>
<li>Entity – that should derive from NamedElement (so the user can edit the entity name). </li>
<li>Module Reference – that should derive from ReadOnlyNamedElement (so that the name is read-only). </li>
</ul>
<p>At this point, the next step is to define the correct base class for each of these domain classes. To do that:</p>
<ol>
<li>Select the domain class in the DSL diagram. </li>
<li>Modify the “Base Class” property and select the correct base class (from the DslLibrary). </li>
</ol>
<p><img src="http://dl.dropbox.com/u/140742/Blog/DslLibrary04.PNG" width="250" height="207" /></p>
<p><strong>6. Transform All &amp; Build</strong></p>
<p>Finally, you need to transform all templates and build your DSL.</p>
<p>After transforming templates you will notice references to your DslLibrary project. For example, if you search for the Entity class in the DomainClasses.cs generated file, you will see that class implementing NamedElement from your library. Something like this:</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/DslLibrary05.PNG" width="350" height="150" /></p>
<p>If you compile your project at this moment you will see that a reference is missing to the DslLibrary assembly. Add that reference to your Dsl and DslPackage projects and you’re set.</p>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/12/20/dsl-tools-20-dsllibraries/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/12/20/dsl-tools-20-dsllibraries/</feedburner:origLink></item>
		<item>
		<title>DSL Tools #19 – Validate Model Before Generating Code</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/wiQmscmU-kg/</link>
		<comments>http://hugoribeiro.blog.com/2010/12/11/dsl-tools-19-validate-model-before-generating-code/#comments</comments>
		<pubDate>Sat, 11 Dec 2010 19:15:35 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[Code Generation]]></category>
		<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/12/11/dsl-tools-19-validate-model-before-generating-code/</guid>
		<description><![CDATA[The whole purpose of the DSL Tools models is to have code generators (T4 text templates) that generate code from them. One thing that the default implementation of the DSL Tools doesn’t do is to validate the model before executing the actual code generation. But the infrastructure is there to implement it quite easily, although [...]]]></description>
			<content:encoded><![CDATA[<p>The whole purpose of the DSL Tools models is to have code generators (T4 text templates) that generate code from them.</p>
<p>One thing that the default implementation of the DSL Tools doesn’t do is to validate the model before executing the actual code generation. But the infrastructure is there to implement it quite easily, although it may very easy to miss it in the documentation.</p>
<p>My simple model includes a very simple custom validation (see <a href="http://hugoribeiro.blog.com/2007/08/16/dsl-tools-5-implementing-custom-validations/" target="_blank">this post</a> if you need help with implementing custom validations):</p>
<pre>[ValidationMethod(ValidationCategories.Menu | ValidationCategories.Open | ValidationCategories.Save)]
private void ValidateReservedNames(ValidationContext context)
{
    string[] reservedNames = { &quot;Entity&quot;, &quot;BusinessEntity&quot; };

    if (reservedNames.Contains(this.Name))
    {
        string error = string.Format(CultureInfo.CurrentCulture, &quot;Entity '{0}' name is reserved.&quot;, this.Name);
        context.LogError(error, ValidationError, this);
    }
}</pre>
<p>Then I have a very simple text template that generates a XML file from it.</p>
<pre>&lt;#@ ExEntitiesModel processor=&quot;ExEntitiesModelDirectiveProcessor&quot;
	requires=&quot;fileName='ExEntitiesModel.entitiesModel'&quot;#&gt;
&lt;#@ template inherits=&quot;Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation&quot; debug=&quot;true&quot;#&gt;
&lt;#@ output extension=&quot;.xml&quot; #&gt;
&lt;#@ import namespace = &quot;Experimental.Entities&quot; #&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;entities&gt;
&lt;#
foreach (Entity entity in this.ExEntitiesModelRoot.Entities)
{
#&gt;
	&lt;entity name=&quot;&lt;#= entity.Name #&gt;&quot;&gt;
	&lt;/entity&gt;
&lt;#
}
#&gt;
&lt;/entities&gt;</pre>
<p>Now imagine that the code generation is a lot more complex and that it really requires the model to be valid before even trying to generate anything.</p>
<p>To do that you just need to modify the directive processor requires parameter to include the “Validation” parameter. This parameter should specify the validation category (ValidationCategories enum) that should be considered:</p>
<pre>&lt;#@ ExEntitiesModel processor=&quot;ExEntitiesModelDirectiveProcessor&quot;
	requires=&quot;fileName='ExEntitiesModel.entitiesModel';<strong>validation='Save'</strong>&quot;#&gt;
...</pre>
<p>The problem with this approach is that you have to put it in every single text template that generates code from your model.</p>
<p>There is another way to achieve this that will affect any code generator created over your model. It involves customizing the directive processor itself.</p>
<p><strong>1. Create a Partial Class for the Model Directive Processor</strong></p>
<p>The name of the directive processor class can be found in the text template (processor=?) and depends on your model name. If, for example, your model is named “ExEntitiesModel” than the directive processor will be named “ExEntitiesModelDirectiveProcessor”;</p>
<p><strong>2. Override GeneratePostInitializationCode</strong></p>
<p>This method is called in the directive processor base class to obtain the values of the requires arguments and generate the code transformation accordingly. You can access these values and inject the “Validation” argument if it was not provided in the text template:</p>
<pre>using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Text;

namespace Experimental.Entities
{
    /// &lt;summary&gt;
    /// Provides custom code for the ExEntitiesModelDirectiveProcessor.
    /// &lt;/summary&gt;
    public partial class ExEntitiesModelDirectiveProcessor
    {
        #region Protected Methods

        /// &lt;summary&gt;
        /// Contribute additively to initialization code for the TextTransformation generated class.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;directiveName&quot;&gt;The directive name.&lt;/param&gt;
        /// &lt;param name=&quot;codeBuffer&quot;&gt;The code buffer.&lt;/param&gt;
        /// &lt;param name=&quot;languageProvider&quot;&gt;The language provider.&lt;/param&gt;
        /// &lt;param name=&quot;requiresArguments&quot;&gt;The requires arguments values.&lt;/param&gt;
        /// &lt;param name=&quot;providesArguments&quot;&gt;The provides arguments values.&lt;/param&gt;
        /// &lt;remarks&gt;
        /// This code will be added after the call to the base class.
        /// &lt;/remarks&gt;
        protected override void GeneratePostInitializationCode(string directiveName, StringBuilder codeBuffer, CodeDomProvider languageProvider, IDictionary&lt;string, string&gt; requiresArguments, IDictionary&lt;string, string&gt; providesArguments)
        {
            // Check if requires includes validation

            if (requiresArguments.Keys.Contains(&quot;Validation&quot;))
            {
                if (string.IsNullOrEmpty(requiresArguments[&quot;Validation&quot;]))
                {
                    requiresArguments[&quot;Validation&quot;] = &quot;Save&quot;;
                }
            }
            else
            {
                requiresArguments.Add(&quot;Validation&quot;, &quot;Save&quot;);
            }

            // Default behavior

            base.GeneratePostInitializationCode(directiveName, codeBuffer, languageProvider, requiresArguments, providesArguments);
        }

        #endregion
    }
}</pre>
<p>And you are done.</p>
<p>NOTE: This idea of having text templates force the validation of the underlying model has a potential issue. If you have, say, 10 different text templates in the same solution, all generating code from the same model, each one will execute the validation before running (if you run Transform All Templates for example). That will probably result in some kind of performance issue.</p>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/12/11/dsl-tools-19-validate-model-before-generating-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/12/11/dsl-tools-19-validate-model-before-generating-code/</feedburner:origLink></item>
		<item>
		<title>DSL Tools #18 – “Smart” Reset Model</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/hNSwJvty-2A/</link>
		<comments>http://hugoribeiro.blog.com/2010/12/05/dsl-tools-18-smart-reset-model/#comments</comments>
		<pubDate>Sun, 05 Dec 2010 18:32:19 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/12/05/dsl-tools-18-smart-reset-model/</guid>
		<description><![CDATA[It is not uncommon to have the necessity to restart a model by removing all shapes in the diagram. In fact, we have a set of models (different DSLs) that are integrated through custom commands that read the original model and import them (or parts of them) in the destination model. So, I decided to [...]]]></description>
			<content:encoded><![CDATA[<p>It is not uncommon to have the necessity to restart a model by removing all shapes in the diagram.</p>
<p>In fact, we have a set of models (different DSLs) that are integrated through custom commands that read the original model and import them (or parts of them) in the destination model.</p>
<p>So, I decided to implement also a custom command that resets the model so that the import command can be easily executed again. But this means removing only some of the shapes in the model, not all.</p>
<p>Off-course the user can select the shapes in the model and delete them but that is not really handy. So the “Reset Model” command actually iterates trough all the shapes in the model and deletes them leaving the shapes of types specified to be ignored.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/ResetModel01.png" width="260" height="141" /></p>
<p>The code is very simple. I wanted it to be absolutly generic so I’m using a Diagram extension method, iterating through the node shapes in the diagram, instead of using the Clear() methods available for generated embedded relations.</p>
<pre>/// &lt;summary&gt;
/// Resets the current diagram.
/// &lt;/summary&gt;
/// &lt;param name=&quot;diagram&quot;&gt;The diagram.&lt;/param&gt;
/// &lt;param name=&quot;prompt&quot;&gt;A value indicating whether the user should be prompted to confirm.&lt;/param&gt;
/// &lt;param name=&quot;dontDelete&quot;&gt;A list of types that specify shape elements and/or model elements that should not be deleted.&lt;/param&gt;
public static void ResetModel(this Diagram diagram, bool prompt, params Type[] dontDelete)
{
    // Validation

    if (diagram == null)
    {
        throw new ArgumentNullException(&quot;diagram&quot;);
    }

    // Prompt the user?

    if (prompt)
    {
        if (!Dialogs.ShowQuestion(Properties.Resources.RES_PleaseConfirm, Properties.Resources.RES_Question_ResetModel))
        {
            return;
        }
    }

    // Get the child node shapes
    // Add the shapes that should be deleted to a collection

    Collection&lt;NodeShape&gt; toDelete = new Collection&lt;NodeShape&gt;();
    foreach (NodeShape child in diagram.NestedChildNodeShapes())
    {
        // Check if the shape is set to be ignored

        bool delete = true;

        if (dontDelete != null)
        {
            Type nodeShapeType = child.GetType();
            if (dontDelete.Contains(nodeShapeType))
            {
                delete = false;
            }
            else
            {
                if (child.ModelElement != null)
                {
                    Type modelElementType = child.ModelElement.GetType();
                    if (dontDelete.Contains(modelElementType))
                    {
                        delete = false;
                    }
                }
            }
        }

        // Delete?

        if (delete)
        {
            toDelete.Add(child);
        }
    }

    // Transaction

    using (Transaction transaction = diagram.Store.TransactionManager.BeginTransaction(&quot;ResetModel&quot;))
    {
        // Delete

        foreach (NodeShape shape in toDelete)
        {
            shape.Delete();
        }

        // Commit

        transaction.Commit();
    }
}</pre>
<p>Note that NestedChildNodeShapes is an extension of ShapeElement:</p>
<pre>/// &lt;summary&gt;
/// Gets a list of the nested node shapes.
/// &lt;/summary&gt;
/// &lt;param name=&quot;shape&quot;&gt;The parent shape.&lt;/param&gt;
/// &lt;returns&gt;A list of the nested node shapes that are connected to the specified node shape.&lt;/returns&gt;
public static IEnumerable&lt;NodeShape&gt; NestedChildNodeShapes(this ShapeElement shape)
{
    // Validation

    if (shape == null)
    {
        throw new ArgumentNullException(&quot;shape&quot;);
    }

    // Search all nested child shapes

    Collection&lt;NodeShape&gt; result = new Collection&lt;NodeShape&gt;();
    foreach (ShapeElement child in shape.NestedChildShapes)
    {
        // Is it a node shape?

        NodeShape nodeShape = child as NodeShape;
        if (nodeShape != null)
        {
            result.Add(nodeShape);
        }
    }

    return result.AsEnumerable&lt;NodeShape&gt;();
}</pre>
<p>And also that the argument dontDelete allows you to specify the types of the shapes or model elements that should not be deleted from the diagram.</p>
<p>Very simple.</p>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/12/05/dsl-tools-18-smart-reset-model/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/12/05/dsl-tools-18-smart-reset-model/</feedburner:origLink></item>
		<item>
		<title>DSL Tools #17 – Auto-hide Connectors</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/r0MPBeIgqyM/</link>
		<comments>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-17-auto-hide-connectors/#comments</comments>
		<pubDate>Tue, 30 Nov 2010 21:40:52 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/11/30/dsl-tools-17-auto-hide-connectors/</guid>
		<description><![CDATA[Even more interesting than allowing the user to show or hide all the connectors in a model is if you provide a way for connectors to automatically show or hide as the user selects shapes in the model. Thinking of this I’ve created a new feature in my models – called auto-hide connectors – that [...]]]></description>
			<content:encoded><![CDATA[<p>Even more interesting than allowing the user to <a href="http://hugoribeiro.blog.com/2010/11/30/dsl-tools-16-showhide-connectors/" target="_blank">show or hide all the connectors</a> in a model is if you provide a way for connectors to automatically show or hide as the user selects shapes in the model.</p>
<p>Thinking of this I’ve created a new feature in my models – called auto-hide connectors – that does something like that.</p>
<p>I’ve set the following requirements:</p>
<ul>
<li>The user should be able to set the feature on and off at any time (through a context menu). </li>
<li>By default the feature is off. </li>
<li>The user setting should be persisted when the user closes the model (to be in the same state the next he opens it). </li>
<li>When the feature is off, connectors are always visible. </li>
<li>When the feature is on:
<ul>
<li>If nothing is selected in the diagram, all the connectors are hidden. </li>
<li>When a node shape is selected, all the connectors to and from that shape will be visible. </li>
</ul>
</li>
</ul>
<p>Implementing these requirements is quite simple.</p>
<p><strong>1. AutoHideConnectors Domain Property</strong></p>
<p>You need a place to persist a flag that turns the feature on and off. For that you can create a domain property called AutoHideConnectors in the model root.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/AutoHideConnectors01.PNG" width="250" height="175" /></p>
<p>NOTE: Be sure to make it not browsable so that it won’t appear in the model properties as it will be changed by a context menu.</p>
<p><strong>2. Transform All</strong></p>
<p>Transform all templates to reflect the new domain property in the model object model.</p>
<p><strong>3. Context Menu</strong></p>
<p>The next step is to create a context menu that allows the user to activate/deactivate this feature.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/AutoHideConnectors02.png" width="300" height="127" /></p>
<p>To make the Checked property of the menu depend on the AutoHideConnectors domain property you have to add the following code to OnPopUpMenuDisplayAction:</p>
<pre>internal void OnPopUpMenuDisplayAction(object sender, EventArgs e)
{
    // Menu command

    MenuCommand command = sender as MenuCommand;
    if (command != null)
    {
        if (command.CommandID.Guid.Equals(this.cmdAutoHideConnectorsGUID))
        {
            command.Visible = this.CurrentModel != null;
            command.Enabled = command.Visible;
            command.Checked = command.Visible &amp;&amp; this.CurrentModel.AutoHideConnectors;
        }

        // Default behavior

        command.Visible = true;
        command.Enabled = command.Visible;
    }
}</pre>
<p>The code associated with the MenuClick event is the following:</p>
<pre>private void ExecuteAutoHideConnectors()
{
    // Validation

    if (this.CurrentDocData == null || this.CurrentDocView == null || this.CurrentDocView.CurrentDiagram == null)
    {
        return;
    }

    // Transaction to change the model

    using (Transaction transaction = this.CurrentDocData.Store.TransactionManager.BeginTransaction(&quot;AutoHideConnectors&quot;))
    {
        // Change model property

        this.CurrentModel.AutoHideConnectors = !this.CurrentModel.AutoHideConnectors;

        // Update the view

        if (this.CurrentModel.AutoHideConnectors)
        {
            this.CurrentDocView.CurrentDiagram.HideAllLinks();
        }
        else
        {
            this.CurrentDocView.CurrentDiagram.ShowAllLinks();
        }

        // Commit

        transaction.Commit();
    }
}</pre>
<p>This code relies in the ShowAllLinks and HideAllLinks extensions described in this <a href="http://hugoribeiro.blog.com/2010/11/30/dsl-tools-16-showhide-connectors/" target="_blank">previous post</a>.</p>
<p>NOTE: The infrastructure to add context menus his explained <a href="http://hugoribeiro.blog.com/2010/11/30/dsl-tools-15-context-menus-with-code-generation/" target="_blank">here</a>.</p>
<p><strong>4. OnSelectionChanged (DocView)</strong></p>
<p>Now the only thing remaining is to have the diagram react to the shape that is selected.</p>
<p>To implement that you will need to extend the DocView for your model and there override the OnSelectionChanged event handler.</p>
<p>NOTE: The name of the class that you will need to extend depends on your DSL and can be found in the DocView.cs file of your DSLPackage project (it ends with DocView).</p>
<p>The code is quite simple. You have to check if the primary selection corresponds to a node shape (meaning that is a shape that can have connectors to/from it) and then have the diagram show only the links that come from or go to that shape.</p>
<pre>using System;
using Experimental.Core.Extensions;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace Experimental.Reporting
{
    /// &lt;summary&gt;
    /// Provides custom code for the ExReportingModelDocView.
    /// &lt;/summary&gt;
    internal partial class ExReportingModelDocView
    {
        #region Protected Methods

        /// &lt;summary&gt;
        /// Called when selection changes in this window.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;e&quot;&gt;&lt;/param&gt;
        /// &lt;remarks&gt;
        /// Overriden to update the F1 help keyword for the selection.
        /// &lt;/remarks&gt;
        protected override void OnSelectionChanged(EventArgs e)
        {
            // Default behavior

            base.OnSelectionChanged(e);

            // There is something to do only if AutoHideConnectors is true

            if (!this.CurrentModel&lt;ExReportingModelRoot&gt;().AutoHideConnectors)
            {
                return;
            }

            // Process selection

            NodeShape selectedShape = (this.PrimarySelection as NodeShape);
            if (selectedShape != null)
            {
                // Hide all the links in the diagram

                if (this.CurrentDiagram != null)
                {
                    this.CurrentDiagram.HideAllLinks();
                }

                // If the shape is the diagram itself, nothing more to do

                if (selectedShape is Diagram)
                {
                    return;
                }

                // Show the links connected to the selected shape

                if (selectedShape.Diagram != null)
                {
                    selectedShape.Diagram.ShowAllLinks(selectedShape);
                }
            }
        }

        #endregion
    }
}</pre>
<p>The ShowAllLinks method used here is also an extension of the Diagram class:</p>
<pre>/// &lt;summary&gt;
/// Shows all the links in the current diagram that connect to the specified node shape.
/// &lt;/summary&gt;
/// &lt;param name=&quot;diagram&quot;&gt;The diagram.&lt;/param&gt;
/// &lt;param name=&quot;nodeShape&quot;&gt;The node shape whose links should be shown.&lt;/param&gt;
public static void ShowAllLinks(this Diagram diagram, NodeShape nodeShape)
{
    ShowHideAllLinks(diagram, nodeShape, true);
}

private static void ShowHideAllLinks(this Diagram diagram, NodeShape nodeShape, bool show)
{
    // Validation

    if (diagram == null)
    {
        throw new ArgumentNullException(&quot;diagram&quot;);
    }

    // Get the links that should be shown or hidden

    IEnumerable&lt;BinaryLinkShape&gt; links = diagram.NestedChildBinaryLinkShapes(nodeShape);

    // Show/hide the links

    foreach (BinaryLinkShape link in links)
    {
        if (show)
        {
            if (!link.IsVisible)
            {
                link.Show();
            }
        }
        else
        {
            if (link.IsVisible)
            {
                link.Hide();
            }
        }
    }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-17-auto-hide-connectors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-17-auto-hide-connectors/</feedburner:origLink></item>
		<item>
		<title>DSL Tools #16 – Show/Hide Connectors</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/M-g8JYTc-As/</link>
		<comments>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-16-showhide-connectors/#comments</comments>
		<pubDate>Tue, 30 Nov 2010 21:22:39 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/11/30/dsl-tools-16-showhide-connectors/</guid>
		<description><![CDATA[One of the major issues in the DSL Tools today is that you can’t have a model be defined in two or more diagrams (files). This is an issue for many reasons. One of them is that it is very easy to have models becoming very hard to manipulate (or even read) because they have [...]]]></description>
			<content:encoded><![CDATA[<p>One of the major issues in the DSL Tools today is that you can’t have a model be defined in two or more diagrams (files). This is an issue for many reasons. One of them is that it is very easy to have models becoming very hard to manipulate (or even read) because they have lots and lots of shapes and connectors.</p>
<p>Thinking about this a bit, one of the things that contributes more to make a model hard to read are connectors, that is when you have a lot of them.</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/ShowHideConnectors01.PNG" width="550" height="376" /></p>
<p>So a very useful thing that diagrams should have is the ability to hide and show all the connectors at the user’s discretion.</p>
<p>It turns out that this is very easy to implement just by adding two extensions to the Diagram class.</p>
<p>Here is how I’ve done it.</p>
<p><strong>1. Extend Diagram</strong></p>
<p>I’ve created a static class called DiagramExtensions that provides extension methods for the Diagram class. This class adds two extensions:</p>
<ul>
<li>ShowAllLinks </li>
<li>HideAllLinks </li>
</ul>
<p>The magic happens in the ShowHideAllLinks private method:</p>
<ul>
<li>First I get an IEnumerable of all the shapes in the diagram that are of type BinaryLinkShape through another extension method called NestedChildBinaryLinkShapes (defined for ShapeElement). </li>
<li>NestedChildBinaryLinkShapes just iterates through NestedChildShapes and returns only the shapes that are of type BinaryLinkShape (a connector in the DSL Tools). </li>
<li>Finally, the IEnumerable is enumerated and the connector is shown if it is hidden or hidden if it is visible. </li>
</ul>
<p>Here is the source code for DiagramExtensions:</p>
<pre>using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace Experimental.Core.Extensions
{
    /// &lt;summary&gt;
    /// Provides extension methods for the Diagram class.
    /// &lt;/summary&gt;
    public static class DiagramExtensions
    {
        #region Public Methods

        /// &lt;summary&gt;
        /// Shows all the links in the current diagram.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;diagram&quot;&gt;The diagram.&lt;/param&gt;
        public static void ShowAllLinks(this Diagram diagram)
        {
            ShowHideAllLinks(diagram, true);
        }

        /// &lt;summary&gt;
        /// Hides all the links in the current diagram.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;diagram&quot;&gt;The diagram.&lt;/param&gt;
        public static void HideAllLinks(this Diagram diagram)
        {
            ShowHideAllLinks(diagram, false);
        }

        #endregion

        #region Private Methods

        private static void ShowHideAllLinks(this Diagram diagram, bool show)
        {
            ShowHideAllLinks(diagram, null, show);
        }

        private static void ShowHideAllLinks(this Diagram diagram, NodeShape nodeShape, bool show)
        {
            // Validation

            if (diagram == null)
            {
                throw new ArgumentNullException(&quot;diagram&quot;);
            }

            // Get the links that should be shown or hidden

            IEnumerable&lt;BinaryLinkShape&gt; links = diagram.NestedChildBinaryLinkShapes(nodeShape);

            // Show/hide the links

            foreach (BinaryLinkShape link in links)
            {
                if (show)
                {
                    if (!link.IsVisible)
                    {
                        link.Show();
                    }
                }
                else
                {
                    if (link.IsVisible)
                    {
                        link.Hide();
                    }
                }
            }
        }

        #endregion
    }
}</pre>
<p>And the source code for ShapeElementExtensions:</p>
<pre>using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace Experimental.Core.Extensions
{
    /// &lt;summary&gt;
    /// Provides extension methods for the ShapeElement class.
    /// &lt;/summary&gt;
    public static class ShapeElementExtensions
    {
        #region Public Methods

        /// &lt;summary&gt;
        /// Gets a list of the nested binary link shapes.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;shape&quot;&gt;The shape.&lt;/param&gt;
        /// &lt;returns&gt;A list of the nested binary link shapes.&lt;/returns&gt;
        public static IEnumerable&lt;BinaryLinkShape&gt; NestedChildBinaryLinkShapes(this ShapeElement shape)
        {
            return NestedChildBinaryLinkShapes(shape, null);
        }

        /// &lt;summary&gt;
        /// Gets a list of the nested binary link shapes that are connected to the specified node shape.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;shape&quot;&gt;The shape.&lt;/param&gt;
        /// &lt;param name=&quot;toOrFromShape&quot;&gt;The node shape to which the link shape must be connected to appear in the result.&lt;/param&gt;
        /// &lt;returns&gt;A list of the nested binary link shapes that are connected to the specified node shape.&lt;/returns&gt;
        public static IEnumerable&lt;BinaryLinkShape&gt; NestedChildBinaryLinkShapes(this ShapeElement shape, NodeShape toOrFromShape)
        {
            // Validation

            if (shape == null)
            {
                throw new ArgumentNullException(&quot;shape&quot;);
            }

            // Search all nested child shapes

            Collection&lt;BinaryLinkShape&gt; result = new Collection&lt;BinaryLinkShape&gt;();
            foreach (ShapeElement child in shape.NestedChildShapes)
            {
                // Is it a link shape?

                BinaryLinkShape linkShape = child as BinaryLinkShape;
                if (linkShape != null)
                {
                    // If the node shape is not specified, just add to the result

                    if (toOrFromShape == null)
                    {
                        result.Add(linkShape);
                    }
                    else
                    {
                        // Otherwise the link shape must connect to the specified node shape

                        if (linkShape.FromLinkConnectsToNode.Nodes.Equals(toOrFromShape) ||
                            linkShape.ToLinkConnectsToNode.Nodes.Equals(toOrFromShape))
                        {
                            result.Add(linkShape);
                        }
                    }
                }
            }

            return result.AsEnumerable&lt;BinaryLinkShape&gt;();
        }

        #endregion
    }
}</pre>
<p><strong>2. Add Context Menus</strong></p>
<p>The two new operations are available to the user through context menus (implemented as explained <a href="http://hugoribeiro.blog.com/2010/11/30/dsl-tools-15-context-menus-with-code-generation/" target="_blank">here</a>). The corresponding commands just need to call the extension methods defined in the previous step.</p>
<pre>private void ExecuteShowAllConnectors()
{
    // Validation

    if (this.CurrentDocView == null || this.CurrentDocView.CurrentDiagram == null)
    {
        return;
    }

    // Execute

    this.CurrentDocView.CurrentDiagram.ShowAllLinks();
}

private void ExecuteHideAllConnectors()
{
    // Validation

    if (this.CurrentDocView == null || this.CurrentDocView.CurrentDiagram == null)
    {
        return;
    }

    // Execute

    this.CurrentDocView.CurrentDiagram.HideAllLinks();
}</pre>
<p>Easy.</p>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-16-showhide-connectors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-16-showhide-connectors/</feedburner:origLink></item>
		<item>
		<title>DSL Tools #15 – Context Menus with Code Generation</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/uvQcXbOiyZs/</link>
		<comments>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-15-context-menus-with-code-generation/#comments</comments>
		<pubDate>Tue, 30 Nov 2010 21:21:13 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[DSL]]></category>
		<category><![CDATA[Model-driven Development]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/11/30/dsl-tools-15-context-menus-with-code-generation/</guid>
		<description><![CDATA[Following this idea by Filipe Romano, I’ve augmented the model he proposed to support building context menus that can be organized inside sub-menus. In my DSL project I wanted to achieve a context menu like this: Notice my custom context menus: Auto-hide Show All Hide All Reset Model Based on Filipe’s sample, all you need [...]]]></description>
			<content:encoded><![CDATA[<p>Following this <a href="http://lessisthenewmore.wordpress.com/2009/03/09/managing-menu-entries-in-a-dsl/" target="_blank">idea by Filipe Romano</a>, I’ve augmented the model he proposed to support building context menus that can be organized inside sub-menus.</p>
<p>In my DSL project I wanted to achieve a context menu like this:</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/ContextMenus01.png" width="450" height="246" /></p>
<p>Notice my custom context menus:</p>
<ul>
<li>Auto-hide </li>
<li>Show All </li>
<li>Hide All </li>
<li>Reset Model </li>
</ul>
<p>Based on Filipe’s sample, all you need to do is the following:</p>
<p><strong>1. Add CommandSetConfig.tt to the DSLPackage project</strong></p>
<p>This file contains the model that defines the context menus. There are three collections here – menus, groups, and commands – that you populate and relate according to what you are trying to achieve.</p>
<pre>&lt;#
string languageNamespace = &quot;Experimental.Reporting&quot;;
string languageName = &quot;ExReportingModel&quot;;

// Lists

Collection&gt; menus = new Collection&gt;();
Collection&gt; groups = new Collection&gt;();
Collection&gt; commands = new Collection&gt;();

// -- Menus --

Dictionary menu = null;

// Menu Connectors

menu = new Dictionary();
menu.Add(&quot;CanonicalName&quot;, &quot;mnuConnectors&quot;);
menu.Add(&quot;ButtonText&quot;, &quot;Connectors&quot;);
menu.Add(&quot;Id&quot;, &quot;{E4AB24D9-31C4-4AD5-B7DC-07E33D997265}&quot;);
menus.Add(menu);

// -- Groups --

Dictionary group = null;

// Group Connectors

group = new Dictionary();
group.Add(&quot;Parent&quot;, &quot;mnuConnectors&quot;);
group.Add(&quot;CanonicalName&quot;, &quot;grpConnectors&quot;);
group.Add(&quot;Id&quot;, &quot;{F933E696-BD92-4498-AD64-E3BEFE926278}&quot;);
groups.Add(group);

// -- Buttons --

Dictionary command = null;

// ... Menu Connectors

// Command AutoHideConnectors

command = new Dictionary();
command.Add(&quot;Parent&quot;, &quot;grpConnectors&quot;);
command.Add(&quot;CanonicalName&quot;, &quot;cmdAutoHideConnectors&quot;);
command.Add(&quot;ButtonText&quot;, &quot;Auto-hide&quot;);
command.Add(&quot;ToolTipText&quot;, &quot;Toggle auto-hide connectors.&quot;);
command.Add(&quot;Id&quot;, &quot;{804CBDAD-0D02-4966-B0D7-3FFEE8DA4F59}&quot;);
commands.Add(command);

// Command ShowAllConnectors

command = new Dictionary();
command.Add(&quot;Parent&quot;, &quot;grpConnectors&quot;);
command.Add(&quot;CanonicalName&quot;, &quot;cmdShowAllConnectors&quot;);
command.Add(&quot;ButtonText&quot;, &quot;Show All&quot;);
command.Add(&quot;ToolTipText&quot;, &quot;Shows all connectors in the model.&quot;);
command.Add(&quot;Id&quot;, &quot;{31024157-E41F-4AB6-A530-306EC0F290DE}&quot;);
commands.Add(command);

// Command HideAllConnectors

command = new Dictionary();
command.Add(&quot;Parent&quot;, &quot;grpConnectors&quot;);
command.Add(&quot;CanonicalName&quot;, &quot;cmdHideAllConnectors&quot;);
command.Add(&quot;ButtonText&quot;, &quot;Hide All&quot;);
command.Add(&quot;ToolTipText&quot;, &quot;Hides all connectors in the model.&quot;);
command.Add(&quot;Id&quot;, &quot;{3E992345-126B-46F0-8921-9FB62AF42A32}&quot;);
commands.Add(command);

// ...

// Command cmdResetModel

command = new Dictionary();
command.Add(&quot;CanonicalName&quot;, &quot;cmdResetModel&quot;);
command.Add(&quot;ButtonText&quot;, &quot;Reset Model&quot;);
command.Add(&quot;ToolTipText&quot;, &quot;Reset the current model.&quot;);
command.Add(&quot;Id&quot;, &quot;{874741C7-26E5-427E-B73C-DE6BEE7133ED}&quot;);
commands.Add(command);

#&gt;</pre>
<p>NOTE: You will need to remove custom tool associated with this file to prevent Visual Studio from trying to generate code from it.</p>
<p><strong>2. Add Commands.tt</strong></p>
<p>This will generate the custom command definitions file in xml from the configuration you set in CommandSetConfig.tt.</p>
<p>The source code is the following:</p>
<pre>&lt;#@ template inherits=&quot;Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation&quot; debug=&quot;true&quot;#&gt;
&lt;#@ assembly name=&quot;Microsoft.VisualStudio.TextTemplating.Modeling.10.0.dll&quot;#&gt;
&lt;#@ output extension=&quot;.vsct&quot; #&gt;
&lt;#@ import namespace = &quot;System.Collections.Generic&quot; #&gt;
&lt;#@ import namespace = &quot;System.Collections.ObjectModel&quot; #&gt;
&lt;#@ include file=&quot;CommandSetConfig.tt&quot; #&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;CommandTable xmlns=&quot;http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable&quot; xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;&gt;
	&lt;!-- --&gt;
	&lt;!-- This file contains custom command definitions. --&gt;
	&lt;!-- --&gt;
	&lt;!-- NOTE: Each time commands are added or changed, the &quot;version&quot; parameter to the --&gt;
	&lt;!-- ProvideMenuResource attribute in Shell\Package.tt should be incremented. --&gt;
	&lt;!-- This causes Visual Studio to re-merge the menu definitions for the package. --&gt;
	&lt;!-- Otherwise, changes won't take effect until the next time devenv /setup is run. --&gt;
	&lt;!-- --&gt;
	&lt;Extern href=&quot;stdidcmd.h&quot;/&gt;
	&lt;Extern href=&quot;vsshlids.h&quot;/&gt;
	&lt;Extern href=&quot;msobtnid.h&quot;/&gt;
	&lt;Extern href=&quot;virtkeys.h&quot;/&gt;
	&lt;Extern href=&quot;DSLToolsCmdID.h&quot;/&gt;
	&lt;Include href=&quot;GeneratedCode\GeneratedVsct.vsct&quot;/&gt;
	&lt;Commands package=&quot;guidPkg&quot;&gt;

		&lt;Menus&gt;

&lt;#
foreach (Dictionary&lt;string, string&gt; element in menus)
{
#&gt;
				&lt;Menu guid=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;GUID&quot; id=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;ID&quot; priority=&quot;0x0000&quot; type=&quot;Menu&quot;&gt;
					&lt;Parent guid=&quot;guidCmdSet&quot; id=&quot;grpidContextMain&quot; /&gt;
					&lt;CommandFlag&gt;DynamicVisibility&lt;/CommandFlag&gt;
					&lt;Strings&gt;
					  &lt;ButtonText&gt;&lt;#= element[&quot;ButtonText&quot;] #&gt;&lt;/ButtonText&gt;
					  &lt;CanonicalName&gt;&lt;#= element[&quot;CanonicalName&quot;] #&gt;&lt;/CanonicalName&gt;
					&lt;/Strings&gt;
				&lt;/Menu&gt;

&lt;#
}
#&gt;
		&lt;/Menus&gt;

		&lt;Groups&gt;

&lt;#
foreach (Dictionary&lt;string, string&gt; element in groups)
{
#&gt;
			&lt;Group guid=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;GUID&quot; id=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;ID&quot; priority=&quot;0x0000&quot;&gt;
				&lt;Parent guid=&quot;&lt;#= element[&quot;Parent&quot;] #&gt;GUID&quot; id=&quot;&lt;#= element[&quot;Parent&quot;] #&gt;ID&quot; /&gt;
			&lt;/Group&gt;

&lt;#
}
#&gt;
		&lt;/Groups&gt;

		&lt;Buttons&gt;

&lt;#
foreach (Dictionary&lt;string, string&gt; element in commands)
{
	string parentGuid = null;
	string parentId = null;

	if (element.TryGetValue(&quot;Parent&quot;, out parentGuid))
	{
		parentId = parentGuid + &quot;ID&quot;;
		parentGuid = parentGuid + &quot;GUID&quot;;
	}
	else
	{
		parentId = &quot;grpidContextMain&quot;;
		parentGuid = &quot;guidCmdSet&quot;;
	}

#&gt;
			&lt;Button guid=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;GUID&quot; id=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;ID&quot; priority=&quot;0x0000&quot; type=&quot;Button&quot;&gt;
				&lt;Parent guid=&quot;&lt;#= parentGuid #&gt;&quot; id=&quot;&lt;#= parentId #&gt;&quot; /&gt;
				&lt;CommandFlag&gt;DynamicVisibility&lt;/CommandFlag&gt;
				&lt;Strings&gt;
					&lt;CanonicalName&gt;&lt;#= element[&quot;CanonicalName&quot;] #&gt;&lt;/CanonicalName&gt;
					&lt;ButtonText&gt;&lt;#= element[&quot;ButtonText&quot;] #&gt;&lt;/ButtonText&gt;
					&lt;ToolTipText&gt;&lt;#= element[&quot;ToolTipText&quot;] #&gt;&lt;/ToolTipText&gt;
				&lt;/Strings&gt;
			&lt;/Button&gt;

&lt;#
}
#&gt;
		&lt;/Buttons&gt;

	&lt;/Commands&gt;

	&lt;Symbols&gt;

		&lt;!-- Menus --&gt;

&lt;#
int index = 1000;
foreach (Dictionary&lt;string, string&gt; element in menus)
{
#&gt;
		&lt;GuidSymbol name=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;GUID&quot; value=&quot;&lt;#= element[&quot;Id&quot;] #&gt;&quot;&gt;
			&lt;IDSymbol name=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;ID&quot; value=&quot;0x&lt;#= index #&gt;&quot; /&gt;
		&lt;/GuidSymbol&gt;

&lt;#
index++;
}
#&gt;

		&lt;!-- Groups --&gt;

&lt;#
index = 1100;
foreach (Dictionary&lt;string, string&gt; element in groups)
{
#&gt;
		&lt;GuidSymbol name=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;GUID&quot; value=&quot;&lt;#= element[&quot;Id&quot;] #&gt;&quot;&gt;
			&lt;IDSymbol name=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;ID&quot; value=&quot;0x&lt;#= index #&gt;&quot; /&gt;
		&lt;/GuidSymbol&gt;

&lt;#
index++;
}
#&gt;

		&lt;!-- Commands --&gt;

&lt;#
index = 1200;
foreach (Dictionary&lt;string, string&gt; element in commands)
{
#&gt;
		&lt;GuidSymbol name=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;GUID&quot; value=&quot;&lt;#= element[&quot;Id&quot;] #&gt;&quot;&gt;
			&lt;IDSymbol name=&quot;&lt;#= element[&quot;CanonicalName&quot;] #&gt;ID&quot; value=&quot;0x&lt;#= index #&gt;&quot; /&gt;
		&lt;/GuidSymbol&gt;

&lt;#
index++;
}
#&gt;

	&lt;/Symbols&gt;

&lt;/CommandTable&gt;</pre>
<p><strong>3. Add CommandSet.tt</strong></p>
<p>This will generate the commandset partial class. The source code is the following:</p>
<pre>&lt;#@ template inherits=&quot;Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation&quot; debug=&quot;true&quot;#&gt;
&lt;#@ assembly name=&quot;Microsoft.VisualStudio.TextTemplating.Modeling.10.0.dll&quot;#&gt;
&lt;#@ output extension=&quot;.cs&quot; #&gt;
&lt;#@ import namespace = &quot;System.Collections.Generic&quot; #&gt;
&lt;#@ import namespace = &quot;System.Collections.ObjectModel&quot; #&gt;
&lt;#@ include file=&quot;CommandSetConfig.tt&quot; #&gt;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Design;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Shell;

namespace &lt;#= languageNamespace #&gt;
{
    /// &lt;summary&gt;
    /// Custom code for &lt;#= languageName #&gt;CommandSet.
    /// &lt;/summary&gt;
    internal partial class &lt;#= languageName #&gt;CommandSet : &lt;#= languageName #&gt;CommandSetBase
    {
        #region Constants

&lt;#
int index = 1200;

foreach (Dictionary&lt;string, string&gt; element in commands)
{
	string canonicalName = element[&quot;CanonicalName&quot;];

	string constName = canonicalName.Substring(0, 1).ToUpper() + canonicalName.Substring(1);
#&gt;
        /// &lt;summary&gt;
        /// &lt;#= constName #&gt; commmand identifier.
        /// &lt;/summary&gt;
        private const int &lt;#= constName #&gt;ID = 0x&lt;#= index #&gt;;

&lt;#
	index++;
}
#&gt;
        #endregion

        #region Members

&lt;#
foreach (Dictionary&lt;string, string&gt; element in commands)
{
	string canonicalName = element[&quot;CanonicalName&quot;];
#&gt;
        /// &lt;summary&gt;
        /// Enable related task commmand unique identifier.
        /// &lt;/summary&gt;
        private Guid &lt;#= canonicalName #&gt;GUID = new Guid(&quot;&lt;#= element[&quot;Id&quot;] #&gt;&quot;);

&lt;#
}
#&gt;
        #endregion

        #region Protected Methods

        /// &lt;summary&gt;
        /// Provide the menu commands that this command set handles.
        /// &lt;/summary&gt;
        /// &lt;returns&gt;A list of commands.&lt;/returns&gt;
        protected override IList&lt;MenuCommand&gt; GetMenuCommands()
        {
            // Execute base

            IList&lt;MenuCommand&gt; commands = base.GetMenuCommands();

&lt;#
foreach (Dictionary&lt;string, string&gt; element in commands)
{
	string canonicalName = element[&quot;CanonicalName&quot;];

	string constName = canonicalName.Substring(0, 1).ToUpper() + canonicalName.Substring(1);
#&gt;
            // Add the new menu command

            DynamicStatusMenuCommand &lt;#= canonicalName #&gt; =
                new DynamicStatusMenuCommand(
                    new EventHandler(this.OnPopUpMenuDisplayAction),
                    new EventHandler(this.OnPopUpMenuClick),
                    new CommandID(this.&lt;#= canonicalName #&gt;GUID, &lt;#= constName #&gt;ID));
            commands.Add(&lt;#= canonicalName #&gt;);

&lt;#
}
#&gt;
            // Result

            return commands;
        }

        #endregion
    }
}</pre>
<p><strong>4. Transform</strong></p>
<p>Next you’ll need to transform the previous two templates to get the code generated and to be able to continue to finish the CommandSet class.</p>
<p><strong>5. Finish the CommandSet class</strong></p>
<p>This is the ExReportingModelCommandSet.cs in my project. Here you will need to implement the following methods:</p>
<ul>
<li>OnPopUpMenuDisplayAction: to control menu status. </li>
<li>OnPopUpMenuClick: to execute the menu command. </li>
</ul>
<p>The basic source code in my project is the following:</p>
<pre>using System;
using System.ComponentModel.Design;
using Experimental.Core.Extensions;
using Microsoft.VisualStudio.Modeling;
using Experimental.Core;

namespace Experimental.Reporting
{
    /// &lt;summary&gt;
    /// Custom code for ExReportingModelCommandSet.
    /// &lt;/summary&gt;
    internal partial class ExReportingModelCommandSet : ExReportingModelCommandSetBase
    {
        #region Internal Methods

        #region EventHandlers

        /// &lt;summary&gt;
        /// Called when the pop up menu is going to be displayed.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;sender&quot;&gt;The sender.&lt;/param&gt;
        /// &lt;param name=&quot;e&quot;&gt;The &lt;see cref=&quot;System.EventArgs&quot;/&gt; instance containing the event data.&lt;/param&gt;
        internal void OnPopUpMenuDisplayAction(object sender, EventArgs e)
        {
            // Menu command

            MenuCommand command = sender as MenuCommand;
            if (command != null)
            {
                if (command.CommandID.Guid.Equals(this.cmdAutoHideConnectorsGUID))
                {
                    command.Visible = this.CurrentModel != null;
                    command.Enabled = command.Visible;
                    command.Checked = command.Visible &amp;&amp; this.CurrentModel.AutoHideConnectors;
                }

                // Default behavior

                command.Visible = true;
                command.Enabled = command.Visible;
            }
        }

        /// &lt;summary&gt;
        /// Called when the user clicks an option in the pop up menu.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;sender&quot;&gt;The sender.&lt;/param&gt;
        /// &lt;param name=&quot;e&quot;&gt;The &lt;see cref=&quot;System.EventArgs&quot;/&gt; instance containing the event data.&lt;/param&gt;
        internal void OnPopUpMenuClick(object sender, EventArgs e)
        {
            // Menu command

            MenuCommand command = sender as MenuCommand;
            if (command != null)
            {
                if (command.CommandID.Guid.Equals(this.cmdAutoHideConnectorsGUID))
                {
                    this.ExecuteAutoHideConnectors();
                }
                else if (command.CommandID.Guid.Equals(this.cmdShowAllConnectorsGUID))
                {
                    this.ExecuteShowAllConnectors();
                }
                else if (command.CommandID.Guid.Equals(this.cmdHideAllConnectorsGUID))
                {
                    this.ExecuteHideAllConnectors();
                }
                else if (command.CommandID.Guid.Equals(this.cmdResetModelGUID))
                {
                    this.ExecuteResetModel();
                }
            }
        }

        #endregion

        #endregion

        #region Private Methods

        #region Execute

        private void ExecuteAutoHideConnectors()
        {
            // ...
        }

        private void ExecuteShowAllConnectors()
        {
            // ...
        }

        private void ExecuteHideAllConnectors()
        {
            // ...
        }

        private void ExecuteResetModel()
        {
            // ...
        }

        #endregion

        #endregion
    }
}</pre>
<p>The DSLPackage project should look something along these lines:</p>
<p><img src="http://dl.dropbox.com/u/140742/Blog/ContextMenus02.PNG" width="250" height="263" /></p>
<p><strong>6. Copy Commands.vsct</strong></p>
<p>To finish just copy the contents of the generated Commands.vsct to the file with the same name that is found in the DSLPackage project root.</p>
<p>Build the DSL and that’s it. You have a very simple and effective code generator to create custom context menus in your DSL projects.</p>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-15-context-menus-with-code-generation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/11/30/dsl-tools-15-context-menus-with-code-generation/</feedburner:origLink></item>
		<item>
		<title>New Home</title>
		<link>http://feedproxy.google.com/~r/HugoRibeiro/~3/kBiUNGuhO5s/</link>
		<comments>http://hugoribeiro.blog.com/2010/11/22/new-home/#comments</comments>
		<pubDate>Mon, 22 Nov 2010 15:47:00 +0000</pubDate>
		<dc:creator>Hugo Ribeiro</dc:creator>
				<category><![CDATA[Curious]]></category>

		<guid isPermaLink="false">http://hugoribeiro.blog.com/2010/11/22/new-home/</guid>
		<description><![CDATA[So I’ve decided to host the blog in another house: hugoribeiro.blog.com. I truly hope that this will make blog a lot more than these last months. Let’s see. I do have a lot of possible posts to continue the DSL Tools series. PS: You don’t need to update the feed. Just continue using feeds.feedburner.com/HugoRibeiro.]]></description>
			<content:encoded><![CDATA[<p>So I’ve decided to host the blog in another house: <a href="http://hugoribeiro.blog.com/" target="_blank">hugoribeiro.blog.com</a>.</p>
<p>I truly hope that this will make blog a lot more than these last months. Let’s see. I do have a lot of possible posts to continue the <a href="http://hugoribeiro.blog.com/category/dsl/" target="_blank">DSL Tools series</a>.</p>
<p>PS: You don’t need to update the feed. Just continue using <a href="http://feeds.feedburner.com/HugoRibeiro" target="_blank">feeds.feedburner.com/HugoRibeiro</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://hugoribeiro.blog.com/2010/11/22/new-home/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://hugoribeiro.blog.com/2010/11/22/new-home/</feedburner:origLink></item>
	</channel>
</rss>

