Pablo Galiano :

Subscriptions

<October 2008>
SuMoTuWeThFrSa
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

News

Subscribe to Pablo Galiano by Email

Post Categories

DSL (RSS)

How do I create a ModelElement via API

My eighteenth How do I is up.

Scenario

Let's say that we start from the Minimal Language DSL template and we have an ExampleElement domain class that has a Name domain property with the Is Element Name flag set to true.

Because it has the IsElementName flag, every time that we create a ExampleElement with the UI (toolbox or model explorer) the element is created with a default name. This default name is composed of the type name of the concept plus an index. Example : ElementName1, ElementName2, etc.

The focus of this How do I shows how to create the model element programmatically.

 

Interfaces and classes needed

 

Code snippet

Wrong way:

private void CreateElement(Store store)

{

    using(Transaction tx = store.TransactionManager.BeginTransaction("Add ExampleElement"))

    {

        ExampleModel root = store.ElementDirectory.FindElements<ExampleModel>().First() as ExampleModel;

 

        ExampleElement element =

            this.Store.ElementFactory.CreateElement(ExampleElement.DomainClassId) as ExampleElement;

 

        root.Elements.Add(element);

 

        tx.Commit();

    }

}

 

Right way:

 

private void CreateElement(Store store)

{

    using(Transaction tx = store.TransactionManager.BeginTransaction("Add ExampleElement"))

    {

        ExampleModel root = store.ElementDirectory.FindElements<ExampleModel>().First() as ExampleModel;

 

        ExampleElement element =

            store.ElementFactory.CreateElement(ExampleElement.DomainClassId) as ExampleElement;

 

        ElementOperations elementOperations =

            new ElementOperations(store as IServiceProvider, store);

 

        ElementGroup elementGroup = new ElementGroup(store);

        elementGroup.Add(element);

        elementGroup.MarkAsRoot(element);

        elementOperations.MergeElementGroup(root, elementGroup);

 

        tx.Commit();

    }

}

 

 

Assemblies needed

  • Microsoft.VisualStudio.Shell.Interop
  • Microsoft.VisualStudio.Modeling.Sdk.Shell
  • Microsoft.VisualStudio.Modeling.Sdk.Diagrams

 

Stay tuned,

Pablo

posted Tuesday, September 30, 2008 8:17 AM by pga with 1 Comments

VSXDevCon08 pictures

Here are some pictures for the VSX Developer Conference with me in the front. :)

The videos are going to posted at MSDN soon...

 con08_1.png

con08_2.png

Pablo

posted Monday, September 22, 2008 2:33 PM by pga with 1 Comments

T4 Editor RTM is OUT!!!

As Victor announced it, after great efforts the T4 Editor v1.0 was finally out.

I don't need to tell you how much the user experience can drastically change when you use it, having syntax coloring, intellisense, code generation preview, support for multiple T4 hosts, etc etc.

Check it out here

Pablo

posted Monday, September 15, 2008 11:39 AM by pga with 0 Comments

How do I cancel a model element property value editing operation

My fourteenth How do I is up.

Scenario

Let's say that we want to cancel an editing operation in a model element property if the new value meets a certain condition. The focus of this How do I tackles this scenario.

In the next sample we have a MyLanguage dsl and a MyElement domain class and we want to cancel the editing operation over the "Foo" property if the new value is empty.

 

Interfaces and classes needed

 

Code snippet

    public partial class MyLanguageDomainModel

    {

        protected override Type[] GetCustomDomainModelTypes()

        {

            var types = new List<Type>();

 

            types.AddRange(base.GetCustomDomainModelTypes());

            types.Add(typeof(MyElementChangeRule));

 

            return types.ToArray();

        }

    }

 

    [RuleOn(typeof(MyElement), FireTime = TimeToFire.TopLevelCommit)]

    public partial class MyElementChangeRule : ChangeRule

    {

        public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)

        {

            if(!e.ModelElement.Store.TransactionManager.CurrentTransaction.IsSerializing)

            {

                if(e.DomainProperty.Name.Equals("Foo"))

                {

                    if(string.IsNullOrEmpty(e.NewValue.ToString()))

                    {

                        //The name cannot be empty, therefore we cancel the change

                        PackageUtility.ShowError(e.ModelElement.Store, "Value cannot be empty");

                        e.ModelElement.Store.TransactionManager.CurrentTransaction.Rollback();

                    }

                }

            }

        }

    }

Assemblies needed

  • Microsoft.VisualStudio.Modeling.Sdk, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

 

Stay tuned,

Pablo

posted Thursday, August 28, 2008 5:49 PM by pga with 1 Comments

How do I know when a model element is being added by a user demand

My ninth How do I is up.

Scenario

Let's say that we have some "Add rules" in our model to perform some custom operation every time a model element is added. One common problem is that we want to perform this operation only when the user creates a model element on demand, this can be translated to the user drags a shape from the toolbox, uses the model explorer, etc. But the add rule is also fired when the store is being deserialized and somehow we need to distinguish both cases. The focus of this How do I tackles this scenario.

 

Interfaces and classes needed

 

