Enable Ports

Hi Support!

I created a class to design a “Pool object”, and I would like to know if there is a way to enable Ports in my class, I would like to link Pool with Pool, but I don´t know how to create ports in my class. Can you help me with an example, please ? How can I change my code to enable ports?
I create this class based on Planogrammer4 example. So, is there a way to insert ports in Rack object in Planogrammer4 example?

Thanks.

See my code class:

//Diagram Pool
public class Pool : PoolDisplay
{
    //Variables
    private static readonly Pen StandardPen = new Pen(Color.Black, 1);
    private static readonly Pen HighlightPen = new Pen(Color.Green, 1);
    private int CellGridSize = 3;

    //Constuctor
    public Pool()
    {
        this.Label.Text = "Pool";
    }


    //Create Grid
    protected override GoGrid CreateGrid()
    {
        GoGrid grid = new PoolGrid();
        grid.Selectable = false;
        grid.AutoRescales = true;
        grid.Resizable = true;
        grid.ResizesRealtime = true;
        grid.Bounds = new RectangleF(0, 0, 50, 50);
        grid.SnapDrag = GoViewSnapStyle.Jump;
        grid.SnapResize = GoViewSnapStyle.Jump;
        grid.CellSize = new SizeF(CellGridSize, CellGridSize);
        grid.Style = GoViewGridStyle.None;
        grid.Pen = new Pen(Color.Black, 1);
        grid.BrushColor = Color.White;

        return grid;
    }



    //Make sure the Lane's Label is positioned above the top-left corner of the Grid; this makes it potentially useful 
    //for selection and dragging even if all of the grid is covered by Items
    public override void LayoutChildren(GoObject childchanged)
    {
        if (this.Count >= 2)
        {
            GoGrid grid = this.Grid;
            GoText label = this.Label;

            if (grid != null && label != null)
            {
                //Label in Left side
                label.Width = grid.Height;
                PointF center = grid.GetSpotLocation(MiddleLeft) - new SizeF(label.Height / 2 + 1, 0);
                label.Center = center;
            }
        }
    }


    //The Location of a Lane is actually the Position of its Grid
    public override PointF Location
    {
        get { return this.Grid.Position; }
        set
        {
            SizeF off = GoTool.SubtractPoints(this.Grid.Position, this.Position);
            SizeF pos = GoTool.SubtractPoints(value, off);
            this.Position = new PointF(pos.Width, pos.Height);
        }
    }


    //Show a differente color when node is dragged into lane
    public override void SetHighlight(bool show)
    {
        GoGrid grid = this.Grid;
        if (grid != null)
        {
            if (show)
            {
                grid.Pen = Pool.HighlightPen;
            }
            else
            {
                grid.Pen = Pool.StandardPen;
            }
        }
    }

}




//Diagram Pool Grid
public class PoolGrid : GoGrid
{
    //Variables
    private int CellGridSize = 3;
    private int MinSizeW = 50;
    private int MinSizeH = 50;

    
 //Constructor
    public PoolGrid()
    {
    }


    //The grid in a Poll only snaps Lanes
    public override bool CanSnapPoint(PointF p, GoObject obj, GoView view)
    {
        if (!(obj is Lane))
        {
            return false;
        }

        // do standard checks, such as whether the grid is a child of the OBJ,
        // the value of the grid's snap style, whether the OBJ intersects with the grid,
        // and whether the mouse point is in the grid
        return base.CanSnapPoint(p, obj, view);

    }


