WPF V1.2.1.4 Beta
I am prototyping a state machine diagram editor. Each state is a group (can contain states).
I must be able to connect a child state to the side of the containing state.
By default, the connection appends to the center of the group because the default Node.ToSpot=“None”.
I have browsed the documentation about a list of ToSpot valid values but I have not found one. So I have tested different values and one was accepted : “AllSides”.
But with this value the links ends in the middle, and the behavior of connecting from inside the group is strange. Sorry it is difficult to explain.
Could you please give me some help about that ?
Additional Info:
The “Cut” blue link in Link Demo
The Spot enumeration has a bunch of standard spot values. I don’t know what you want, but perhaps you want to use MiddleLeft or something like that.
I need to let connect a child state to its parent state on any side. Example image:
So, “AllSides” is what I need. But, when using this value, the link look wrong. See image in previous message and in the following image of my prototype.
The problem appends with the Link when:
ToPortSpot = AllSides & Routing=Normal & Curve=Bezier
OK, use this as the Link.Route and make sure the spots are all Spot.None (the default).
[code] // Smarter routing for a Link inside a Group that is connecting to that Group:
// connect to the nearest point assuming the Group’s port is rectangular.
// Assumes Spot.None; does not work for Orthogonal routing
public class ContainerRoute : Route {
public override Point GetLinkPoint(Node node, FrameworkElement port, Spot spot, bool from,
bool ortho, Node othernode, FrameworkElement otherport) {
Group g = othernode as Group;
if (g != null && this.Link.IsContainedBy(g)) {
Point ctr = node.GetElementPoint(port, Spot.Center);
Point p = GetLinkPointFromPoint(othernode, otherport, new Point(), ctr, !from);
return GetLinkPointFromPoint(node, port, ctr, p, from);
} else {
return base.GetLinkPoint(node, port, spot, from, ortho, othernode, otherport);
}
}
protected override Point GetLinkPointFromPoint(Node node, FrameworkElement port,
Point focus, Point p, bool from) {
Group g = node as Group;
if (g != null && this.Link.IsContainedBy(g)) {
// assume rectangular port
Rect b = node.GetElementBounds(port);
return ClosestPointOnRect(b, p);
} else {
return base.GetLinkPointFromPoint(node, port, focus, p, from);
}
}
private static Point ClosestPointOnRect(Rect b, Point p) {
double x = p.X;
double y = p.Y;
// inside the rect?
if (b.Left < p.X && p.X < b.Right && b.Top < p.Y && p.Y < b.Bottom) {
// distances to each side
double left = p.X-b.Left;
double right = b.Right-p.X;
double top = p.Y-b.Top;
double bottom = b.Bottom-p.Y;
// find closest quadrant, then closest side in that quadrant
if (left < right) {
if (top < bottom) {
if (left < top) x = b.Left; else y = b.Top;
} else {
if (left < bottom) x = b.Left; else y = b.Bottom;
}
} else {
if (top < bottom) {
if (right < top) x = b.Right; else y = b.Top;
} else {
if (right < bottom) x = b.Right; else y = b.Bottom;
}
}
} else { // outside the rect
if (p.X <= b.Left) x = b.Left; else if (p.X >= b.Right) x = b.Right;
if (p.Y <= b.Top) y = b.Top; else if (p.Y > b.Bottom) y = b.Bottom;
}
return new Point(x, y);
}
}[/code]
Thanks Walter. Works well. Very elegant way to plug new features.