Code snippet

    var transaction = e.ModelElement.Store.TransactionManager.CurrentTransaction;

 

    if(transaction != null && !transaction.IsSerializing)

    {

//TODO: perform operation 

    }

 

Assemblies needed

  • Microsoft.VisualStudio.Modeling.Sdk

 

Stay tuned,

Pablo

posted Monday, August 25, 2008 6:32 AM by pga with 1 Comments

How do I get the model element associated to a shape and vice versa

My sixth How do I is up.

Scenario

The scenario here is really simple, we want to get the shape associated with a model element or vice versa. The focus of this How do I tackles this scenario.

 

Interfaces and classes needed

 

Code snippet

Getting the model element corresponding shape:

 

    PresentationViewsSubject.GetPresentation(modelElement)

        .ForEach(pel =>

            {

                ShapeElement shape = pel as ShapeElement;

 

                //TODO: use shape

            });

Getting the model element corresponding shape:

 

    ModelElement modelElement = PresentationViewsSubject.GetSubject(shape);

 

    //TODO: use model element

 

Assemblies needed

  • Microsoft.VisualStudio.Modeling.Sdk.Diagrams

 

Stay tuned,

Pablo

posted Wednesday, August 20, 2008 11:55 AM by pga with 1 Comments

TTxGen on MSDN Code Gallery

TTxGen is a generic single file generator based on the text templating engine.

What is that???, Some background:

Single file generators or custom tools are COM components registered with Visual Studio that generate code.

To implement a custom tool you basically need to implement the IVsSingleFileGenerator interface. For more detail you can read kzu's post 

A custom tool also needs to be registered and associated to file a extension.

The IVsSingleFileGenerator interface declares two methods:

int DefaultExtension (
	out string pbstrDefaultExtension
)

This method is used to specify the extension of the generated file.

int Generate (
	[InAttribute] string wszInputFilePath,
	[InAttribute] string bstrInputFileContents,
	[InAttribute] string wszDefaultNamespace,
	[OutAttribute] IntPtr[] rgbOutputFileContents,
	out uint pcbOutput,
	[InAttribute] IVsGeneratorProgress pGenerateProgress
)

This method is used to generate the code that we want. It receives the name of the file associated with custom tool, the content of the file and it returns a Byte[] with the generated code.

One serious drawback is that we need to implement, register and deploy one custom tool for each representation of custom code that we want to generate.

Ok that's all for custom tools, now the funny part...

As you may know the text templating (t4) engine is now part of Visual Studio 2008. Based on this I created an implementation of a generic single file generator using t4.

The idea here is to have the same context as in custom tools. For that I have created a custom directive processor that injects the context needed on the tt:

<#@ output extension=".xml" #>
<#@ ParentFileInjector processor="TTxGenDirectiveProcessor" requires="fileName='Sample.xml'" #>
<#= this.ParentFileName #>
<#= this.ParentFileContent #>

If we want to access the parent file name we can use the ParentFileName variable, and for the content we can use the ParentFileContent.

TTxGen comes with some tooling to create a xGen template with the proper directives and context to start generating code:

scn1

scn2

The Create xGen Template command unfold a tt template, default the extension to the extension of the parent file and it automatically replace the requires argument.

 

You can download TTxGen from codegallery.

 

Pablo

posted Monday, February 04, 2008 6:10 PM by pga with 7 Comments

Enabling C# or VB 3.5 inside a text template

What about adding any C# 3.5 feature (linq, extension methods, partial methods, etc) inside a text template file?

The procedure is really easy, just add the "C#v3.5" or "VBv3.5" to the language directive:

<#@ template language="C#v3.5"#>
<#@ Import Namespace="System.Linq" #>
<#@ Assembly Name="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" #>

Happy code generation...

Pablo

posted Tuesday, January 22, 2008 10:38 AM by pga with 1 Comments

Software Factories Toolkit is OUT!!!

The first CTP of the SFT or Clarius Software Factory Toolkit was released yesterday.

It has a lot features that will help you to author a guidance package:

  • VB Net support (Create a guidance package using VBNet)
  • DSL integration (Integrate your recipes with DSLs)
  • Eventing (Launch recipes based on VS events)
  • Scripting (Use the script value provider to assign values to recipe arguments inline)
  • Possibility to register a guidance package on the VS Exp Hive
  • Fixes for GAX known issues:
    • .gpstate and TFS issue fixed
  • and much more...

Please download it now and tell us your story. You could win a free MSDN Team Suite subscription.

On the next posts I will cover in more detail some of these features.

 

Pablo

posted Tuesday, December 19, 2006 6:15 AM by pga with 0 Comments

Integrating DSL RTM and GAX part four

As part of the DSL and GAX posts regarding integration, I would like to recommend an article made by Victor and Mauro named Guidance Automation Toolkit and Domain-Specific Language Tools for Visual Studio 2005: Integration Scenarios.

It describes the process of integrating both technologies, I provided some tips of my previous posts: Integrating DSL RTM and GAX part one , Integrating DSL RTM and GAX part two ,  Integrating DSL RTM and GAX part three

A must read...

Pablo