    public override RectangleF ComputeResize(RectangleF origRect, PointF newPoint, int handle, SizeF min, SizeF max, bool reshape)
    {
        RectangleF r = base.ComputeResize(origRect, newPoint, handle, min, max, reshape);
        Pool pool = this.Parent as Pool;
        if (pool != null)
        {
            RectangleF rMin = new RectangleF();
            bool any = false;
            foreach (GoObject obj in pool.GetEnumerator())
            {
                if (obj is Lane)
                {
                    if (!any)
                    {
                        rMin = obj.Bounds;
                        any = true;
                    }
                    else
                    {
                        // add the object's bounding rect to this one
                        rMin = UnionRect(rMin, obj.Bounds);
                    }
                }
            }
            if (any) r = UnionRect(r, rMin);
        }

        r.Width = Math.Max(1, (float)Math.Round(r.Width / CellGridSize)) * CellGridSize;
        r.Height = Math.Max(1, (float)Math.Round(r.Height / CellGridSize)) * CellGridSize;

        return r;
    }


    static RectangleF UnionRect(RectangleF a, RectangleF b)
    {
        float minx = Math.Min(a.X, b.X);
        float miny = Math.Min(a.Y, b.Y);
        float maxr = Math.Max(a.X + a.Width, b.X + b.Width);
        float maxb = Math.Max(a.Y + a.Height, b.Y + b.Height);
        return new RectangleF(minx, miny, maxr - minx, maxb - miny);
    }


    public override void DoResize(GoView view, RectangleF origRect, PointF newPoint, int whichHandle, GoInputState evttype, SizeF min, SizeF max)
    {
        base.DoResize(view, origRect, newPoint, whichHandle, evttype, new SizeF(MinSizeW, MinSizeH), max);  // specify minimum resizing Size
    }

}




//Diagram Pool Group Display
public class PoolDisplay : GoGroup, IGoLabeledNode
{

    //Variables
    private int CellGridSize = 3;

    //Constructor
    protected PoolDisplay()
    {
        //The Grid is always first, in the background
        Add(CreateGrid());
        Add(CreateLabel());
    }

    //Create Grid
    protected virtual GoGrid CreateGrid()
    {
        GoGrid grid = new PoolGrid();
        grid.Selectable = false;
        grid.AutoRescales = true;
        grid.Resizable = true;
        grid.ResizesRealtime = true;
        grid.Bounds = new RectangleF(0, 0, 50, 50);
        grid.SnapDrag = GoViewSnapStyle.Jump;
        grid.SnapResize = GoViewSnapStyle.Jump;
        grid.CellSize = new SizeF(CellGridSize, CellGridSize);
        grid.Style = GoViewGridStyle.None;
        grid.Pen = new Pen(Color.Black, 2);
        grid.BrushColor = Color.White;
        return grid;
    }

    //Create label
    protected virtual GoText CreateLabel()
    {

        //Label Left Side
        RotatedText label = new RotatedText();
        label.Selectable = false;
        label.Multiline = true;
        label.Editable = true;
        label.FontSize = 11;
        label.TransparentBackground = false;
        label.BackgroundColor = Color.White;
        label.Bordered = true;
        // settings for rotation. 
        label.AutoResizes = false;
        label.Alignment = Middle;
        label.Angle = 270;
        return label;
    }

    public virtual GoText Label
    {
        get { return this[1] as GoText; }
    }

    //Get Grid
    public virtual GoGrid Grid
    {
        get { return this[0] as GoGrid; }
    }

    //IGoLabeledNode:
    //Get Label
    //Set and Get Label text
    public virtual String Text
    {
        get
        {
            GoText lab = this.Label;
            if (lab != null)
                return lab.Text;
            return null;
        }
        set
        {
            GoText lab = this.Label;
            if (lab != null)
                lab.Text = value;
        }
    }

    public override void DoBeginEdit(GoView view)
    {
        if (this.Label != null)
        {
            this.Label.DoBeginEdit(view);
        }

    }

    public override bool CanEdit()
    {
        return base.CanEdit();
    }

    //if the Label is not visible or if the view has a small DocScale,it's handy to be able to see the name of the lane
    public override String GetToolTip(GoView view)
    {
        return this.Text;
    }

    //Selection:

    //let users resize the grid, not the whole Lane
    public override GoObject SelectionObject
    {
        get { return this.Grid; }
    }

    public override bool CanSelect()
    {
        return base.CanSelect();
    }

