Friday, December 28, 2007

Adding a Menu to a DSL ( 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 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 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 environment. I’ve created by accident 2 projects which shared the same ID and I was getting the wrong text.
  • Add Commands
Example modified VSCT File

   18 <Commands package="guidPkg">
   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>
   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>
   40   <Symbols>
   41     <GuidSymbol name="cmdImportDbSchemaGUID" value="{EC120F9A-9E7F-469d-8D61-F4E2A97E5725}">
   42       <IDSymbol name="cmdImportDbSchemaID" value="0x810">IDSymbol>
   43     GuidSymbol>
   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 , 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
Step#4: Customize your specific CommandSet
  • (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;
    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;
   17         public Guid dbImportClassesGuid = new Guid("EC120F9A-9E7F-469d-8D61-F4E2A97E5726");
   18         public const int dbImportClassesID = 0x811;
   21         protected override IList GetMenuCommands()
   22         {
   23             IList commands = base.GetMenuCommands();
   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);
   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));
   42             commands.Add(cmdImportClasses);
   44             return commands;
   45         }

   56         internal void OnPopUpMenuDisplayAction(object sender, EventArgs e)
   57         {
   58             MenuCommand command = sender as MenuCommand;
   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             }
   71             // The popmenu command is always visible
   72             command.Visible = false;
   73             command.Enabled = false;
   74         }
   76         internal void OnPopUpMenuClick(object sender, EventArgs e)
   77         {
   78             MenuCommand command = sender as MenuCommand;
   80             StringBuilder sb = new StringBuilder();
   81             foreach (object selectedObject in this.CurrentSelection)
   82             {
   83                 sb.AppendLine("Selected Shape: " + selectedObject.ToString());
   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                 }
   93                 if (selectedObject is ClassDiagram)
   94                 {
   95                 }
   96             }
   98             System.Windows.Forms.MessageBox.Show(sb.ToString());
   99         }
  101     }
  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.

Friday, December 21, 2007

NHibernate and WinForms article (1st draft)

As I've mentioned before, I am trying to create a Article for using NHibernate with Windows Forms (WinForms).

Both the article and the example project are not finished (it's work in progress) but I can't wait any longer , and therefore decided to share and get some initial feedback / reactions.

Wednesday, December 19, 2007

Warning : Renaming a DSL --> old name still used in .tt files

If you manually rename the DSL File ( DSLDefinition.dsl ) to something else you will notice that your project will not work anymore giving several weird error messages.

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\" #>

Monday, December 17, 2007

WinForms inheritance workaround

I've started some days ago with a simple mini-guide for creating Windows Forms Applications with NHibernate. It's not finished yet but what's interesting because I wanted to have visual inheritance in my application + using Generics. I initially thought that this should not be a problem but i was wrong.

After adding Generics support to my Forms + creating abstract Form , the Designer stopped working with one of those "ugly design-time errors" , which BTW are very nicely shown in 2008.
So my conclusion is : neither 2005 nor 2008 can easily support Generics + USer Control (or forms) inheritance (they both share this same "bug" / limitation ).

Luckily I found this workaournd from Frank Bakker .I could work-around and create a common/base UserControl for my Business Object UI.

Code Example:

public partial class ProductFormUC : ProductFormUCDummy
public ProductFormUC() : base()

public ProductFormUC(int pProductID) : this()
Product product = this.Repository.ProductDAO.Fetch(pProductID);
if (product == null)
throw new Exception("Not Found : was it deleted? improve this case");


categoryBindingSource.DataSource = this.Repository.CategoriesDAO.GetAll();
categoryBindingSource.DataMember = "CategoryName";

productBindingSource.DataSource = product;



This "intermediate" class makes the trick :
public partial class ProductFormUCDummy : BaseBOFormUC
protected override IDAO DAO
get { return this.Repository.ProductDAO; }


Wednesday, August 22, 2007

GenWise : Source Code Synchronization

In the last couple of projects we've noticed that we where loosing some "precious" time synchronizing code back from a VS.NET solution into the GenWise project system.

Although we have an integrated Source Editor, our users are constantly switching to VS.NET for debugging purposes. Sometimes while debugging, it’s needed to change code to test again, etc.

We have now created a feature to automatically synchronize those changes back to the project system.

This is a time save feature and allows to combine both worlds better.

We have not yet decided in what version we are going to include this feature.

Thursday, August 16, 2007

Fenix ASP.NET Generation == goodbye

Fenix was my first ASP.NET Generation templates. It was implemented as a Template chain inside the Clarion IDE.
Now it's time to say bye-bye to Fenix and finally put all our efforts in GenWise.

If you wanna read more about it :

Monday, June 25, 2007

NHibernate ILifecycle vs Validation Model

After reading this excellent article :

I finally understood why our Validation model was not hitting on Updates!
I thought it was some-kind-of-bug but it was definitively not so.

Since we just have released GenWise v1.09
--> this topic will be included in the next version of the Templates.

Wednesday, May 30, 2007

Intersystem Cache NHibernate Driver/Dialect

For a project we had to use Intersystem's Cache.

I've create the NHibernate Dialect and Driver (based on the Java version as a source).

I don't really know where to post this files so here they go : Download NHibernate Cache Driver/Dialect.

I now need to learn:
* Where to post so this get's added to Nhibernate.
* Before that step : are there any tests for new dialects (should i write them, how? )

My tests show 1 problem:
When trying to create a parameterized query using system.guid as parameter type i get this exception: CacheException : Type out of range: System.Guid

1) Standard_BoLayer.Tests.Email_AddressesTest.FetchTest : NHibernate.ADOException : could not execute query
[ SELECT this_."Email Address-ID" as Email1_7_0_, this_."Member_id" as Member2_7_0_, this_."System #" as System3_7_0_, this_."Mail@" as Mail4_7_0_, this_."Include in Mailing" as Include5_7_0_ FROM "dbo"."Email Addresses" this_ WHERE this_."Email Address-ID" = ? ]
Positional parameters: 0 aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
[SQL: SELECT this_."Email Address-ID" as Email1_7_0_, this_."Member_id" as Member2_7_0_, this_."System #" as System3_7_0_, this_."Mail@" as Mail4_7_0_, this_."Include in Mailing" as Include5_7_0_ FROM "dbo"."Email Addresses" this_ WHERE this_."Email Address-ID" = ?]
----> InterSystems.Data.CacheClient.CacheException : Type out of range: System.Guid
at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)

