FlowChart with NShape

Mar 19, 2013 at 1:42 PM
Edited Mar 19, 2013 at 3:57 PM
Hello,

I want to programm a little costum FlowChart-Editor with NShape by myself.

In this Editor the user can drop some SquareShapes and connect them with polylines. The polylines should have some text which represenst the conditions. I would realize this with textlables which are connected to the polyline.

My question now is :

Can i get information about the connections between two (or more) SquareShapes and their conditions?

For Example : I connect SquareShapes A to SquareShapes B with the Condition 1 and to SquareShapes C with the Condition 2.
Now i wanted to know ( in my code ), to which SquareShapes SquareShapesA is connected and which conditon this connection has.

Is something like that possible? Perhaps someone has a good code-example for a little FlowChart-Editor which would help me ?

Thanks in advance and sorry for my bad english.
Mar 19, 2013 at 6:47 PM
Edited Mar 19, 2013 at 6:49 PM
Hope this will give you the main idea:
private void SomeMethodInYourForm()
{
    var squareShapes = this.display1.Diagram.Shapes.OfType<Dataweb.NShape.GeneralShapes.Square>();
    if (!squareShapes.Any())
        Console.WriteLine("No 'Square' shapes found!");
    else
        foreach (var square in squareShapes)
            PrintConnectionInformation(square);
}

private static void PrintConnectionInformation(Dataweb.NShape.GeneralShapes.Square square)
{
    foreach (var connInfo in square.GetConnectionInfos(ControlPointId.Any, null)
        .Where(p => p.OtherShape is Dataweb.NShape.GeneralShapes.Polyline))
    {
        var connector = connInfo.OtherShape as Dataweb.NShape.GeneralShapes.Polyline;
        foreach (var connInfo2 in connInfo.OtherShape.GetConnectionInfos(ControlPointId.Any, null))
        {
            if (connInfo2.OtherShape == square || !(connInfo2.OtherShape is Dataweb.NShape.GeneralShapes.Square))
                continue;
            // We've found the connected Square:
            var connectedSquare = connInfo2.OtherShape as Dataweb.NShape.GeneralShapes.Square;
            // The last thing to do - find the Label shape attached to the connector:
            Dataweb.NShape.GeneralShapes.Label label = null;
            foreach (var connInfo3 in connector.GetConnectionInfos(ControlPointId.Any, null))
            {
                label = connInfo3.OtherShape as Dataweb.NShape.GeneralShapes.Label;
                if (label == null)
                    continue;
            }
            // Print out the results:
            Console.WriteLine("Square '{0}' is connected to Square '{1}' via Polyline {2}",
                square.Text,
                connectedSquare.Text,
                label == null
                    ? "with no condition defined"
                    : string.Format("with condition '{0}'", label.Text));
        }
    }
}
Mar 20, 2013 at 7:25 AM
Thanks a lot.

I tried it and i guess this is exactly what i'm looking for.

Thanks for your quick answer. :)
Mar 20, 2013 at 10:25 AM
One correction must be done in this code:
instead of
if (label == null)
    continue;
you should write
if (label != null)
    break;
Besides, you may find it useful to rewrite this code using extension methods and/or lambdas or Linq - to make it more readable and avoid nested loops.
Mar 20, 2013 at 11:37 AM
Sometimes it is important to understand how is the "connector" line directed. For example, in situations when your diagram describes some data flow, and so some shapes are "sources" and some are "targets" (or "senders" and "receivers"). Usually in such cases the connector is designed as an "arrow". NShape allows this to do.

Here's the modified code which will also print out information about the direction of each "connector" (for certainty, I assume that the "arrow" is made by applying the "OpenArrow" style to one of its caps):
private void SomeMethodInYourForm()
{
    var squareShapes = this.display1.Diagram.Shapes.OfType<Dataweb.NShape.GeneralShapes.Square>();
    if (!squareShapes.Any())
        Console.WriteLine("No 'Square' shapes found!");
    else
        foreach (var square in squareShapes)
            PrintConnectionInformation(square, this.project1.Design.CapStyles);
}

private static void PrintConnectionInformation(Dataweb.NShape.GeneralShapes.Square square, ICapStyles capStyles)
{
    foreach (var connInfo in square.GetConnectionInfos(ControlPointId.Any, null)
        .Where(p => p.OtherShape is Dataweb.NShape.GeneralShapes.Polyline))
    {
        var connector = connInfo.OtherShape as Dataweb.NShape.GeneralShapes.Polyline;
        foreach (var connInfo2 in connInfo.OtherShape.GetConnectionInfos(ControlPointId.Any, null))
        {
            if (connInfo2.OtherShape == square || !(connInfo2.OtherShape is Dataweb.NShape.GeneralShapes.Square))
                continue;
            // We've found the connected Square:
            var connectedSquare = connInfo2.OtherShape as Dataweb.NShape.GeneralShapes.Square;
            // Now we'll find the Label shape attached to connector:
            var label =
                connector.GetConnectionInfos(ControlPointId.Any, null)
                .Select(p => p.OtherShape)
                .FirstOrDefault(s => s is Dataweb.NShape.GeneralShapes.Label)
                as Dataweb.NShape.GeneralShapes.Label;
            // And find the "direction" of the connector:
            string directionInfo = FindConnectorDirection(connector, connInfo.OtherPointId, square, connectedSquare, capStyles);
            // Print out the results:
            Console.WriteLine("Square '{0}' is connected to Square '{1}' via Polyline {2} {3}",
                square.Text,
                connectedSquare.Text,
                label == null
                    ? "with no condition defined"
                    : string.Format("with condition '{0}'", label.Text),
                directionInfo);
        }
    }
}