    //Unlike normal GoGroups, PickObjects picks all children at a particular PointF, not just the "top" one
    public override IGoCollection PickObjects(PointF p, bool selectableOnly, IGoCollection coll, int max)
    {
        if (coll == null) coll = new GoCollection();
        if (coll.Count >= max) return coll;
        if (!CanView()) return coll;
        foreach (GoObject child in this.Backwards)
        {
            PoolDisplay disp = child as PoolDisplay;
            if (disp != null)
            {
                disp.PickObjects(p, selectableOnly, coll, max);
            }
            else
            {
                GoObject picked = child.Pick(p, selectableOnly);
                if (picked != null)
                {
                    coll.Add(picked);
                    if (coll.Count >= max) return coll;
                }
            }
        }
        return coll;
    }

    //Dragging:

    //when dragging a non-Display onto a Display, highlight it to indicate that the dropped object(s) will be added to the Display
    public override bool OnEnterLeave(GoObject from, GoObject to, GoView view)
    {

        if (from is PoolDisplay && from != this)
        {
            ((PoolDisplay)from).SetHighlight(false);
        }

        SetHighlight(view.Tool is GoToolDragging && to == this && !view.Selection.IsEmpty && IsAddable(view.Selection.Primary) && view.Selection.Primary.Parent != this);

        return true;
    }

    //Called after a GoToolDragging drop
    public override bool OnSelectionDropped(GoObjectEventArgs evt, GoView view)
    {
        view.Selection.AddRange(AddItems(view.Selection));
        return true;
    }

    //Don't add pools as children of this Display
    public virtual bool IsAddable(GoObject obj)
    {
        if (obj is Lane)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    //Return a collection of objects that actually are added to this Pool
    public virtual IGoCollection AddItems(IGoCollection coll)
    {
        //Skip all dropped Lanes -- just include Items and GoText labels
        GoCollection items = new GoCollection();

        foreach (GoObject obj in coll)
        {
            if (IsAddable(obj))
            {
                items.Add(obj);
            }
        }

        if (items.IsEmpty)
        {
            return items;
        }

        IGoCollection added = AddCollection(items, false);

        return added;
    }

    //Visually distinguish this Display from others, to indicate that it can (or just did) add an Item
    public virtual void SetHighlight(bool show)
    {
    }

}

You started with Planogram’s Display class? Changing that to derive from GoBoxNode instead of GoGroup might be all you need to do. (I haven’t tried this)

I changed, but as you can see in your demo, if you changed GoGroup to GoBoxNode, everywhere where you call .Grid, will show an error!Tthe first error was showed in constructor… This line failed! So, is there a way to adjust it ?

r.Grid.Bounds = new RectangleF(150, 150, 300, 300);

Rack r = new Rack();
r.Text = “Rack 1”;
r.Grid.Bounds = new RectangleF(150, 150, 300, 300);
doc.Add®;

A runtime error, right? You’ve added parts to your “Group/Node” now, and Grid isn’t the object at this[0] anymore. Look at how “Get Grid” is implemented.

Hi Jake, thank you for information. Please, can you help me with 2 details ?

  1. I don´t know why when I selected GoGroup , objects inside are not with the same size of it…
  2. I don´t know how to adjust GoBoxNode port

Please, I need your help. I just want to connect GoBoxNode Objects ( in my case, connect Pool with Pool - BPM )

See my image:

//Diagram Pool
[Serializable]
public class Pool : PoolDisplay
{
    //Variables
    private static readonly Pen StandardPen = new Pen(Color.Black, 1);
    private static readonly Pen HighlightPen = new Pen(Color.Green, 1);
    private int CellGridSize = 1;
    private ResourceManager rm;

    //Constuctor
    public Pool()
    {
        //Resources
        rm = new ResourceManager("constants", this.GetType().Assembly);
        this.Label.Text = rm.GetString("PROCESS_DIAGRAM_POOL_ITEM_NAME");
    }

