What’s the matter?
If you define Domain Properties on your Domain Classes and Shapes, you can configure the way a user of your DSL can interact with this Domain Properties. With the properties Is Browsable and Is UI Read Only you can hide a property from the Properties Window, make it read only or give the user full access to it.
But I want to change this behavior of certain Domain Properties dynamically at runtime!
Why the heck would someone need this? I don’t know, but I can tell why I need it: I’m designing a DSL with two types of users in mind. The DSL should look the same to both users, but one user can edit the whole DSL and change every property while the other user is not allowed to do so. Some properties will be disabled (read only) and some other properties will be invisible to the second user.
Another scenario could be a simple and advanced mode for some DSL Editor and the user can switch between these modes in some options dialog.
How do you use it?
First I want to describe the using of my library. If you are not interested in understanding how it works, you can use the library after reading this section.
First you have to define an enumeration with the modes your editor should support. The enumeration can contain more then two elements if you need more modes. The special Value 0 is used for the editor in the way you defined it within the DSL Tools. You should define your properties with Is Browsable set to true
and Is UI Read Only set to false
.
public enum RestrictionModes
{
Original = 0,
Simple,
Advanced
}
Than you can provide your Domain Classes and the Domain Model with the RestrictedProperty
-Attribute to configure the different properties:
[RestrictedProperty((int)RestrictionModes.Simple,
"P1", Restriction.Hidden)]
[RestrictedProperty((int)RestrictionModes.Simple,
"P2", Restriction.ReadOnly)]
[RestrictedProperty((int)RestrictionModes.Simple,
"P3", Restriction.ReadOnly)]
[RestrictedProperty((int)RestrictionModes.Advanced,
"P1", Restriction.Full)]
[RestrictedProperty((int)RestrictionModes.Advanced,
"P2", Restriction.Full)]
[RestrictedProperty((int)RestrictionModes.Advanced,
"P3", Restriction.ReadOnly)]
partial class ExampleModel
{
}
The ExampleModel
has three properties (P1
, P2
, P3
) and in the original DSL Editor these properties are all writable. Properties that are not mentioned by the attributes will work as defined.
If the Restriction Mode is set to RestrictionModes.Advanced
two of them are fully assessable (in fact you do not need to create Attributes to set the properties to Restriction.Full
since this is the default value) and one is read only. In the RestrictionModes.Simple
-case one property will be hidden and two are read only.
You can assign these attribute to each class that shows properties in the Properties Window. That are Model Elements, Shapes, Connectors and the Model itself.
After that you have to create a partial
class for your Package
and "activate" my library for each Class that uses these attributes:
partial class RestrictPropertiesTestPackage
{
protected override void Initialize()
{
UserRestrictionProvider.RegisterRestrictedElement<ExampleElement>();
UserRestrictionProvider.RegisterRestrictedElement<ExampleModel>();
base.Initialize();
}
}
Or use the shorter way to add all classes with one line of code. This will use reflection to find the classes.
UserRestrictionProvider
.RegisterAllRestrictedElements
<RestrictPropertiesExampleDiagram>();
Now there is only one step left: how to change the mode. Each Store
(that is the class where the Elements of a Model are stored in memory) is mapped to one Restriction Mode. So you can define one mode for each Store
and so one mode for each Model
or Diagram
. The Store
can be accessed from each ModelElement
, so as a key for this purpose it is a great value. There is a UserRestrictionProvider
class with two static
methods:
-
public static void SetRestrictionMode(Store store, int mode)
-
public static int GetRestrictionMode(Store store)
You can use these methods whenever you want to change the Restriction Mode. For the demo project I used a Domain Property of the Diagram with Custom Storage.
How does it work?
With the UserRestrictionProvider.RegisterRestrictedElement()
method I register a special TypeDescriptionProvider to the global Component Model (via the TypeDescriptor.AddProvider() method). This new Provider is be asked from the IDE whenever a list of all properties of a particular object is needed. At this point it is easy to remove some properties form the original list (this properties are not be shown in the Properties Windows) or make them read only (see the ReadOnlyPropertyDescriptor
class in my code).
For more in depth information feel free to take a look at the source code.
…but beware
All these property restrictions effect only the properties windows. The properties can be changed and accessed by code and via other elements of the DSL Designer (for example TextDecorators and the DSL Explorer).
Download
In the zip file you will find all described classes in one project and an example DSL project.
Update
This code is now part of the JaDAL – Just another DSL-Tools Addon Library project. Please download the current version from that page. The download over at CodePlex contains the source code described here, an example DSL language and the library as a binary. Future enhancements of the code will be published there, too.
Recent Comments