Thursday, June 25, 2009

Programmatically Changing Z-Order of DSL Shapes

If you want to programmatically change the Z-Order of a shape in a Visual Studio based DSL, don’t even bother trying to change the ZOrder property.  Rather, get the shape’s parent and change the order of the items in the NestedChildShapes collection.

This isn’t very well documented and a Google search using “zorder dsl change” doesn’t really pull up much useful information.  However (somewhat to my surprise) a Bing search using the same term turns up the answer as the first result.

Wednesday, June 10, 2009

How to Dynamically Customize the Property Window

The on-line help for the Microsoft Visual Studio Domain-Specific Language (DSL) tools explains how to prevent domain properties from appearing in the properties window:

You can prevent domain properties from appearing in the Properties window by setting the Is Browsable property to False. The Is Property Browsable property is available on domain roles.

However, this is a compile-time configuration.  This does not work if you need to optionally display a property based on some runtime state information.

Fortunately, a bit of digging with the most excellent Reflector tool shows that the Microsoft.VisualStudio.Modeling.Design.ElementTypeDescriptor has a virtual method, ShouldCreatePropertyDescriptor, that can be overridden.

Suppose you have a domain class Person with the properties IsMarried and WeddingDate.  You want the WeddingDate property to show in the property window only if the IsMarried property is true.

First, create a ElementTypeDescriptionProvider for the Person domain class:

class PersonTypeDescriptorProviderElementTypeDescriptorProvider    { }

Now, override the CreateTypeDescriptor() method to create a custom type descriptor named PersonTypeDescriptor:

class PersonTypeDescriptorProvider : ElementTypeDescriptionProvider

   {

   protected override ElementTypeDescriptor

        CreateTypeDescriptor(ICustomTypeDescriptor parent, ModelElement element)

     {return new PersonTypeDescriptor(parent, element);}

   }

 

Using the designer, select the Person domain class and a custom attribute of the type TypeDescriptionProvider passing the PersonTypeDescriptorProvider type to its constructor.

Now create the PersonTypeDescriptor class:

class PersonTypeDescriptor : ElementTypeDescriptor

{

    public PersonTypeDescriptor(

        ICustomTypeDescriptor parent,

        ModelElement element) :base(parent, element)

    {

    }

}

 

Finally, override ShouldCreatePropertyDescriptor method:

protected override bool ShouldCreatePropertyDescriptor(ModelElement requestor, DomainPropertyInfo domainProperty)

{

    if (domainProperty.Name == "WeddingDate")

        return ((Person)requestor).IsMarried;

    return base.ShouldCreatePropertyDescriptor(requestor, domainProperty);

}

 

It’s as simple as that.