    //Create Grid
    protected override GoGrid CreateGrid()
    {
        GoGrid grid = new PoolGrid();
        grid.Selectable = false;
        grid.AutoRescales = true;
        grid.Resizable = true;
        grid.ResizesRealtime = true;
        grid.Bounds = new RectangleF(0, 0, 150, 100);
        grid.SnapDrag = GoViewSnapStyle.Jump;
        grid.SnapResize = GoViewSnapStyle.Jump;
        grid.CellSize = new SizeF(CellGridSize, CellGridSize);
        grid.Style = GoViewGridStyle.None;
        grid.Pen = new Pen(Color.Black, 1);
        grid.BrushColor = Color.White;
        grid.Style = GoViewGridStyle.Cross;

        return grid;
    }

    //Make sure the Lane's Label is positioned above the top-left corner of the Grid; this makes it potentially useful 
    //for selection and dragging even if all of the grid is covered by Items
    public override void LayoutChildren(GoObject childchanged)
    {

        if (this.Count >= 4)
        {
            GoGrid grid = this.Grid;
            GoText label = this.Label;

            if (grid != null && label != null)
            {
                //Label in Left side
                label.Width = grid.Height;
                PointF center = grid.GetSpotLocation(MiddleLeft) - new SizeF(label.Height / 2 + 1, 0);
                label.Center = center;
            }

            //Adjust pool size after add and remove Lanes...
            if (this.Count > 4)
            {

                if ((childchanged is Lane) && (childchanged.BeingRemoved))
                {
                    //Define new POol Heigh
                    RectangleF rectPool = this.Grid.Bounds;
                    Lane mLaneItem = (Lane)this[4];
                    rectPool.Height = (this.Count - 4) * mLaneItem.Grid.Height;
                    RectangleF newpollrect = new RectangleF(rectPool.X, rectPool.Y, rectPool.Width, rectPool.Height);
                    this.Grid.Bounds = newpollrect;
                    RectangleF rectLane = mLaneItem.Grid.Bounds;


                    for (int i = 4; i < this.Count; i++)
                    {
                        Lane LaneItem = (Lane)this<em>;

                        if (i == 4)
                        {
                            RectangleF newrect1 = new RectangleF(rectPool.X + this.Label.Height, rectPool.Y, rectPool.Width - this.Label.Height, mLaneItem.Grid.Height);
                            LaneItem.Grid.Bounds = newrect1;
                        }
                        else
                        {
                            RectangleF newrect2 = new RectangleF(rectPool.X + this.Label.Height, rectLane.Y + ((i - 4) * LaneItem.Grid.Height), rectPool.Width - this.Label.Height, mLaneItem.Grid.Height);
                            LaneItem.Grid.Bounds = newrect2;
                        }
                    }
                }
            }

            this.Port.Bounds = grid.Bounds; 
        }

    }

    //The Location of a Lane is actually the Position of its Grid
    public override PointF Location
    {
        get { return this.Grid.Position; }
        set
        {
            SizeF off = GoTool.SubtractPoints(this.Grid.Position, this.Position);
            SizeF pos = GoTool.SubtractPoints(value, off);
            this.Position = new PointF(pos.Width, pos.Height);
        }
    }

    //Show a differente color when node is dragged into lane
    public override void SetHighlight(bool show)
    {
        GoGrid grid = this.Grid;
        if (grid != null)
        {
            if (show)
            {
                grid.Pen = Pool.HighlightPen;
            }
            else
            {
                grid.Pen = Pool.StandardPen;
            }
        }
    }

}

//Diagram Pool Grid
[Serializable]
public class PoolGrid : GoGrid
{
    //Variables
    private int CellGridSize = 1;
    private int MinSizeW = 50;
    private int MinSizeH = 50;

    //Constructor
    public PoolGrid()
    {
    }

    //The grid in a Pool only snaps Lanes
    public override bool CanSnapPoint(PointF p, GoObject obj, GoView view)
    {
        if (!(obj is Lane))
        {
            return false;
        }

        // do standard checks, such as whether the grid is a child of the OBJ,
        // the value of the grid's snap style, whether the OBJ intersects with the grid,
        // and whether the mouse point is in the grid
        return base.CanSnapPoint(p, obj, view);

    }

