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!

posted on 12/26/2006 1:05:13 AM UTC  #   
 Wednesday, December 20, 2006

Some time ago I started building a new Domain Specific Language for modeling message and data contracts. Building the DSL was pretty straight forward so it didn't take me too much time to build the beauty. However, during the debugging and testing phase of that DSL I noticed that the user experience of the DSL wasn't too good. For example, this particular DSL lets you model a data contract. Each data contract has a relation with one or more data members (implemented as compartment items) and for each data member you have to set its name, type, order and required properties. So, to add a data member to a data contract in my DSL I first had to do two right mouse clicks, after that I had to type the name of the data member, after that I had to switch to the properties windows and type the various values of the data members properties. This just didn't feel too good, especially when modeling a number of message and data contracts in a row. At that time I decided not to use the DSL, simply because of the, in my opinion, poor user experience.

Just recently, during some other Domain Specific Language related work I noticed again that I had some trouble getting the user experience right for modeling "relations" between model elements. Again, it was the same number of mouse clicks that bothered me (maybe it's just me?!). So, it was about time to try and find a solution for this "problem". I soon decided to build my own custom tool window specifically for my DSL but didn't know yet how to represent the "relational data" in that tool window. Luckily, in one of my talks with Jezz he came up with this brilliant idea to use the "VirtualTreeControl" (Microsoft.VisualStudio.VirtualTreeGrid.dll) for this purpose. He already used this control in the EFx Factory as you can see here. I have to be honest, this control is a real bitch to figure out, it isn't documented and I don't even know if it is officially supported but with some help of Jezz and a wrapper he built for it specifically for DSL relations, I got this working for my message-/data contracts DSL.

With this control you can show hierarchical domain relationships, and each row can have child rows, and you can display whatever columns of data you want from the relationships and domain classes.

As you can see in the picture below I can now maintain my "relational data", for my data contracts (in this case data members) in my custom tool window ("Data Contract Editor". I can easily add new data members and set their properties without having to switch between the mouse and keyboard over and over again. I think this control really rocks and I absolutely love its user experience.

The control is especially useful for exposing domain relations and domain classes which don’t have shapes or connectors on the diagram. For example, children of domain classes displayed in compartments. Therefore the control reduces shape ‘clutter’ on the diagram.

I like to consider tool windows and/or editing controls like this as "out of the box" features for future releases of the DSL Tools! In my opinion, it will dramatically improve the usage scenarios of DSL build with the DSL Tools.

posted on 12/20/2006 12:08:19 PM UTC  #