Proper way to add shape to diagram from code

Nov 22, 2012 at 5:41 PM

Hi,

I want to add shape to diagram from code - but achieve exactly the same result as if I drop it from the toolbox. The following code seems to be incorrect or at least not complete because although the shape gets created its ModelObject is null:

private void CreateDiagramWithOneShape()
{
    Diagram diagram = new Diagram("Test NShape diagram");
    this.display1.Diagram = diagram;
    this.cachedRepository1.Insert(diagram);
    // Now add shape to diagram:
    Shape myShape = this.project1.ShapeTypes["MyShape"].CreateInstance();
    myShape.DisplayService = this.display1;
    diagram.Shapes.Add(myShape);
    this.project1.Repository.Insert(myShape, diagram);
    this.project1.Repository.Update();
}

What is the proper way to do that?

PS: if I add the same shape ("MyShape") manually, from toolbox - everything is fine.

Nov 23, 2012 at 6:47 AM

The following code seems to work:

Shape myShape = this.project1.Repository.GetTemplate("MyShape").CreateShape();
this.display1.InsertShape(myShape);

Is it correct? can I use it?

Coordinator
Nov 23, 2012 at 10:34 AM

Yes.

Nov 23, 2012 at 11:59 AM
Edited Nov 23, 2012 at 1:57 PM

Thank you!

[UPDATE] However, I get an error "Arithmetic operation resulted in an overflow" when I right-click on the shape which I created programmatically. This error occurs in the following method of the ShapeCollection class:

public Shape FindShape(int x, int y, ControlPointCapabilities controlPointCapabilities, int range, Shape startShape) {
    return GetFirstShapeInArea(x - range, y - range, 2 * range, 2 * range, controlPointCapabilities, startShape, SearchMode.Near);
}

If I check values of the x and y variables - they are equal to Int32.MinValue.

Note that before right-clicking on this shape, I have to scroll the diagram upwards so that the shape comes into view: when it is added programmatically, it is added at the (0; 0) position which is initially not visible.

If before right-clicking I make a single left click on this shape - then the following right click works fine (brings up the shape's context menu)!

Why?!

[UPDATE] If after "this.display1.InsertShape(myShape);" I add "myShape.MoveBy(500, 500);" so that my shape is initially visible (and I do not need to scroll the diagram) - nothing changes: I still get the same error. Maybe this is important.

Coordinator
Nov 28, 2012 at 7:34 AM

The movement to the desired position is necessary. The diagram inserts the shape as it is - at its default location with the default size.
Is your shape initialized to a valid size (Width/Height) in "InitializeToDefault" (by your implementation or the base class' implementation)?
I tried your sample code with "RoundedBox" instead of "MyShape" and it works fine:

private void CreateDiagramWithOneShape()
{
    Diagram diagram = new Diagram("Test NShape diagram");
    this.display1.Diagram = diagram;
    this.cachedRepository1.Insert(diagram);
    // Now add shape to diagram:
    Shape myShape = this.project1.ShapeTypes["RoundedBox"].CreateInstance();
    myShape.DisplayService = this.display1;
myShape.MoveTo(diagram.Width / 2, diagram.Height / 2); // Move the shape to the desired position diagram.Shapes.Add(myShape); this.project1.Repository.Insert(myShape, diagram); this.project1.Repository.Update(); }
Nov 28, 2012 at 8:29 AM
KurtHolzinger wrote:

Is your shape initialized to a valid size (Width/Height) in "InitializeToDefault" (by your implementation or the base class' implementation)?

Yes, it is:

protected override void InitializeToDefault(IStyleSet styleSet)
{
    base.InitializeToDefault(styleSet);
    this.CharacterStyle = styleSet.CharacterStyles["Black Tahoma 8 Bold"];
    this.Width = 150;
    this.Height = 50;
}

As I said before, I also tried moving shape from its default position, but this didn't help.

BTW, the default location of the shape is (0; 0) but not (Int32.MinValue; Int32.MinValue), so I do not understand why x and y are both set to Int32.MinValue.

Coordinator
Nov 28, 2012 at 1:34 PM

Can you reproduce it using e.g. "RoundedBox" instead of "MyShape"?
Could you please provide me with a small demo where I can reproduce the issue? You can send the demo to support_at_dataweb_dot_de.

Nov 28, 2012 at 5:09 PM

Hi,

I've sent you a small project demonstrating the problem.
If you start it and right-click on the RoundedBox shape – you’ll get the OverflowException.
But if you comment out the Form1.CreateTools() method call – the problem goes away.
This method creates two custom tools (MySelectionTool and MyPlanarShapeCreationTool) according to your recommendations given in this topic.
Please note that problem remains even if I comment out the inner code of these tools so that they add nothing to the functionality of their base classes!

Coordinator
Nov 29, 2012 at 7:13 AM
Edited Nov 29, 2012 at 7:33 AM

Thanks for your demo program. I can reproduce the issue and I've found the problem:
[Edit:] Your display has a tool assigned that is no longer part of the toolSetController after you have cleared its contents. Due to this fact, all ProcessMouseEvent calls go to the wrong instance and the CurrentTool of the display does know the current mouse position (which is in turn the default value Geometry.InavlidPoint (int.MinValue) you have seen). [End of Edit]

The solution is quite simple:
After you clear the toolbox (and delete the Display.CurrentTool) and create a new SelectionTool, add it to the toolSetCOntroller and assign it to the Display.CurrentTool property:

        private void CreateTools()
        {
            this.toolSetController1.Clear();
            this.toolSetController1.AddTool(new MySelectionTool(), true);
            this.display1.CurrentTool = toolSetController1.DefaultTool;
            ...
        }

We will think about how to improve the framework in order to prevent others from running into this issue.
Thanks for your feedback.

Nov 29, 2012 at 1:38 PM

Thank you, it works!