    public override RectangleF ComputeResize(RectangleF origRect, PointF newPoint, int handle, SizeF min, SizeF max, bool reshape)
    {
        RectangleF r = base.ComputeResize(origRect, newPoint, handle, min, max, reshape);

        Pool pool = this.Parent as Pool;
        if (pool != null)
        {
            int i = 0;
            float Ycoord = 0;

            foreach (GoObject obj in pool.GetEnumerator())
            {
                i++;

                if (obj is Lane)
                {
                    RectangleF rectLane = ((Lane)obj).Grid.Bounds;
                    RectangleF rectPool = pool.Grid.Bounds;

                    if ((((Lane)obj).Count >= 2) && (pool.Count >= 5))
                    {
                        rectLane.X = rectLane.X - ((Lane)obj).Label.Height;
                        rectLane.Width = rectLane.Width + ((Lane)obj).Label.Height;


                        rectPool.X = rectPool.X - pool.Label.Height;
                        rectPool.Width = rectPool.Width + pool.Label.Height;

                        if (i == 5)
                        {
                            RectangleF newrect = new RectangleF(rectPool.X + pool.Label.Height + ((Lane)obj).Label.Height, rectPool.Y, rectPool.Width - pool.Label.Height - ((Lane)obj).Label.Height, rectPool.Height / (pool.Count - 4));
                            ((Lane)obj).Grid.Bounds = newrect;
                            Ycoord = Ycoord + rectPool.Y;
                        }
                        else
                        {
                            Ycoord = Ycoord + rectPool.Height / (pool.Count - 4);

                            RectangleF newrect = new RectangleF(rectPool.X + pool.Label.Height + ((Lane)obj).Label.Height, Ycoord, rectPool.Width - pool.Label.Height - ((Lane)obj).Label.Height, rectPool.Height / (pool.Count - 4));
                            ((Lane)obj).Grid.Bounds = newrect;
                        }

                    }
                }
            }
        }

        r.Width = Math.Max(1, (float)Math.Round(r.Width / CellGridSize)) * CellGridSize;
        r.Height = Math.Max(1, (float)Math.Round(r.Height / CellGridSize)) * CellGridSize;

        return r;
    }

    public override void DoResize(GoView view, RectangleF origRect, PointF newPoint, int whichHandle, GoInputState evttype, SizeF min, SizeF max)
    {
        base.DoResize(view, origRect, newPoint, whichHandle, evttype, new SizeF(MinSizeW, MinSizeH), max);  // specify minimum resizing Size
    }

}

//Diagram Pool Group Display
[Serializable]
public class PoolDisplay : GoBoxNode, IGoLabeledNode
{

    //Variables
    private int CellGridSize = 1;

    //Constructor
    protected PoolDisplay()
    {
        this.PortBorderMargin = new SizeF(0, 0);
        this.Port.BrushColor = Color.White;
        this.Port.PenColor = Color.Black;
        this.LinkPointsSpread = true;


        //The Grid is always first, in the background
        Add(CreateGrid());
        Add(CreateLabel());

    }

    //Create Grid
    protected virtual GoGrid CreateGrid()
    {
        GoGrid grid = new PoolGrid();
        grid.Selectable = false;
        grid.AutoRescales = true;
        grid.Resizable = true;
        grid.ResizesRealtime = true;
        grid.Bounds = new RectangleF(0, 0, 150, 100);
        grid.SnapDrag = GoViewSnapStyle.Jump;
        grid.SnapResize = GoViewSnapStyle.Jump;
        grid.CellSize = new SizeF(CellGridSize, CellGridSize);
        grid.Style = GoViewGridStyle.None;
        grid.Pen = new Pen(Color.Black, 2);
        grid.BrushColor = Color.White;
        return grid;
    }

