Tuesday, December 26, 2006

One of the things that always "bothered" me is the default look of the shapes in a new DSL created with the DSL Tools. Have a look at the first screenshot which I took from a shape in a DSL that is based on the "minimal language template" and compare that to the second screenshot of a shape in the DSL designer of the DSL Tools itself.  

 

 I really don't like the first shape but DO like the way the shape in the second screenshot looks. As you can see in the screenshot below (from another DSL!) it is possible, just by changing a few of the shapes properties, to make the shape look like the shapes in the DSL designer.

Still there is one thing missing! It isn't possible to display icons for the compartment items by just setting some properties for the shape. Luckily, we can do this by writing some custom code in the "GetCompartmentMappings" method that is available in the "shapes.cs" file (GeneratedCode folder in the DSL project). 

In the "GetCompartmentMappings" method for your compartmentshape you will find a piece of code that looks like this (of course with on your own language and shape name!).

mappings[localCompartmentMappingsOffset+0] = new DslDiagrams::ElementListCompartmentMapping("DataMembers",                                     global::MyCompany.DataContractLanguage.DataMember.NameDomainPropertyId,

            global::MyCompany.DataContractLanguage.DataMember.DomainClassId,

            GetElementsFromDataContractForDataMembers,

            null, null, null);

 

We can replace the last "null" value with a reference to a "DisplayImageGetter Delegate". This might look something like this.

 

Microsoft.VisualStudio.Modeling.Diagrams.DisplayImageGetter displayImageGetter = new Microsoft.VisualStudio.Modeling.Diagrams.DisplayImageGetter(CompartmentImageProvider);

                            

                            

mappings[localCompartmentMappingsOffset+0] = new DslDiagrams::ElementListCompartmentMapping("DataMembers",                                     global::MyCompany.DataContractLanguage.DataMember.NameDomainPropertyId,

            global::MyCompany.DataContractLanguage.DataMember.DomainClassId,

            GetElementsFromDataContractForDataMembers,

            null, null, displayImageGetter);

 

Finally we can implement the "CompartmentImageProvider" method that is used in the delegate to get the image we need for our compartment item. In this demo implementation we stored the images in a resource file called "CompartmentImages" and assumed this resource file holds an image with the name “[shape name]Image”. Of course all of this can be changed; this is just for demoing purposes.

public System.Drawing.Image CompartmentImageProvider(Microsoft.VisualStudio.Modeling.ModelElement element)

{

      return (System.Drawing.Image)CompartmentImages.ResourceManager.GetObject(string.Format("{0}{1}", element.GetType().Name, "Image"));

}

Another thing to remember is that all manual changes in the "shapes.cs" will be lost after a "Transform all Templates" action so we either have to implement these changes in the shapes.tt template or use partial classes.

As you can see in the above screenshot, the end result of the above changes is a shape with icons on the left side of the compartment items, a shape that looks just like the shapes in the DSL designer, just the way I like it!