Monday, June 23, 2008
DSL : Model References (Backplane)
Edward Bakker finally found out that in Rosario the VSX team is actually giving a standard solution for this problem. Here is a detail BLOG entry about his findings, which I found very interesting.
What I wonder is when (and package into what product? I hope/think it should be the SDK), this improvement will be available.I've tried to google based on "Microsoft.VisualStudio.ToolIntegration.Backplane.dll" and Edward's blog was the only result.
I will try to find this information in Code Generation conference which I will be attending this week.
Thursday, January 17, 2008
DSL - How to use DesignVerbs with shapes?
Why? Because the other way is too complex (too many steps) and I have many actions/commands.
Every time you click on a shape, a PropertyGrid is used to expose the ShapeProperties + DomainProperties (yes, they are merged in the PropertyGrid).
So, one natural approach would be to think "Why not add DesignVerbs as done for Custom Controls?". This question was asked in the msdn forum with null replied (until now ;) )
What I did was combined the idea from Geoff Appleby with a Custom partial class for each shape (off course only for the ones you need some special command/verb).
This is how the final solution looks like:

As you can see, "My Custom Action" and "Synchronize" are my exposed Actions/Commands. Here is the code that defines what to show:
public DesignerVerbCollection Verbs
{
get {
DesignerVerbCollection verbs = new DesignerVerbCollection();
verbs.Add( new DesignerVerb("My Custom Action", new EventHandler(ExecuteAction1) ));
verbs.Add(new DesignerVerb("Synchronize", new EventHandler(Synchronize)));
return verbs;
}
}
private void Synchronize(object sender, EventArgs e)
{
ExampleElement element = this.ModelElement as ExampleElement;
if ( element == null ) return;
MessageBox.Show("Action 1 was executed on model Element:" + element.Name);
}
Off course it's not only that since you need to also implement 2 interfaces:
public partial class ExampleShape : DslDiagrams::NodeShape, IComponent, IVerbsHost
{
private ISite _site;
public ISite Site
{
get
{
if (_site == null)
_site = new VerbSite(this, new VerbMenuCommandService(this));
return _site;
}
set { _site = value; }
}
public interface IVerbsHost { DesignerVerbCollection Verbs { get; }}
Drop me an e-mail if you are interested in the complete source code ( blogger does not have file upload i think.. need to check..)
TODO : Next I would like to combine both techniques be able to access this design verbs not only from the PropertyGrid but also from the Shape's right mouse and DSL Explorer.
Tuesday, January 15, 2008
Cleaning "old" DSL Languages
After a while your "New Item" dialog will end up looking really crowded.
Don't ask me why but the "Reset the Microsoft Visual Studio 2008 Experimental hive" option does not seem to work on all cases, and I still have several old dsl languages which won't go away. ( Note: I guess that the reset option by design will not mess us local user's document as explained below)
First, I've tried , with no success, to follow the tip from "El Bruno" (spanish blog) .
What's the solution ?
You need to "remove"all the zip files in the following directories:
C:\Users\
Note: On every DSLPackage build , a new file
Wednesday, January 9, 2008
Text Templating (tt) : calling custom method
Below there is an example of how to achieve this:

It's important to notice that this syntax has changed because long time ago you could have seen it as <#! , otherwise look at this old post from Gareth
Text Templating (.tt) Validation
But what about the Text Templating requirements?
This are validations that apply only to a specific generation task. Let's say if have a property named DotNetType. It could be that this property does not affect generation of [t1] but I need this property for [t2]. For this cases, you will need to somehow validate in the (tt) Template itself.
Note: You could argue (please don't) that the example below is a bad example, I know but there are still some other real cases.
The 'correct' way
- This page actually shows what's the correct technique
How to: Generate Errors and Warnings from Text Templates

I must say that before finding out that I've tried this 2 other options:
- Raise an exception (hard but work since it's integrated with the Error list as shown below):


- Just add a comment to the output file (this is not always possible ( example : asp.net template based controls like GridView don't support XML comment inside their tpl tags..)
Friday, December 28, 2007
Adding a Menu to a DSL (vs.net 2008 SDK + VSCT file)
It's just strange that something so simple is not integrated as part of the basic features of the DSL tools themselves. Furthermore, the only DSL book I have it shows old code (refers to the old ctc file), the document in the vs.net 2008 SDK shows the same problem, etc.
The "closest" example I've found is this one: El Bruno (Spanish) but unfortunately, this is also based on CTC file and not using the new VSCT example. I must admit that with the new VSCT file it's easier than the previously CTC file.
All the BLOG's I found showed vs.net 2005 examples all using the old ctc file.
I first tried to use Clarius SFT (Software Factories Toolkit) which probably would have been a better options but I could not install it ( VS.NET 2008 RTM , can't install old GAX extensions…so SFT would also fail to install). Victor Garcia Aprea had exactly the same problem as looks like I share his point of view about how obscure adding a menu could be.
This msdn page: VSCT Samples in C# showed me the missing link: How to define the command Guid's and ID's.
Step#1: Modify Commands.vsct
- Project = DSLPackage
- Open Commands.vsct
- Add Symbols ( Guid + ID)
- Please remmember that the commands ID and GUID need to be unique not only in your project but in your whole vs.net environment. I’ve created by accident 2 projects which shared the same ID and I was getting the wrong text.
- Add Commands
18 <Commands package="guidPkg">
19 20 <Buttons>
21 <Button guid="cmdImportDbSchemaGUID" id="cmdImportDbSchemaID" priority="0x0902" type="Button">
22 <Parent guid="guidCmdSet" id="grpidContextMain"/>
23 <Strings>
24 <CanonicalName>cmdImportDbSchemaCanonicalName>
25 <ButtonText>Import from Database SchemaButtonText>
26 <ToolTipText>Use this option to create the domain from an existing Database SchemaToolTipText>
27 Strings>
28 Button>
29 30 <Button guid="cmdImportClassesGUID" id="cmdImportClassesID" priority="0x0902" type="Button">
31 <Parent guid="guidCmdSet" id="grpidContextMain"/>
32 <Strings>
33 <CanonicalName>cmdImportClassesCanonicalName>
34 <ButtonText>Import from Existing ClassesButtonText>
35 Strings>
36 Button>
37 Buttons>
38 Commands>
39 40 <Symbols>
41 <GuidSymbol name="cmdImportDbSchemaGUID" value="{EC120F9A-9E7F-469d-8D61-F4E2A97E5725}">
42 <IDSymbol name="cmdImportDbSchemaID" value="0x810">IDSymbol>
43 GuidSymbol>
44 45 <GuidSymbol name="cmdImportClassesGUID" value="{EC120F9A-9E7F-469d-8D61-F4E2A97E5726}">
46 <IDSymbol name="cmdImportClassesID" value="0x811">IDSymbol>
47 GuidSymbol>
48 Symbols>
49 CommandTable>
Step#2: Modify Package version
- Locate the Package.tt , file , edit
- Increment the version number (2nd parameter) as shown below
Step#3: Search for "your" CommandSet class
- Search in your DSL Solution (DslPackage project) for the text “DslShell::CommandSet”
- You should notice that’s found 1 time in the CommandSet.cs
- If you now find the references for that found class (in this case DomainDesignCommandSetBase ) but in your project will be named differently. You should find that it’s derived + made partial to allow customization
- (optional) Create a folder to hold your own customized classes
- Create a partial class (as shown below)
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.ComponentModel.Design;
6 using Microsoft.VisualStudio.Modeling.Shell;
7 8 namespace GenWise.VsNet.DomainDesign.DslPackage
9 { 10 internal partial class DomainDesignCommandSet : DomainDesignCommandSetBase
11 { 12 // Note: Here you need to repeat the code from the VSCT .
13 // I could not find an easy way of re-using the Symbols from the vsct
14 public Guid dbImportSchemaGuid = new Guid("EC120F9A-9E7F-469d-8D61-F4E2A97E5725");
15 public const int dbImportSchemaID = 0x810;
16 17 public Guid dbImportClassesGuid = new Guid("EC120F9A-9E7F-469d-8D61-F4E2A97E5726");
18 public const int dbImportClassesID = 0x811;
19 20 21 protected override IListGetMenuCommands()
22 { 23 IListcommands = base.GetMenuCommands();
24 25 // You need to create a new command and add it to
26 // the commands collection.
27 DynamicStatusMenuCommand cmdImportDbSchema = 28 new DynamicStatusMenuCommand(
29 new EventHandler(OnPopUpMenuDisplayAction),
30 new EventHandler(OnPopUpMenuClick),
31 new CommandID(dbImportSchemaGuid, dbImportSchemaID));
32 commands.Add(cmdImportDbSchema); 33 34 // You need to create a new command and add it to
35 // the commands collection.
36 DynamicStatusMenuCommand cmdImportClasses = 37 new DynamicStatusMenuCommand(
38 new EventHandler(OnPopUpMenuDisplayAction),
39 new EventHandler(OnPopUpMenuClick),
40 new CommandID(dbImportClassesGuid, dbImportClassesID));
41 42 commands.Add(cmdImportClasses); 43 44 return commands;
45 } 46 47
56 internal void OnPopUpMenuDisplayAction(object sender, EventArgs e)
57 { 58 MenuCommand command = sender as MenuCommand;
59 60 foreach (object selectedObject in this.CurrentSelection)
61 { 62 if (selectedObject is ClassDiagram)
63 { 64 // The popmenu command is always visible
65 command.Visible = true;
66 command.Enabled = true;
67 return;
68 } 69 } 70 71 // The popmenu command is always visible
72 command.Visible = false;
73 command.Enabled = false;
74 } 75 76 internal void OnPopUpMenuClick(object sender, EventArgs e)
77 { 78 MenuCommand command = sender as MenuCommand;
79 80 StringBuilder sb = new StringBuilder();
81 foreach (object selectedObject in this.CurrentSelection)
82 { 83 sb.AppendLine("Selected Shape: " + selectedObject.ToString());
84 85 // the Current selection will hold your "shape" class, so if you are interested
86 // in getting the Model Class you need to use the ModelElement Property as shown below.
87 if (selectedObject is ClassShape)
88 { 89 ModelClass modelClass = (ModelClass)(selectedObject as ClassShape).ModelElement;
90 sb.AppendLine("*** Related Domain Class: " + modelClass.ToString());
91 } 92 93 if (selectedObject is ClassDiagram)
94 { 95 } 96 } 97 98 System.Windows.Forms.MessageBox.Show(sb.ToString()); 99 } 100 101 } 102 103 104 }Step #5 : Transform Templates + Test It
- Ok, finally, you can now transform templates + run + test it.
- You should see the following in your diagram:

How to access the Related Domain Object (given a shape)?
// the Current selection will hold your "shape" class, so if you are interested // in getting the Model Class you need to use the ModelElement Property as shown below.
87 if (selectedObject is ClassShape)
88 { 89 ModelClass modelClass = (ModelClass)(selectedObject as ClassShape).ModelElement;
90 sb.AppendLine("*** Related Domain Class: " + modelClass.ToString());
91 }How to control visibility of the Command?
Look at lines 56 - 74 from the previous code, it clearly shows how you can based on a condition, enable or disable the command.
Wednesday, December 19, 2007
Warning : Renaming a DSL --> old name still used in .tt files
The Solution is to manually also change all the .tt files that are still referencing the old name.
Default Name : DslDefinition.dsl
Search for this name and you will find that all the .tt files are still referencing the old name.
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\DslDefinition.dsl'" #>
<#@ include file="Dsl\ConnectionBuilder.tt" #>