    //Create label
    protected virtual GoText CreateLabel()
    {

        //Label Left Side
        RotatedText label = new RotatedText();
        label.Selectable = false;
        label.Multiline = true;
        label.Editable = true;
        label.FontSize = 11;
        label.TransparentBackground = false;
        label.BackgroundColor = Color.White;
        label.Bordered = true;
        // settings for rotation. 
        label.AutoResizes = false;
        label.Alignment = Middle;
        label.Bold = false;
        //label.FontSize = 8;
        label.Angle = 270;
        return label;
    }

    public override GoText Label
    {
        get 
        {
            Pool mPool = (Pool)this;
            if (mPool.Count > 3)
            {
                RotatedText mPoolGrid = (RotatedText)mPool[3];
                return mPoolGrid as GoText;
            }
            else
            {
                return null;
            } 
        }
    }

    //Get Grid
    public virtual GoGrid Grid
    {
        get 
        {
            Pool mPool = (Pool)this;
            if (mPool.Count > 2)
            {
                PoolGrid mPoolGrid = (PoolGrid)mPool[2];
                return mPoolGrid as GoGrid; 
            }
            else
            {
                return null;
            }
        }
    }

    //IGoLabeledNode:
    //Get Label
    //Set and Get Label text
    public override String Text
    {
        get
        {
            GoText lab = this.Label;
            if (lab != null)
                return lab.Text;
            return null;
        }
        set
        {
            GoText lab = this.Label;
            if (lab != null)
                lab.Text = value;
        }
    }

    public override void DoBeginEdit(GoView view)
    {
        if (this.Label != null)
        {
            this.Label.DoBeginEdit(view);
        }

    }

    public override bool CanEdit()
    {
        return base.CanEdit();
    }


    //Selection:

    //let users resize the grid, not the whole Lane
    public override GoObject SelectionObject
    {
        get { return this.Grid; }
    }

    public override bool CanSelect()
    {
        return base.CanSelect();
    }

    //Unlike normal GoGroups, PickObjects picks all children at a particular PointF, not just the "top" one
    public override IGoCollection PickObjects(PointF p, bool selectableOnly, IGoCollection coll, int max)
    {
        if (coll == null) coll = new GoCollection();
        if (coll.Count >= max) return coll;
        if (!CanView()) return coll;
        foreach (GoObject child in this.Backwards)
        {
            PoolDisplay disp = child as PoolDisplay;
            if (disp != null)
            {
                disp.PickObjects(p, selectableOnly, coll, max);
            }
            else
            {
                GoObject picked = child.Pick(p, selectableOnly);
                if (picked != null)
                {
                    coll.Add(picked);
                    if (coll.Count >= max) return coll;
                }
            }
        }
        return coll;
    }

    //Dragging:

    ////when dragging a non-Display onto a Display, highlight it to indicate that the dropped object(s) will be added to the Display
    //public override bool OnEnterLeave(GoObject from, GoObject to, GoView view)
    //{

    //    if (from is PoolDisplay && from != this)
    //    {
    //        ((PoolDisplay)from).SetHighlight(false);
    //    }

    //    SetHighlight(view.Tool is GoToolDragging && to == this && !view.Selection.IsEmpty && IsAddable(view.Selection.Primary) && view.Selection.Primary.Parent != this);

    //    return true;
    //}

    //Called after a GoToolDragging drop
    public override bool OnSelectionDropped(GoObjectEventArgs evt, GoView view)
    {
        view.Selection.AddRange(AddItems(view.Selection));
        return true;
    }