posted Thursday, November 09, 2006 10:03 AM by pga with 0 Comments

Integrating DSL RTM and GAX part three

On the part two, I talked about launching recipes from the DSL Designer.

Another posibility is to launch a recipe from the DSL Language Explorer. For that we need the command bar GUID and ID.

The good news is that the commandbar GUID is the same that the one for the DSL Designer

The ID for the Language Explorer will always be 65537.

DSLLangExplorer.JPG

 

Pablo

posted Wednesday, October 18, 2006 11:49 AM by pga with 1 Comments

Integrating DSL RTM and GAX part two

Once we have the guidance package and the DSL package living on the same visual studio hive one thing that we will need for sure is the ability to launch recipes from the DSL designer.

For that we need to find out the command bar GUID of the DSL designer.

Steps:

  • Open the DSL solution
  • Open the Constants.cs file located under the DslPackage.csproj
  • Look for:         

    internal static partial class Constants

    {

        // Menu identifier

        public const string Language1CommandSetId = "a00ac613-8df8-4537-b7c7-89d31a44651c";

    }

  • Update the HostData section of the recipe manifest

  < HostData >

    < CommandBar Guid ="a00ac613-8df8-4537-b7c7-89d31a44651c"ID="65536"/>

  </ HostData

 

      Notice that the ID for the DSL RTM version will always be 65536.

 

Pablo

posted Monday, October 09, 2006 9:39 AM by pga with 2 Comments

Integrating DSL RTM and GAX part one

A guidance package and a DSL package are registered by default in different visual studio hives. A guidance package lives on the main hive and a DSL package lives on the Experimental one.

So the first thing that we need to do is migrate one of the packages so the live on the same hive.

I am going to migrate the DSL package to the main hive, the procedure is very simple:

A DSL solution consists of 2 projects, the Dsl.csproj and DslPackage.csproj and we need to edit both:

Dsl.csproj:

Change the line:

  <PropertyGroup>
    <StartProgram>$(DevEnvDir)\devenv.exe</StartProgram>
    <StartAction>Program</StartAction>
    <StartArguments>/rootsuffix Exp /DesignTimeRun "..\..\..\Debugging\Debugging.sln"</StartArguments>
  </PropertyGroup>

To

  <PropertyGroup>
    <StartProgram>$(DevEnvDir)\devenv.exe</StartProgram>
    <StartAction>Program</StartAction>
    <StartArguments>/DesignTimeRun "..\..\..\Debugging\Debugging.sln"</StartArguments>
  </PropertyGroup>

DslPackage.csproj:

Change the line:

  <PropertyGroup>
    <StartProgram>$(DevEnvDir)\devenv.exe</StartProgram>
    <StartAction>Program</StartAction>
    <StartArguments>/rootsuffix Exp /DesignTimeRun "..\..\..\Debugging\Debugging.sln"</StartArguments>
  </PropertyGroup>

To

  <PropertyGroup>
    <StartProgram>$(DevEnvDir)\devenv.exe</StartProgram>
    <StartAction>Program</StartAction>
    <StartArguments>/DesignTimeRun "..\..\..\Debugging\Debugging.sln"</StartArguments>
  </PropertyGroup>

And

<TargetRegistryRoot>Software\Microsoft\VisualStudio\8.0Exp</TargetRegistryRoot>

To

<TargetRegistryRoot>Software\Microsoft\VisualStudio\8.0</TargetRegistryRoot>

 

After this changes the guidance package and the DSL will live in the same visual studio hive, which means that one is going to be "visible" by the other and viceversa.

 

Pablo

posted Monday, October 09, 2006 9:17 AM by pga with 1 Comments

Executing a GAT recipe from the DSL surface area

To execute a recipe you need to find out which is the GUID for the DSL. This GUID is different for every DSL project that we create.

So, you need to open the GeneratedCmd.cs class file located at \Shell on the Designer project and search for the following constant:

public const string guidDSLNAMEMenuString = "GUID";

For example if we have a DSL named DSLFoo, then we need to search for the constant named guidDSLFooMenuString.

Once we have the GUID, we need the ID. For the DSL menu it will always be 256.

If we supose that we have a guidDSLFooMenuString constant with a value of  “d309f791-903f-11d0-9efc-00a0c911004f“, then the CommandBar will be:

<CommandBar Guid="d309f791-903f-11d0-9efc-00a0c911004f" ID="256"/>

Pablo

posted Wednesday, April 05, 2006 3:11 AM by pga with 1 Comments

T4 syntax coloring and Intellisense!!!

Gaston Milano developed an addin fron Visual Studio 2005, to support intellisense and syntax coloring for T4 Templates.

It works really great.

Pablo

posted Sunday, March 19, 2006 2:08 PM by pga with 1 Comments

T4 Syntax for DSL Tools

I've found a great post about T4 syntax.

http://blogs.msdn.com/garethj/archive/2005/06/01/T4Syntax.aspx

Pablo

 [Via GarethJ's WebLog]

posted Thursday, November 03, 2005 12:33 AM by pga with 2 Comments

DSL Toolkit September CTP released

You can download it from here.

Pablo

posted