Share via


Auto Layout Diagram

In the DSL project I am working on, I am performing layout for the model diagram myself. This problem mostly arises because we want two-way synchronization between model and code. Hence, after one of our users has modified the diagram by hand, if we update the model from code, the diagram can get screwed up. The DSL tools do not seem to have any  way to direct layout of a model automatically after it is loaded but before it is displayed. If you use the rule engine to layout model shapes using the RuleOn attribute, we discovered that the rules can get fired when the model is being built (there may be a way to eliminate this behavior however). Thus, we ended up with having to special case our layout rules with repeated adjustments. A second approach we took is to split the problem.

  1. When the model is already displayed and the user adds an element, then we only layout that shape and adjust the subsequent shapes. We assume that the model before the new shape was added is laid out correctly. Thus, we did not have to special case our rules and we were assured of a model that had been laid out well enough.
  2. When the model is being loaded, none of the layout rules fire. However, layout is performed after the model data has been fully loaded, but before the designer surface is displayed.

We achieved part (2) by overriding the LoadView method in the ModelNameDocView type. Something like this:

protected override bool LoadView()

{

bool status = base.LoadView();

if (status)

{

MantisTestDiagram diagram = this.Diagram as MantisTestDiagram;

diagram.LayoutEngine.Layout();

}

return status;

}

The LayoutEngine::Layout method walks through all the model shapes and relocations them correctly. A brief skeleton for this method looks like this:

 

this.parentDiagram.Store.RuleManager.SuspendRuleNotification();

 

try

{

using (Transaction t = this.parentDiagram.Store.TransactionManager.BeginTransaction("Model-Auto-Layout-" + this.parentDiagram.Id))

{

// do layout

t.Commit();

}

}

catch (Exception ex)

{

Utility.DisplayException(ex); // debug help

throw;

}

finally

{

this.parentDiagram.Store.RuleManager.ResumeRuleNotification();

}