    //Don't add pools as children of this Display
    public virtual bool IsAddable(GoObject obj)
    {
        if (obj is Lane)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    //Return a collection of objects that actually are added to this Pool
    public virtual IGoCollection AddItems(IGoCollection coll)
    {
        //Skip all dropped Lanes -- just include Items and GoText labels
        GoCollection items = new GoCollection();

        foreach (GoObject obj in coll)
        {
            if (IsAddable(obj))
            {
                items.Add(obj);
            }
        }

        if (items.IsEmpty)
        {
            return items;
        }

        IGoCollection added = AddCollection(items, false);

        return added;
    }

    //Show a differente color when node is dragged into pool
    public virtual void SetHighlight(bool show)
    {
    }


}

//This class configure port, links...
public class GraphViewLinkingNewTool : GoToolLinkingNew
{
    //Variables
    private GoPort myLastNearestPort = null;

    //Constructor
    public GraphViewLinkingNewTool(GoView v): base(v)
    {
    }

    //Get elements
    public override IGoPort PickNearestPort(PointF dc)
    {
        IGoPort iport = base.PickNearestPort(dc);

        if (this.EndPort != null && this.EndPort.GoObject is GoPort)
        {
            if (iport != null)
            {
                myLastNearestPort = (GoPort)this.EndPort.GoObject;
                if (iport.Node is ProcessDiagram.Pool)
                {
                    myLastNearestPort.Style = GoPortStyle.None;
                }
                else
                {
                    myLastNearestPort.Style = GoPortStyle.Ellipse;
                }
            
                myLastNearestPort.Pen = ((ProcessView)this.View).PortHighlightPen;
            }
            else if (myLastNearestPort != null)
            {
                myLastNearestPort.Style = GoPortStyle.None;
                myLastNearestPort = null;
            }
        }

        return iport;
    }

    //Set port to be normal after link is completed
    public override void Stop()
    {
        base.Stop();
        if (myLastNearestPort != null)
        {
            myLastNearestPort.Style = GoPortStyle.None;
            myLastNearestPort = null;
        }
    }

    //Set new link, based on starter node
    public override void StartNewLink(IGoPort port, PointF dc)
    {

        //Set correct link based on starter node to link
        if (port.Node is ProcessDiagram.AnnotationItem)
        {
            GraphLink mGraphLink = new GraphLink();
            mGraphLink.ConfigureLink(ItemKind.MessageLink);
            ((ProcessView)this.View).NewLinkPrototype = mGraphLink;
        }

        else if (port.Node is ProcessDiagram.Pool)
        {
            GraphLink mGraphLink = new GraphLink();
            mGraphLink.ConfigureLink(ItemKind.PoolItem);
            ((ProcessView)this.View).NewLinkPrototype = mGraphLink;
        }

        base.StartNewLink(port, dc);

    }

    //Check if FromPort object was already added in ToPort object
    public static bool ValidSubGraphLink(IGoPort fromPort, IGoPort toPort)
    {
        if (fromPort == null || fromPort.Node.GoObject == null || toPort == null || toPort.Node.GoObject == null)
        {
            return false;
        }

        GoObject mfromPortObj = fromPort.Node.GoObject as GoObject;
        //Check if from port node already exists in To port node
        foreach (GoObject obj in toPort.Node.Sources)
        {
            if (obj == mfromPortObj)
            {
                return false;
            }
        }

        return true;
    }

