Click here to Skip to main content
15,886,919 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
for connection .xaml
HTML
<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>
            <!-- Arrow Grid 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>
            <!-- base style for all arrow shapes -->
            <Style x:Key="ArrowSymbolBaseStyle" TargetType="Path">
                <setter property="Fill" value="{StaticResource SolidBorderBrush}" />
                <setter property="Stretch" value="Fill" />
            </Style>
            <!-- Arrow -->
            <Style x:Key="Arrow" TargetType="Path" BasedOn="{StaticResource ArrowSymbolBaseStyle}">
                <setter property="Data" value="M0,0 8,4 0,8 Z" />
            </Style>
            <!-- Diamond  -->
            <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>

                        <!--Uncomment this to show default label text-->
                        <!--<textblock width="100" height="35">
                                       Text="{Binding Path=(Canvas.ZIndex)}"
                                       Canvas.Left="{Binding LabelPosition.X}"
                                       Canvas.Top="{Binding LabelPosition.Y}">
                              <textblock.rendertransform>
                                <translatetransform x="5" y="5" />
                              </textblock.rendertransform>
                            </textblock>-->

                        <!--<Canvas.BitmapEffect>
                            <dropshadowbitmapeffect color="Gray" direction="315" shadowdepth="10" softness="0" opacity="0.1" />
                        </Canvas.BitmapEffect>-->
                    </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>

                        <!--<multitrigger>
                            <multitrigger.conditions>
                                <condition property="IsSelected" value="true" />
                            </multitrigger.conditions>
                            <setter property="Template" value="{StaticResource SelectedTemplate}" />
                        </multitrigger>-->

                    </controltemplate.triggers>
                </controltemplate>
                
            </setter.value>
        </setter>
    </Style>
</resourcedictionary>

and
connection class
C#
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; }

        // source connector
        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();
                }
            }
        }

        // sink connector
        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();
                }
            }
        }

        // connection path geometry
        private PathGeometry pathGeometry;
        public PathGeometry PathGeometry
        {
            get { return pathGeometry; }
            set
            {
                if (pathGeometry != value)
                {
                    pathGeometry = value;
                    UpdateAnchorPosition();
                    OnPropertyChanged("PathGeometry");
                }
            }
        }

        // between source connector position and the beginning 
        // of the path geometry we leave some space for visual reasons; 
        // so the anchor position source really marks the beginning 
        // of the path geometry on the source side
        private Point anchorPositionSource;
        public Point AnchorPositionSource
        {
            get { return anchorPositionSource; }
            set
            {
                if (anchorPositionSource != value)
                {
                    anchorPositionSource = value;
                    OnPropertyChanged("AnchorPositionSource");
                }
            }
        }

        // slope of the path at the anchor position
        // needed for the rotation angle of the arrow
        private double anchorAngleSource = 0;
        public double AnchorAngleSource
        {
            get { return anchorAngleSource; }
            set
            {
                if (anchorAngleSource != value)
                {
                    anchorAngleSource = value;
                    OnPropertyChanged("AnchorAngleSource");
                }
            }
        }

        // analogue to source side
        private Point anchorPositionSink;
        public Point AnchorPositionSink
        {
            get { return anchorPositionSink; }
            set
            {
                if (anchorPositionSink != value)
                {
                    anchorPositionSink = value;
                    OnPropertyChanged("AnchorPositionSink");
                }
            }
        }
        // analogue to source side
        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");
                }
            }
        }

        // specifies a point at half path length
        private Point labelPosition;
        public Point LabelPosition
        {
            get { return labelPosition; }
            set
            {
                if (labelPosition != value)
                {
                    labelPosition = value;
                    OnPropertyChanged("LabelPosition");
                }
            }
        }

        // pattern of dashes and gaps that is used to outline the connection path
        private DoubleCollection strokeDashArray;
        public DoubleCollection StrokeDashArray
        {
            get
            {
                return strokeDashArray;
            }
            set
            {
                if (strokeDashArray != value)
                {
                    strokeDashArray = value;
                    OnPropertyChanged("StrokeDashArray");
                }
            }
        }

        // if connected, the ConnectionAdorner becomes visible
        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);

            // usual selection business
            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
            {
               // _shape.Fill = new SolidColorBrush(value);
                _color = value;
            }
        }
        void OnConnectorPositionChanged(object sender, PropertyChangedEventArgs e)
        {
            // whenever the 'Position' property of the source or sink Connector 
            // changes we must update the connection path geometry
            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;

            // the PathGeometry.GetPointAtFractionLength method gets the point and a tangent vector 
            // on PathGeometry at the specified fraction of its length
            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);

            // get angle from tangent vector
            this.AnchorAngleSource = Math.Atan2(-pathTangentAtStartPoint.Y, -pathTangentAtStartPoint.X) * (180 / Math.PI);
            this.AnchorAngleSink = Math.Atan2(pathTangentAtEndPoint.Y, pathTangentAtEndPoint.X) * (180 / Math.PI);

            // add some margin on source and sink side for visual reasons only
            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()
        {
            // the ConnectionAdorner is created once for each Connection
            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)
        {
            // do some housekeeping when Connection is unloaded

            // remove event handler
            this.Source = null;
            this.Sink = null;

            // remove adorner
            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

        // we could use DependencyProperties as well to inform others of property changes
        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);
           // Connection.BorderBrushProperty = new Brush();
        }
       

        #endregion
    }

    public enum ArrowSymbol
    {
        None,
        Arrow,
        Diamond
    }
}
Posted
Updated 7-Jul-15 1:44am
v2
Comments
Kornfeld Eliyahu Peter 7-Jul-15 7:16am    
This unformatted code-dump will not get you any answer...
Please post only the relevant code and show where exactly you have problems...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900