Edit this page

Create Custom Connection Cap

This tutorial will guide you through the task of creating custom connection cap. The final result will look like this.

Custom Cap

With our Q1 2015 official release we extended our RadDiagramConnection component so that its caps can now be customized.

To implement the neccesary customization you need to create custom class deriving from our RadDiagramConnection and override a couple of methods. Our comopnent exposes the CreateSourceCapGeometry() and CreateTargetCapGeometry() methods which we will take advantage of. As their names imply the CreateSourceCapGeometry() generates the source cap and the CreateTargetCapGeometry() generates the target cap. These methods should return an object of type PathFigure which is further used as the respective cap of the RadDiagramConnection. The customized implementation of those methods should create the desired PathFigures based on three points. Those points are received as parameters of the methods.

In the CreateSourceCapGeometry() method the first parameter is called startPoint and marks the position of the connection's connector. The second parameter is called endPoint and marks the furthest point of the first section of the connection. For better understanding please refer to the next picture.

Custom Cap

Based on these two points you can determine the angle of the first section of the connection. This allows you to adjust the cap to that angle so that it follows the direction of the connection's section. The third parameter is named baseLineStart. It marks the starting point of the actual line of the connction.

The third point should be set in your custom logic. In other words, you can control the starting point of the actual line.

Custom Cap

In the CreateTargetCapGeometry() method the parameters serve for the very same purpose and should be used just like the prameter of the other method. For clarification please refer the following picture.

Custom Cap

Example

The next code snippet will create custom connection caps as shown in the beggining of this article.

public class CustomConnection : RadDiagramConnection
{
    protected override System.Windows.Media.PathFigure CreateSourceCapGeometry(System.Windows.Point startPoint, System.Windows.Point endPoint, ref System.Windows.Point baseLineStart)
    {
        baseLineStart = startPoint;
        var result = CreateMyCap(startPoint);

        return result;
    }

    protected override PathFigure CreateTargetCapGeometry(Point startPoint, Point endPoint, ref Point baseLineEnd)
    {
        baseLineEnd = startPoint;
        var result = this.CreateMyCap(startPoint);

        return result;
    }

    private PathFigure CreateMyCap(Point startPoint)
    {
        var result = new PathFigure();
        result.StartPoint = startPoint;

        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X, startPoint.Y - 2) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X + 4, startPoint.Y - 5) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X + 6, startPoint.Y - 3) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X + 2, startPoint.Y) });

        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X + 6, startPoint.Y + 3) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X + 4, startPoint.Y + 5) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X, startPoint.Y + 2) });

        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X - 4, startPoint.Y + 5) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X - 6, startPoint.Y + 3) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X - 2, startPoint.Y) });

        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X - 6, startPoint.Y - 3) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X - 4, startPoint.Y - 5) });
        result.Segments.Add(new LineSegment() { Point = new Point(startPoint.X, startPoint.Y - 2) });
        return result;
    }
}
Public Class CustomConnection
    Inherits RadDiagramConnection
    Protected Overrides Function CreateSourceCapGeometry(startPoint As System.Windows.Point, endPoint As System.Windows.Point, ByRef baseLineStart As System.Windows.Point) As System.Windows.Media.PathFigure
        baseLineStart = startPoint
        Dim result = CreateMyCap(startPoint)

        Return result
    End Function

    Protected Overrides Function CreateTargetCapGeometry(startPoint As Point, endPoint As Point, ByRef baseLineEnd As Point) As PathFigure
        baseLineEnd = startPoint
        Dim result = CreateMyCap(startPoint)

        Return result
    End Function

    Private Function CreateMyCap(startPoint As Point) As PathFigure
        Me.SourceCapSize = New Size(13, 13)

        Dim result = New PathFigure()
        result.StartPoint = startPoint

        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X, startPoint.Y - 2) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X + 4, startPoint.Y - 5) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X + 6, startPoint.Y - 3) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X + 2, startPoint.Y) _
        })

        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X + 6, startPoint.Y + 3) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X + 4, startPoint.Y + 5) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X, startPoint.Y + 2) _
        })

        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X - 4, startPoint.Y + 5) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X - 6, startPoint.Y + 3) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X - 2, startPoint.Y) _
        })

        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X - 6, startPoint.Y - 3) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X - 4, startPoint.Y - 5) _
        })
        result.Segments.Add(New LineSegment() With { _
            Key .Point = New Point(startPoint.X, startPoint.Y - 2) _
        })
        Return result
    End Function
End Class

After utilising this code you can go in XAML and use your custom connection like this:

<telerik:RadDiagram x:Name="diagram">
        <telerik:RadDiagramShape x:Name="shape1" Position="100 100" ZIndex="1"/>
        <telerik:RadDiagramShape x:Name="shape2" Position="300 100" ZIndex="1"/>
        <local:CustomConnection Source="{Binding ElementName=shape1}" Target="{Binding ElementName=shape2}" ZIndex="3"/>
    </telerik:RadDiagram>

"local" points to the namespace where the CustomConnection class is defined.

Custom Cap

See Also