private static string FindConnectorDirection(
    Dataweb.NShape.GeneralShapes.Polyline connector,
    ControlPointId connectorPointId,
    Dataweb.NShape.GeneralShapes.Square square,
    Dataweb.NShape.GeneralShapes.Square connectedSquare,
    ICapStyles capStyles)
{
    if (connector.EndCapStyle == capStyles.None
        && connector.StartCapStyle == capStyles.None)
        return "(connector is not directed)";
    if (connector.EndCapStyle == capStyles.OpenArrow
        && connector.StartCapStyle == capStyles.OpenArrow)
        return "(connector is bi-directed)";
    if (connector.EndCapStyle == capStyles.None
        && connector.StartCapStyle == capStyles.OpenArrow)
    {
        if (connectorPointId == ControlPointId.LastVertex)
            return string.Format("(connector is directed from Square '{0}' to Square '{1}')",
                                 square.Text, connectedSquare.Text);
        if (connectorPointId == ControlPointId.FirstVertex)
            return string.Format("(connector is directed from Square '{1}' to Square '{0}')",
                                 square.Text, connectedSquare.Text);
        return "(cannot determine connector direction)";
    }
    if (connector.EndCapStyle == capStyles.OpenArrow
        && connector.StartCapStyle == capStyles.None)
    {
        if (connectorPointId == ControlPointId.FirstVertex)
            return string.Format("(connector is directed from Square '{0}' to Square '{1}')",
                                 square.Text, connectedSquare.Text);
        if (connectorPointId == ControlPointId.LastVertex)
            return string.Format("(connector is directed from Square '{1}' to Square '{0}')",
                                 square.Text, connectedSquare.Text);
        return "(cannot determine connector direction)";
    }
    return "(cannot determine connector direction)";
}
I also avoided the third loop by using extension methods Select() and FirstOrDefault().

This code prints smth. like this:
Square 'aaa' is connected to Square 'bbb' via Polyline with condition '123' (connector is directed from Square 'bbb' to Square 'aaa')
Mar 21, 2013 at 3:50 PM
Very nice :)
Knowing the direction is really very useful .
Thank you very much for your fast help :)
May 26, 2016 at 7:30 AM
Edited May 26, 2016 at 9:14 AM
Hi i try this code block for same reason first message.

Image

"squareShapes" = 1,2,3,4,5 its ok.
1 connected to 2 ok.
1 connected to 5 ok.
5 connected to 1 ok.
5 connected to 2 ok.
2 connected to 1 ok.
2 connected to 5 ok.
3 and 4 connection no found.
Why?

I tried 1 connected to 3 or 3 connected to 5 no found not yet, but i add new square and connect to 3 or 4 found it.

Maybe 2-3-4-5 squares copy of 1 is this a problem?

And I changed 3-4 connectionline(polyline) with original line copy(3-4 polyline) its work :S no change on polyline copy and change original line. i guess this is a bug in my save file :)

How to change polyline default end or start capstyle open arrow?
Coordinator
May 31, 2016 at 9:43 AM
Edited May 31, 2016 at 12:55 PM
To be honest, I'm a bit confused by the description of your connection problem.
Can you tell me more about what you do?
  • Do you draw and connect the shapes with code, with the mouse in your own application or in the NShapeDesigner (shipped with NShape)?
  • Did you copy any of these shapes from another or did you create them from the tool box?
  • Can you provide me a step-by-step description (for dummies) of what you do exactly?
You can change the default line endings by editing the cap styles of the templates used to create the shapes.
Therefore, you can
  • Create all Templates by code
  • Create a NShape XML project file (with edited templates but without diagrams) and load it on program start
See Documentation: "Programmer Tasks > Customizing the Toolbox"
May 31, 2016 at 11:30 AM
Firstly thanks for all reply, my english is not enough i know.

I solved my problems, I would like to explain:
I drew diagram in the picture(with my app ArchiSketch Copy - i add archisketch form to my app) - draw with mouse- and i used code block. The boxes copies of each other. Code block couldnt find 3 with 4 connection. i try connect another shape(add new box and connect), and found it.
After i copy and replace 3-4 connection polyline its work, program found it. Probably it was a bug in my save file because i always open save file.

The other question is solved. I create template and add toolbox its ok.