Saturday, April 28, 2007

GenWise Templates and the Project life-cycle

One of the unique features of the GenWise Template System is the fact that the templates are always alive during your project life-cycle. The Generation process is not a single step (normally an initial step) but it's present during the whole life-cycle.

This has major advantages:
#1) Template can adapt themselves to new scenarios
This is basically achieved by the fact that their input meta-data can change and template will regenerate their code according to the new input.
Several templates have "Auto Calculated Template Options", for this cases the advantage is even greater since the templates will also adapt the default values of the Template Options (Questions to the user).

#2) Template Option Changes can be easier applied since the Template Options are still available at the end of the project.

#3) Same applies to Global Changes, or global extension : like adding Security Template, make project Ajax aware ( Ajax Templates ), or any other extension.

#4 ) Template itself (new version) can improve or fix a specific scenario and this change might automatically apply to all template instances in your projects.

To make this possible, the IDE needs to keep a Project System. This project system is part of the GenWise Framework which contains ALL your project meta-data.

MySQL GetSchema("Views")

Today i've spend some time debugging why when we use GenWise Studio to import a MySQL database, Views (supported only in MySQL 5.x ) where not imported as VIEWS but where treated as normal TABLES.

Applies to : ODBC 5.00.11 (latest from website) and 3.54.14 shows same behaviour. Server version : 5.0.22

Having an odbc connection with catalog/database set to a specific database when executing this commands :

_connection.GetSchema("Tables") --> returns tables + views (should have been only tables)
If this was expected behaviour it would have been handy that "TABLE_TYPE" could be set as view.. (currently set as TABLE)
_connection.GetSchema("Views") --> returns null.

ODBC TRACE (just partial...)

When requesting VIEW ( _connection.GetSchema("Tables") ) --> 15 are returned instead of 14 (1 is a view)

NOTE: When INFORMATION_SCHEMA (at the server ) shows correct / expected result
SELECT * FROM information_schema.VIEWS V;

Friday, April 27, 2007

SourceGear Vault branching tool

Inside GenWise we had very often the situation that for testing a specific new feature we would need to create separate SourceGear Vault branch.

That's why Ward Bekker created this free tool to share with the community : Vault Branching Tool