for connection .xaml
<resourcedictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:DiagramDesigner"
xmlns:c="clr-namespace:DiagramDesigner.Controls">
<contextmenu x:key="ConnectionContextMenu" xmlns:x="#unknown">
<menuitem header="Delete" command="{x:Static ApplicationCommands.Delete}">
<menuitem.icon>
<Image Source="Images/Delete.png" Width="16"/>
</menuitem.icon>
</menuitem>
<separator />
<menuitem header="Order">
<menuitem header="Bring Forward" command="{x:Static s:DesignerCanvas.BringForward}">
<menuitem.icon>
<Image Source="Images/BringForward.png" Width="16"/>
</menuitem.icon>
</menuitem>
<menuitem header="Bring To Front" command="{x:Static s:DesignerCanvas.BringToFront}">
<menuitem.icon>
<Image Source="Images/BringToFront.png" Width="16"/>
</menuitem.icon>
</menuitem>
<menuitem header="Send Backward" command="{x:Static s:DesignerCanvas.SendBackward}">
<menuitem.icon>
<Image Source="Images/SendBackward.png" Width="16"/>
</menuitem.icon>
</menuitem>
<menuitem header="Send To Back" command="{x:Static s:DesignerCanvas.SendToBack}">
<menuitem.icon>
<Image Source="Images/SendToBack.png" Width="16"/>
</menuitem.icon>
</menuitem>
</menuitem>
</contextmenu>
<Style TargetType="{x:Type s:Connection}">
<Style.Resources>
<!-- Style for the ConnectorAdorner thumbs -->
<Style x:Key="ConnectionAdornerThumbStyle" TargetType="{x:Type Thumb}">
<setter property="Width" value="12" />
<setter property="Height" value="12" />
<setter property="SnapsToDevicePixels" value="true" />
<setter property="RenderTransform">
<setter.value>
<translatetransform x="-6" y="-6" />
</setter.value>
</setter>
<setter property="Template">
<setter.value>
<controltemplate targettype="{x:Type Thumb}">
<rectangle fill="#AADCDCDC" stroke="DodgerBlue" strokethickness="1" radiusx="0" radiusy="0" />
</controltemplate>
</setter.value>
</setter>
</Style>
<!--
<Style x:Key="ArrowGridStyle" TargetType="Grid">
<setter property="Width" value="10" />
<setter property="Height" value="10" />
<setter property="RenderTransform">
<setter.value>
<translatetransform x="-5" y="-5" />
</setter.value>
</setter>
</Style>
<!--
<Style x:Key="ArrowSymbolBaseStyle" TargetType="Path">
<setter property="Fill" value="{StaticResource SolidBorderBrush}" />
<setter property="Stretch" value="Fill" />
</Style>
<!--
<Style x:Key="Arrow" TargetType="Path" BasedOn="{StaticResource ArrowSymbolBaseStyle}">
<setter property="Data" value="M0,0 8,4 0,8 Z" />
</Style>
<!--
<Style x:Key="Diamond" TargetType="Path" BasedOn="{StaticResource ArrowSymbolBaseStyle}">
<setter property="Data" value="M-5,0 0,-5 5,0 0,5 Z" />
</Style>
</Style.Resources>
<setter property="SnapsToDevicePixels" value="True" />
<setter property="Template">
<setter.value>
<controltemplate targettype="{x:Type s:Connection}">
<Canvas DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"
ContextMenu="{StaticResource ConnectionContextMenu}">
<path name="PART_ConnectionPath">
StrokeThickness="2"
Stroke="{StaticResource SolidBorderBrush}"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
StrokeDashArray="{Binding StrokeDashArray}"
SnapsToDevicePixels="True"
Data="{Binding PathGeometry}">
</path>
<grid style="{StaticResource ArrowGridStyle}">
Canvas.Left="{Binding AnchorPositionSource.X}"
Canvas.Top="{Binding AnchorPositionSource.Y}">
<path name="PART_SourceAnchorPath" />
<grid.layouttransform>
<rotatetransform angle="{Binding AnchorAngleSource}" />
</grid.layouttransform>
</grid>
<grid style="{StaticResource ArrowGridStyle}">
Canvas.Left="{Binding AnchorPositionSink.X}"
Canvas.Top="{Binding AnchorPositionSink.Y}">
<path name="PART_SinkAnchorPath" />
<grid.layouttransform>
<rotatetransform angle="{Binding AnchorAngleSink}" />
</grid.layouttransform>
</grid>
<!--
<!--
<!--
</Canvas>
<controltemplate.triggers>
<datatrigger value="Arrow" binding="{Binding RelativeSource={RelativeSource Self},Path=SourceArrowSymbol}">
<setter targetname="PART_SourceAnchorPath" property="Style" value="{StaticResource Arrow}" />
</datatrigger>
<datatrigger value="Diamond" binding="{Binding RelativeSource={RelativeSource Self},Path=SourceArrowSymbol}">
<setter targetname="PART_SourceAnchorPath" property="Style" value="{StaticResource Diamond}" />
</datatrigger>
<datatrigger value="Arrow" binding="{Binding RelativeSource={RelativeSource Self},Path=SinkArrowSymbol}">
<setter targetname="PART_SinkAnchorPath" property="Style" value="{StaticResource Arrow}" />
</datatrigger>
<datatrigger value="Diamond" binding="{Binding RelativeSource={RelativeSource Self},Path=SinkArrowSymbol}">
<setter targetname="PART_SinkAnchorPath" property="Style" value="{StaticResource Diamond}" />
</datatrigger>
<!--
</controltemplate.triggers>
</controltemplate>
</setter.value>
</setter>
</Style>
</resourcedictionary>
and
connection class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace DiagramDesigner
{
public class Connection : Control, ISelectable, INotifyPropertyChanged
{
private Adorner connectionAdorner;
#region Properties
public Guid ID { get; set; }
private Connector source;
public Connector Source
{
get
{
return source;
}
set
{
if (source != value)
{
if (source != null)
{
source.PropertyChanged -= new PropertyChangedEventHandler(OnConnectorPositionChanged);
source.Connections.Remove(this);
}
source = value;
if (source != null)
{
source.Connections.Add(this);
source.PropertyChanged += new PropertyChangedEventHandler(OnConnectorPositionChanged);
}
UpdatePathGeometry();
}
}
}
private Connector sink;
public Connector Sink
{
get { return sink; }
set
{
if (sink != value)
{
if (sink != null)
{
sink.PropertyChanged -= new PropertyChangedEventHandler(OnConnectorPositionChanged);
sink.Connections.Remove(this);
}
sink = value;
if (sink != null)
{
sink.Connections.Add(this);
sink.PropertyChanged += new PropertyChangedEventHandler(OnConnectorPositionChanged);
}
UpdatePathGeometry();
}
}
}
private PathGeometry pathGeometry;
public PathGeometry PathGeometry
{
get { return pathGeometry; }
set
{
if (pathGeometry != value)
{
pathGeometry = value;
UpdateAnchorPosition();
OnPropertyChanged("PathGeometry");
}
}
}
private Point anchorPositionSource;
public Point AnchorPositionSource
{
get { return anchorPositionSource; }
set
{
if (anchorPositionSource != value)
{
anchorPositionSource = value;
OnPropertyChanged("AnchorPositionSource");
}
}
}
private double anchorAngleSource = 0;
public double AnchorAngleSource
{
get { return anchorAngleSource; }
set
{
if (anchorAngleSource != value)
{
anchorAngleSource = value;
OnPropertyChanged("AnchorAngleSource");
}
}
}
private Point anchorPositionSink;
public Point AnchorPositionSink
{
get { return anchorPositionSink; }
set
{
if (anchorPositionSink != value)
{
anchorPositionSink = value;
OnPropertyChanged("AnchorPositionSink");
}
}
}
private double anchorAngleSink = 0;
public double AnchorAngleSink
{
get { return anchorAngleSink; }
set
{
if (anchorAngleSink != value)
{
anchorAngleSink = value;
OnPropertyChanged("AnchorAngleSink");
}
}
}
private ArrowSymbol sourceArrowSymbol = ArrowSymbol.None;
public ArrowSymbol SourceArrowSymbol
{
get { return sourceArrowSymbol; }
set
{
if (sourceArrowSymbol != value)
{
sourceArrowSymbol = value;
OnPropertyChanged("SourceArrowSymbol");
}
}
}
public ArrowSymbol sinkArrowSymbol = ArrowSymbol.Arrow;
public ArrowSymbol SinkArrowSymbol
{
get { return sinkArrowSymbol; }
set
{
if (sinkArrowSymbol != value)
{
sinkArrowSymbol = value;
OnPropertyChanged("SinkArrowSymbol");
}
}
}
private Point labelPosition;
public Point LabelPosition
{
get { return labelPosition; }
set
{
if (labelPosition != value)
{
labelPosition = value;
OnPropertyChanged("LabelPosition");
}
}
}
private DoubleCollection strokeDashArray;
public DoubleCollection StrokeDashArray
{
get
{
return strokeDashArray;
}
set
{
if (strokeDashArray != value)
{
strokeDashArray = value;
OnPropertyChanged("StrokeDashArray");
}
}
}
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set
{
if (isSelected != value)
{
isSelected = value;
OnPropertyChanged("IsSelected");
if (isSelected)
ShowAdorner();
else
HideAdorner();
}
}
}
#endregion
public Connection(Connector source, Connector sink)
{
this.ID = Guid.NewGuid();
this.Source = source;
this.Sink = sink;
base.Unloaded += new RoutedEventHandler(Connection_Unloaded);
}
protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
{
base.OnMouseDown(e);
DesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;
if (designer != null)
{
if ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) != ModifierKeys.None)
if (this.IsSelected)
{
designer.SelectionService.RemoveFromSelection(this);
}
else
{
designer.SelectionService.AddToSelection(this);
}
else if (!this.IsSelected)
{
designer.SelectionService.SelectItem(this);
}
Focus();
}
e.Handled = false;
}
private Color _color;
public Color Color
{
get { return _color; }
set
{
_color = value;
}
}
void OnConnectorPositionChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals("Position"))
{
UpdatePathGeometry();
}
}
private void UpdatePathGeometry()
{
if (Source != null && Sink != null)
{
PathGeometry geometry = new PathGeometry();
List<point> linePoints = PathFinder.GetConnectionLine(Source.GetInfo(), Sink.GetInfo(), true);
if (linePoints.Count > 0)
{
PathFigure figure = new PathFigure();
figure.StartPoint = linePoints[0];
linePoints.Remove(linePoints[0]);
figure.Segments.Add(new PolyLineSegment(linePoints, true));
geometry.Figures.Add(figure);
this.PathGeometry = geometry;
}
}
}
private void UpdateAnchorPosition()
{
Point pathStartPoint, pathTangentAtStartPoint;
Point pathEndPoint, pathTangentAtEndPoint;
Point pathMidPoint, pathTangentAtMidPoint;
this.PathGeometry.GetPointAtFractionLength(0, out pathStartPoint, out pathTangentAtStartPoint);
this.PathGeometry.GetPointAtFractionLength(1, out pathEndPoint, out pathTangentAtEndPoint);
this.PathGeometry.GetPointAtFractionLength(0.5, out pathMidPoint, out pathTangentAtMidPoint);
this.AnchorAngleSource = Math.Atan2(-pathTangentAtStartPoint.Y, -pathTangentAtStartPoint.X) * (180 / Math.PI);
this.AnchorAngleSink = Math.Atan2(pathTangentAtEndPoint.Y, pathTangentAtEndPoint.X) * (180 / Math.PI);
pathStartPoint.Offset(-pathTangentAtStartPoint.X * 5, -pathTangentAtStartPoint.Y * 5);
pathEndPoint.Offset(pathTangentAtEndPoint.X * 5, pathTangentAtEndPoint.Y * 5);
this.AnchorPositionSource = pathStartPoint;
this.AnchorPositionSink = pathEndPoint;
this.LabelPosition = pathMidPoint;
}
private void ShowAdorner()
{
if (this.connectionAdorner == null)
{
DesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
if (adornerLayer != null)
{
this.connectionAdorner = new ConnectionAdorner(designer, this);
adornerLayer.Add(this.connectionAdorner);
}
}
this.connectionAdorner.Visibility = Visibility.Visible;
}
internal void HideAdorner()
{
if (this.connectionAdorner != null)
this.connectionAdorner.Visibility = Visibility.Collapsed;
}
void Connection_Unloaded(object sender, RoutedEventArgs e)
{
this.Source = null;
this.Sink = null;
if (this.connectionAdorner != null)
{
DesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
if (adornerLayer != null)
{
adornerLayer.Remove(this.connectionAdorner);
this.connectionAdorner = null;
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
MessageBox.Show("hello"+ID);
}
#endregion
}
public enum ArrowSymbol
{
None,
Arrow,
Diamond
}
}