Using “AddRule” problem: how we can distinguish between diagram loading situation and user d

Hello!

How we can define aAddRuleto fire only when user drag & drop a domain class into diagram via toolbar?

I’m trying to simplify my DSL’s developer tasks while he drags a domain class into diagram (e.g. add related domain classes, …) , for this propose the suggestion is to using “AddRule”, but I have a simple problem with AddRule: when I use this technique, my AddRule class is called whenever the file (diagram) open and load! How can I bypass my AddRule when diagram is opened?

Is there any way to check is current ModelElemet new or exist (in “ElementAddedEventArgs” of “ElementAdded” at “AddRule”) ?

Thanks,

H. Kavousi

[1594 byte] By [H.Kavousi] at [2007-12-28]
# 1
Check Transaction.IsSerializing.

public override void ElementAdded(ElementAddedEventArgs e)
{
base.ElementAdded(e);

ModelClassProperty property = e.ModelElement as ModelClassProperty;
if (property != null)
{
Transaction transaction = property.Store.TransactionManager.CurrentTransaction;

if (transaction != null && !transaction.IsSerializing)
//Handle
}
}

GokhanAltinoren at 2007-9-4 > top of Msdn Tech,Visual Studio,Visual Studio Extensibility...
# 2

Hi;

Great, and a clever approach, tanks a lot Gokhan; it worked properly J

But yet I have a problem with “AddRule”: this rule is called in recursive style! Means when I add an element in AddRule handler, this cause the AddRule call again, and code fall into an infinite loop! I can’t stop and or bring to an end this loop, because there is no method for that. Is there any way to handle this problem?

And also tanks again for any reply.

H.Kavousi at 2007-9-4 > top of Msdn Tech,Visual Studio,Visual Studio Extensibility...
# 3

Hi,

The transaction context object has a property bag that you can add custom data to, so you could use this to keep track of the model elements you have created in code and not do anything when the add rule fires for these elements. The following code shows how you could do this.

/// <summary>

/// Rule to add a second comment whenever a comment is added

/// to a model

/// </summary>

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

internal sealed class AddCommentRule : AddRule

{

public override void ElementAdded(ElementAddedEventArgs e)

{

// Get a ref to the top-level transaction

Transaction outerTransaction = e.ModelElement.Store.TransactionManager.CurrentTransaction.TopLevelTransaction;

// Don't do anything on deserialization

if (outerTransaction.IsSerializing) { return; }

// Transactions have a ContextInfo dictionary to which you can

// add your own data items. We will add a list that contains the

// items that we have manually created that we don't want

// to run the add rule for.

// Name of our data item

const string createdItemsKeyName = "createdItems";

// List of items that we created manually

List<ModelElement> createdItems;

// Get the list of added items for this transaction, or create it

// if it does not exist.

if (outerTransaction.Context.ContextInfo.ContainsKey(createdItemsKeyName))

{

createdItems = (List<ModelElement>)outerTransaction.Context.ContextInfo[createdItemsKeyName];

}

else

{

createdItems = new List<ModelElement>();

outerTransaction.Context.ContextInfo.Add(createdItemsKeyName, createdItems);

}

// Check whether the current model element is one we created in code

if (createdItems.Contains(e.ModelElement))

{

// Comment was created in code - do nothing

}

else

{

// Comment not created in code - created another

Comment newComment = new Comment(e.ModelElement.Store);

newComment.Text = "Created comment";

// Associate the new comment with the model9

Comment comment = e.ModelElement as Comment;

comment.ModelRoot.Comments.Add(newComment);

// Store a ref to the new model element in the

// transaction context

createdItems.Add(newComment);

}

}

}

However, because this is a rule, it will fire regardless of how the new items are added to the model; via the toolbox, the model explorer, or via code. This may or may not be the behaviour you want.

If you just wanted to add multiple items when dragging from the toolbox, you could override the "CreateElementToolPrototype" method of the model element instead. This method returns a blueprint of the items that will be merged into the model when dragging from the toolbox. The default generated version of the method just adds a single item, but you could change this to add multiple items.

If you want to add two items just when dragging from the toolbox or when clicking "Add" in the model explorer, then you could override the "MergeConfigure" of the model element to create the new item and link it to the model.

Duncan

DuncanP-MSFT at 2007-9-4 > top of Msdn Tech,Visual Studio,Visual Studio Extensibility...
# 4
Hi Duncan and Everyone,

Duncan said:

However, because this is a rule, it will fire regardless of how the new items are added to the model; via the toolbox, the model explorer, or via code. This may or may not be the behaviour you want.

How can I then apply this rule only if the element is added from toolbox not from the code? If this question is a repost, please point me to the related link. TIA.

NB: I changed the Subject Title a little bit, so it fits my problem - if you don't mind.

Regards,

HerruPerdana at 2007-9-4 > top of Msdn Tech,Visual Studio,Visual Studio Extensibility...
# 5

Herru,

The example rule above does what you want: the rule always fires, but it looks for extra information stored in the context of the transaction to detect model elements that it should ignore.

If you add the above rule to a new language based on the Class Diagram, then every time you add a new comment (either from the toolbox or through the model explorer), the rule will add a second comment. The following code snippet shows how you would add a new comment in code that the rule would ignore.

Code Snippet

// Code assumes that it is called from the ClassDiagram domain class

private void AddCommentInCode()
{
using (Transaction t = this.Store.TransactionManager.BeginTransaction("Add comment in code"))
{
// Create a new comment and link it to the model
Comment newComment = new Comment(this.Store);
newComment.Text = "Comment added in code";
((ModelRoot)this.ModelElement).Comments.Add(newComment);

// Record the fact that we created this comment in
// code
List<ModelElement> createdItems = new List<ModelElement>();
t.Context.ContextInfo.Add("createdItems", createdItems);
createdItems.Add(newComment);

t.Commit();
}
}

Duncan

DuncanP-MSFT at 2007-9-4 > top of Msdn Tech,Visual Studio,Visual Studio Extensibility...
# 6
Thanks, Duncan.
HerruPerdana at 2007-9-4 > top of Msdn Tech,Visual Studio,Visual Studio Extensibility...
# 7

The Propertybag in the TransactoinContext is fine. However I wanted to do better and did this:

Code Snippet

internal class DragDropTransactionContext : DslModeling.TransactionContext

{

public DragDropTransactionContext(DiagramDragEventArgs dragArgs)

{

this.dragArgs = dragArgs;

}

public DiagramDragEventArgs dragArgs;

}

public partial class MyDiagram

{

public override void OnDragDrop(DiagramDragEventArgs e)

{

using (DslModeling::Transaction tx = Store.TransactionManager.BeginTransaction("Drag & Drop", false, new DragDropTransactionContext(e))) // the typesafe and nice way to convey the dragargs into the transaction

In words, I derived from TransactionContext and passed it to BeginTransaction(....., TransactionContext c);

Then, in the rule I wanted to do this:

Code Snippet

if (Store.TransactionManager.CurrentTransaction.Context is DragDropTransactionContext)

{ ....

Oh sheer beauty of my code, but this does not work. I found out why: BeginTransaction COPIES the bag from my DragDropTransactionContext instance into its own created context. I think this implementation is unlucky and unexpected. So my suggestion and wish is:

TransactionManager.BeginTransaction( , , , TransactionContext)

should be changed such that a given context is used as the context of the transaction.

Love to hear comments.

And my honest respect for the dsl tools team, I just love it.

(waiting for the book to ship to my office)

citykid2 at 2007-9-4 > top of Msdn Tech,Visual Studio,Visual Studio Extensibility...

Visual Studio

Site Classified