    public override bool IsValidLink(IGoPort fromPort, IGoPort toPort)
    {
        //Check if user is trying to link something in DataObjectItem or Pool with others objects ( Just accpets Pool with pool)
        GoObject mToPortObj = toPort.Node.GoObject as GoObject;
        GoObject mFromPortObj = fromPort.Node.GoObject as GoObject;

        if (mToPortObj != null)
        {
            if (mToPortObj is DataObjectItem)
            {
                return false;
            }
            else
            {
                if (mFromPortObj != null)
                {
                    if ((mFromPortObj is Pool) && (mToPortObj is Pool))
                    {
                        //do nothing...
                    }
                    else
                    {
                        return false;
                    }
                }
            }
        }

        
        //Check if from port node already exists in To port node, just link one time
        return base.IsValidLink(fromPort, toPort) && ValidSubGraphLink(fromPort, toPort);
    }
}

GoBoxNode.LayoutChildren is going to set the Bounds of the port to be this.Body.Bounds plus this.PortBorderMargin. That margin is going to be the area where you get the hand to create a new link.

Hi Jake!

Please, my class is ok now Thumbs%20Up , just it should show a hand to connect Pool objects…

I don´t know where and how to put this code you said in last reply…
I tried, I changed as you can see PoolDisplay() constructor and LayoutChildren()… But without success.

Sorry, but can you change my code ( last post ) ? Everything is correct now, just I can´t see hand to connect… And this hand should be in all Pool border line…

Thank you very much!

what is your setting on PortBorderMargin? Try increasing that.

I increased to:

this.PortBorderMargin = new SizeF(10, 10);

//Constructor
protected PoolDisplay()
{
this.PortBorderMargin = new SizeF(10, 10);
this.Port.BrushColor = Color.White;
this.Port.PenColor = Color.Black;
this.LinkPointsSpread = true;

        //The Grid is always first, in the background
        Add(CreateGrid());
        Add(CreateLabel());

    }

and in LayoutChildren(): this.Port.Bounds = this.Bounds;

And hand to connect was not show in POol rectangle line

public override void LayoutChildren(GoObject childchanged)
{

        if (this.Count >= 4)
        {
            GoGrid grid = this.Grid;
            GoText label = this.Label;

            if (grid != null && label != null)
            {
                //Label in Left side
                label.Width = grid.Height;
                PointF center = grid.GetSpotLocation(MiddleLeft) - new SizeF(label.Height / 2 + 1, 0);
                label.Center = center;
            }

            //Adjust pool size after add and remove Lanes...
            if (this.Count > 4)
            {

                if ((childchanged is Lane)) //&& (childchanged.BeingRemoved)
                {
                    //Define new POol Heigh
                    RectangleF rectPool = this.Grid.Bounds;
                    Lane mLaneItem = (Lane)this[4];
                    rectPool.Height = (this.Count - 4) * mLaneItem.Grid.Height;
                    RectangleF newpollrect = new RectangleF(rectPool.X, rectPool.Y, rectPool.Width, rectPool.Height);
                    this.Grid.Bounds = newpollrect;
                    RectangleF rectLane = mLaneItem.Grid.Bounds;


                    for (int i = 4; i < this.Count; i++)
                    {
                        Lane LaneItem = (Lane)this<em>;

                        if (i == 4)
                        {
                            RectangleF newrect1 = new RectangleF(rectPool.X + this.Label.Height, rectPool.Y, rectPool.Width - this.Label.Height, mLaneItem.Grid.Height);
                            LaneItem.Grid.Bounds = newrect1;
                        }
                        else
                        {
                            RectangleF newrect2 = new RectangleF(rectPool.X + this.Label.Height, rectLane.Y + ((i - 4) * LaneItem.Grid.Height), rectPool.Width - this.Label.Height, mLaneItem.Grid.Height);
                            LaneItem.Grid.Bounds = newrect2;
                        }
                    }
                }
            }

            this.Port.Bounds = grid.Bounds; 
        }

    }

Oh… PortBorderMargin is only going to help if you call base.LayoutChildren. And you will need to override the Body property to return this grid. (and you don’t need to set Port.Bounds in your own LayoutChildren then)

Please, can you show me how to do it using my code? I am one week trying to resolve this problem of GoBoxPort connection without success.

Should I remove PortBorderMargin and add base.LayoutChildren in LayoutChildren() ?

How to override the Body property to return this grid ?
this.Body. ???

Thanks!

It’s hard for me to take a small chunk of code and just try it.



Try these 2 things.



In your initialization code,



this.Body = this.Grid;



that should work, and you won’t have to override the Body property.



and… at the end of LayoutChildren (after you have set the other parts of your lane up) call base.LayoutChildren(childchanged).



You may want to set the FromSides and ToSides of the GoBoxPort to just be the top and bottom. That seems appropriate for BPMN.

Hi Jake, I sent an e-mail with my code example.
I agree with you…with a part of code it is difficult to get a good result.

Thanks!