Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / Common / AuthoringOM / Design / Connector.cs / 1305376 / Connector.cs
using System; using System.IO; using System.Drawing; using System.Drawing.Drawing2D; using System.Collections; using System.Collections.ObjectModel; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Windows.Forms; using System.Diagnostics; using System.ComponentModel.Design.Serialization; using System.Workflow.ComponentModel.Serialization; namespace System.Workflow.ComponentModel.Design { #region Class ConnectionPointHitTestInfo internal sealed class ConnectionPointHitTestInfo : HitTestInfo { private ConnectionPoint connectionPoint; internal ConnectionPointHitTestInfo(ConnectionPoint connectionPoint) : base(connectionPoint.AssociatedDesigner, HitTestLocations.Designer | HitTestLocations.Connector) { this.connectionPoint = connectionPoint; } internal ConnectionPoint ConnectionPoint { get { return this.connectionPoint; } } } #endregion #region ConnectorEvent public delegate void ConnectorEventHandler(object sender, ConnectorEventArgs e); #region Class ConnectorEventArgs public class ConnectorEventArgs : EventArgs { private Connector connector; internal ConnectorEventArgs(Connector connector) { this.connector = connector; } public Connector Connector { get { return this.connector; } } } #endregion #endregion #region Class ConnectionPoint public class ConnectionPoint { private ActivityDesigner associatedDesigner; private DesignerEdges designerEdge; private int connectionIndex; public ConnectionPoint(ActivityDesigner associatedDesigner, DesignerEdges designerEdge, int connectionIndex) { if (associatedDesigner == null) throw new ArgumentNullException("associatedDesigner"); if (connectionIndex < 0 || connectionIndex >= associatedDesigner.GetConnections(designerEdge).Count) throw new ArgumentException(DR.GetString(DR.Error_ConnectionPoint), "connectionIndex"); this.associatedDesigner = associatedDesigner; this.designerEdge = designerEdge; this.connectionIndex = connectionIndex; } public ActivityDesigner AssociatedDesigner { get { return this.associatedDesigner; } } public int ConnectionIndex { get { return this.connectionIndex; } } public DesignerEdges ConnectionEdge { get { DesignerEdges designerEdge = this.designerEdge; if (designerEdge != DesignerEdges.Left && designerEdge != DesignerEdges.Right && designerEdge != DesignerEdges.Top && designerEdge != DesignerEdges.Bottom) { designerEdge = DesignerGeometryHelper.ClosestEdgeToPoint(Location, this.associatedDesigner.Bounds, designerEdge); } return designerEdge; } } public virtual Point Location { get { IListconnections = this.associatedDesigner.GetConnections(this.designerEdge); if (this.connectionIndex < connections.Count) return connections[this.connectionIndex]; else return Point.Empty; } } public virtual Rectangle Bounds { get { IList connections = this.associatedDesigner.GetConnections(DesignerEdges.All); if (connections.Count > 0) { Point location = Location; Size size = DefaultSize; Rectangle enclosingBounds = new Rectangle(new Point(location.X - size.Width / 2, location.Y - size.Height / 2), size); return enclosingBounds; } else { return Rectangle.Empty; } } } public override bool Equals(object obj) { ConnectionPoint connectionPoint = obj as ConnectionPoint; if (connectionPoint == null) return false; if (connectionPoint.AssociatedDesigner == this.associatedDesigner && connectionPoint.designerEdge == this.designerEdge && connectionPoint.ConnectionIndex == this.connectionIndex) return true; else return false; } public override int GetHashCode() { return (this.associatedDesigner.GetHashCode() ^ this.designerEdge.GetHashCode() ^ this.connectionIndex.GetHashCode()); } public void OnPaint(ActivityDesignerPaintEventArgs e, bool drawHighlighted) { Draw(e, Bounds); } internal static void Draw(ActivityDesignerPaintEventArgs e, Rectangle bounds) { bounds.Inflate(-1, -1); e.Graphics.FillEllipse(Brushes.White, bounds); e.Graphics.DrawEllipse(e.AmbientTheme.SelectionForegroundPen, bounds); bounds.Inflate(-1, -1); e.Graphics.FillEllipse(e.AmbientTheme.SelectionForegroundBrush, bounds); } private Size DefaultSize { get { Size defaultSize = WorkflowTheme.CurrentTheme.AmbientTheme.Margin; defaultSize.Width += defaultSize.Width / 2; defaultSize.Height += defaultSize.Height / 2; if (this.associatedDesigner != null) defaultSize = new Size(Math.Max(defaultSize.Width, (int)this.associatedDesigner.DesignerTheme.ForegroundPen.Width * 4), Math.Max(defaultSize.Height, (int)this.associatedDesigner.DesignerTheme.ForegroundPen.Width * 4)); return defaultSize; } } } #endregion #region Class Connector [DesignerSerializer(typeof(ConnectorLayoutSerializer), typeof(WorkflowMarkupSerializer))] public class Connector : IDisposable { #region Members, Construction, Dispose private AccessibleObject accessibilityObject; private FreeformActivityDesigner parentDesigner; private ConnectionPoint source = null; private ConnectionPoint target = null; private List segments = new List (); private bool connectorModified = false; public Connector(ConnectionPoint source, ConnectionPoint target) { if (source == null) throw new ArgumentNullException("source"); if (target == null) throw new ArgumentNullException("target"); if (ConnectionManager.GetConnectorContainer(source.AssociatedDesigner) != ConnectionManager.GetConnectorContainer(target.AssociatedDesigner)) throw new ArgumentException(DR.GetString(DR.Error_Connector1)); this.source = source; this.target = target; } void IDisposable.Dispose() { } #endregion #region Properties and Methods public virtual AccessibleObject AccessibilityObject { get { if (this.accessibilityObject == null) this.accessibilityObject = new ConnectorAccessibleObject(this); return this.accessibilityObject; } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ConnectionPoint Source { get { return this.source; } set { if (value == null) throw new ArgumentNullException("value"); if (this.source.Equals(value)) return; if (ConnectionManager.GetConnectorContainer(value.AssociatedDesigner) != ConnectionManager.GetConnectorContainer(this.target.AssociatedDesigner)) throw new ArgumentException(SR.GetString(SR.Error_InvalidConnectorSource), "value"); this.source = value; PerformLayout(); } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ConnectionPoint Target { get { return this.target; } set { if (value == null) throw new ArgumentNullException("value"); if (this.target.Equals(value)) return; if (ConnectionManager.GetConnectorContainer(value.AssociatedDesigner) != ConnectionManager.GetConnectorContainer(this.source.AssociatedDesigner)) throw new ArgumentException(SR.GetString(SR.Error_InvalidConnectorSource), "value"); this.target = value; PerformLayout(); } } public virtual ReadOnlyCollection ConnectorSegments { get { List connectorSegments = new List (); if (this.source != null && this.target != null) { if (this.segments.Count == 0 || this.segments[0] != this.source.Location) connectorSegments.Add(this.source.Location); connectorSegments.AddRange(this.segments); if (this.segments.Count == 0 || this.segments[this.segments.Count - 1] != this.target.Location) connectorSegments.Add(this.target.Location); } return connectorSegments.AsReadOnly(); } } public Rectangle Bounds { get { Rectangle bounds = DesignerGeometryHelper.RectangleFromLineSegments(new List (ConnectorSegments).ToArray()); bounds.Inflate(1, 1); return bounds; } } public FreeformActivityDesigner ParentDesigner { get { return this.parentDesigner; } } public virtual bool HitTest(Point point) { Size selectionSize = WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize; //We go thru the line seagments and hittest ReadOnlyCollection segments = ConnectorSegments; for (int i = 1; i < segments.Count; i++) { if (DesignerGeometryHelper.PointOnLineSegment(point, new Point[] { segments[i - 1], segments[i] }, selectionSize)) return true; } return false; } public virtual void Offset(Size size) { for (int i = 0; i < this.segments.Count; i++) this.segments[i] = new Point(this.segments[i].X + size.Width, this.segments[i].Y + size.Height); } public override bool Equals(object obj) { Connector connector = obj as Connector; if (connector == null) return false; return (connector.Source == this.source && connector.target == this.target); } public override int GetHashCode() { if (this.source != null && this.target != null) return this.source.GetHashCode() ^ this.target.GetHashCode(); else return base.GetHashCode(); } public void Invalidate() { WorkflowView workflowView = ParentView; if (workflowView != null) workflowView.InvalidateLogicalRectangle(Bounds); } public bool ConnectorModified { get { return this.connectorModified; } } protected WorkflowView ParentView { get { return GetService(typeof(WorkflowView)) as WorkflowView; } } protected void PerformLayout() { WorkflowView workflowView = ParentView; if (workflowView != null) workflowView.PerformLayout(false); } protected internal virtual ICollection ExcludedRoutingRectangles { get { return new Rectangle[] { }; } } //We want to allow framework or the derived classes only to set the connector segments //We do not want any outside entity to set the connector segments randomly protected internal void SetConnectorSegments(ICollection segments) { //Called by derived classes when they want to change connector routing // if (segments == null) throw new ArgumentNullException("segments"); this.connectorModified = (this.parentDesigner != null && segments.Count > 0); if (this.connectorModified) Invalidate(); this.segments.Clear(); this.segments.AddRange(segments); if (this.connectorModified) Invalidate(); } protected internal virtual void OnLayout(ActivityDesignerLayoutEventArgs e) { if (this.segments.Count > 0 && (this.segments[0] != Source.Location || this.segments[this.segments.Count - 1] != Target.Location)) this.connectorModified = false; if (!connectorModified && ParentDesigner != null) { Point[] newSegments = ActivityDesignerConnectorRouter.Route(Source.AssociatedDesigner.Activity.Site, Source, Target, ExcludedRoutingRectangles); this.segments.Clear(); this.segments.AddRange(newSegments); } } protected internal virtual void OnPaint(ActivityDesignerPaintEventArgs e) { CompositeDesignerTheme theme = e.DesignerTheme as CompositeDesignerTheme; if (theme != null) { Size arrowCapSize = new Size(theme.ConnectorSize.Width / 5, theme.ConnectorSize.Height / 5); Size maxCapSize = theme.ConnectorSize; ActivityDesignerPaint.DrawConnectors(e.Graphics, e.DesignerTheme.ForegroundPen, new List (ConnectorSegments).ToArray(), arrowCapSize, maxCapSize, theme.ConnectorStartCap, theme.ConnectorEndCap); } } protected internal virtual void OnPaintSelected(ActivityDesignerPaintEventArgs e, bool primarySelection, Point[] segmentEditPoints) { CompositeDesignerTheme theme = e.DesignerTheme as CompositeDesignerTheme; if (theme == null) return; using (Pen lineSelectionPen = new Pen(WorkflowTheme.CurrentTheme.AmbientTheme.SelectionForeColor, 1)) { Size arrowCapSize = new Size(theme.ConnectorSize.Width / 5, theme.ConnectorSize.Height / 5); Size maxCapSize = theme.ConnectorSize; ActivityDesignerPaint.DrawConnectors(e.Graphics, lineSelectionPen, new List (ConnectorSegments).ToArray(), arrowCapSize, maxCapSize, theme.ConnectorStartCap, theme.ConnectorEndCap); } if (this.source != null) this.source.OnPaint(e, false); ReadOnlyCollection endSegmentEditPoints = ConnectorSegments; for (int i = 1; i < endSegmentEditPoints.Count - 1; i++) PaintEditPoints(e, endSegmentEditPoints[i], false); for (int i = 0; i < segmentEditPoints.Length; i++) PaintEditPoints(e, segmentEditPoints[i], true); if (this.target != null) this.target.OnPaint(e, false); } protected internal virtual void OnPaintEdited(ActivityDesignerPaintEventArgs e, Point[] segments, Point[] segmentEditPoints) { CompositeDesignerTheme theme = e.DesignerTheme as CompositeDesignerTheme; if (theme == null) return; using (Pen editableConnectorPen = new Pen(e.AmbientTheme.SelectionForegroundPen.Color, e.AmbientTheme.SelectionForegroundPen.Width)) { editableConnectorPen.DashStyle = DashStyle.Dash; Size arrowCapSize = new Size(theme.ConnectorSize.Width / 5, theme.ConnectorSize.Height / 5); Size maxCapSize = theme.ConnectorSize; ActivityDesignerPaint.DrawConnectors(e.Graphics, editableConnectorPen, segments, arrowCapSize, maxCapSize, theme.ConnectorStartCap, theme.ConnectorEndCap); } if (this.source != null) this.source.OnPaint(e, false); for (int i = 1; i < segments.Length - 1; i++) PaintEditPoints(e, segments[i], false); for (int i = 0; i < segmentEditPoints.Length; i++) PaintEditPoints(e, segmentEditPoints[i], true); if (this.target != null) this.target.OnPaint(e, false); } protected virtual object GetService(Type serviceType) { object service = null; if (this.parentDesigner != null && this.parentDesigner.Activity != null && this.parentDesigner.Activity.Site != null) service = this.parentDesigner.Activity.Site.GetService(serviceType); return service; } #endregion #region Helpers private void PaintEditPoints(ActivityDesignerPaintEventArgs e, Point point, bool drawMidSegmentEditPoint) { Size size = (this.source != null) ? this.source.Bounds.Size : Size.Empty; if (!size.IsEmpty) { Rectangle bounds = new Rectangle(point.X - size.Width / 2, point.Y - size.Height / 2, size.Width, size.Height); if (drawMidSegmentEditPoint) { using (GraphicsPath path = new GraphicsPath()) { path.AddLine(new Point(bounds.Left + bounds.Width / 2, bounds.Top), new Point(bounds.Right, bounds.Top + bounds.Height / 2)); path.AddLine(new Point(bounds.Right, bounds.Top + bounds.Height / 2), new Point(bounds.Left + bounds.Width / 2, bounds.Bottom)); path.AddLine(new Point(bounds.Left + bounds.Width / 2, bounds.Bottom), new Point(bounds.Left, bounds.Top + bounds.Height / 2)); path.AddLine(new Point(bounds.Left, bounds.Top + bounds.Height / 2), new Point(bounds.Left + bounds.Width / 2, bounds.Top)); e.Graphics.FillPath(Brushes.White, path); e.Graphics.DrawPath(e.AmbientTheme.SelectionForegroundPen, path); } } else { bounds.Inflate(-1, -1); e.Graphics.FillEllipse(e.AmbientTheme.SelectionForegroundBrush, bounds); } } } internal void SetConnectorModified(bool modified) { this.connectorModified = modified; } internal FreeformActivityDesigner RenderingOwner { get { if (this.source == null || this.target == null) return null; // List targetParents = new List (); ActivityDesigner designer = this.target.AssociatedDesigner; while (designer != null) { FreeformActivityDesigner parentFreeFormDesigner = designer as FreeformActivityDesigner; if (parentFreeFormDesigner != null) targetParents.Add(parentFreeFormDesigner); designer = designer.ParentDesigner; } //Go through the parent freeforms of source and match it with target, the first common //parent freeform is the rendering designer designer = this.source.AssociatedDesigner; while (designer != null) { FreeformActivityDesigner parentFreeFormDesigner = designer as FreeformActivityDesigner; if (parentFreeFormDesigner != null && targetParents.Contains(parentFreeFormDesigner)) break; designer = designer.ParentDesigner; } return designer as FreeformActivityDesigner; } } internal void SetParent(FreeformActivityDesigner parentDesigner) { //Make sure that this is in parent chain of both source and the target connection points WorkflowView workflowView = ParentView; if (this.parentDesigner != null && workflowView != null) workflowView.InvalidateLogicalRectangle(this.parentDesigner.Bounds); this.parentDesigner = parentDesigner; if (this.parentDesigner != null && workflowView != null) workflowView.InvalidateLogicalRectangle(this.parentDesigner.Bounds); } internal static Connector GetConnectorFromSelectedObject(object selectedObject) { Connector connector = null; ConnectorHitTestInfo connectorHitTestInfo = selectedObject as ConnectorHitTestInfo; if (connectorHitTestInfo != null) { FreeformActivityDesigner connectorContainer = connectorHitTestInfo.AssociatedDesigner as FreeformActivityDesigner; int index = connectorHitTestInfo.MapToIndex(); if (connectorContainer != null && index >= 0 && index < connectorContainer.Connectors.Count) connector = connectorContainer.Connectors[index]; } return connector; } #region Properties used during serialization only //NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] internal string SourceActivity { get { string activityName = String.Empty; if (this.source != null) activityName = this.source.AssociatedDesigner.Activity.QualifiedName; return activityName; } set { } } //NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] internal int SourceConnectionIndex { get { int connectionIndex = 0; if (this.source != null) connectionIndex = this.source.ConnectionIndex; return connectionIndex; } set { } } //NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] internal DesignerEdges SourceConnectionEdge { get { DesignerEdges connectionEdge = DesignerEdges.None; if (this.source != null) connectionEdge = this.source.ConnectionEdge; return connectionEdge; } set { } } //NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] internal string TargetActivity { get { string activityName = String.Empty; if (this.target != null) activityName = this.target.AssociatedDesigner.Activity.QualifiedName; return activityName; } set { } } //NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] internal int TargetConnectionIndex { get { int connectionIndex = 0; if (this.target != null) connectionIndex = this.target.ConnectionIndex; return connectionIndex; } set { } } //NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] internal DesignerEdges TargetConnectionEdge { get { DesignerEdges connectionEdge = DesignerEdges.None; if (this.target != null) connectionEdge = this.target.ConnectionEdge; return connectionEdge; } set { } } //NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] internal List Segments { get { return this.segments; } } #endregion #endregion } #endregion #region Class ConnectorAccessibleObject public class ConnectorAccessibleObject : AccessibleObject { private Connector connector; public ConnectorAccessibleObject(Connector connector) { if (connector == null) throw new ArgumentNullException("connector"); this.connector = connector; } public override Rectangle Bounds { get { WorkflowView parentView = this.connector.ParentDesigner.ParentView; Rectangle bounds = this.connector.Bounds; return new Rectangle(parentView.LogicalPointToScreen(bounds.Location), parentView.LogicalSizeToClient(bounds.Size)); } } public override AccessibleObject HitTest(int x, int y) { WorkflowView parentView = this.connector.ParentDesigner.ParentView; if (this.connector.HitTest(parentView.ScreenPointToLogical(new Point(x, y)))) return this; else return null; } public override string Name { get { return this.connector.GetType().Name; } set { } } public override AccessibleObject Parent { get { return connector.ParentDesigner.AccessibilityObject; } } public override AccessibleRole Role { get { return AccessibleRole.Diagram; } } } #endregion Class ConnectorAccessibleObject #region Class ConnectorEditor internal sealed class ConnectorEditor { private IServiceProvider serviceProvider; private Connector editedConnector; private EditPoint activeEditPoint; private List editPoints = new List (); public ConnectorEditor(Connector connectorEdited) { this.editedConnector = connectorEdited; this.serviceProvider = this.editedConnector.Source.AssociatedDesigner.Activity.Site; CreateEditPoints(); } public ConnectionPoint EditedConectionPoint { get { if (this.activeEditPoint != null) return this.activeEditPoint.EditedConnectionPoint; else return null; } } public Connector EditedConnector { get { return this.editedConnector; } } public Cursor GetCursor(Point cursorPoint) { Cursor cursor = Cursors.Default; if (this.activeEditPoint != null) { cursor = ConnectionManager.NewConnectorCursor; } else { foreach (EditPoint editPoint in this.editPoints) { if (editPoint.Bounds.Contains(cursorPoint)) { cursor = ConnectionManager.SnappedConnectionCursor; break; } } } return cursor; } public bool OnBeginEditing(Point point) { //Get all the editable points CreateEditPoints(); EditPoint editPointHit = null; for (int i = this.editPoints.Count - 1; i >= 0; i--) { if (this.editPoints[i].Bounds.Contains(point)) { editPointHit = this.editPoints[i]; break; } } if (editPointHit != null && (editPointHit.EditedConnectionPoint == null || ConnectionManager.GetConnectorContainer(editPointHit.EditedConnectionPoint.AssociatedDesigner) != null)) { editPointHit.Location = point; this.activeEditPoint = editPointHit; } Invalidate(); return (this.activeEditPoint != null); } public void OnContinueEditing(Point point) { if (this.activeEditPoint == null) return; Invalidate(); UpdateEditPoints(point); Invalidate(); #if DISPLAYESCAPEREGIONS WorkflowView workflowView = GetService(typeof(WorkflowView)) as WorkflowView; if (workflowView != null) workflowView.InvalidateClientRectangle(Rectangle.Empty); #endif } public void OnEndEditing(Point point, bool commitChanges) { if (this.activeEditPoint == null) return; Invalidate(); if (commitChanges) { //This is to update the edit points based on the activepoint UpdateEditPoints(point); EditPoint activeEditPoint = this.activeEditPoint; this.activeEditPoint = null; //This call is to optimize the segments UpdateEditPoints(point); //If we were creating a new connector or modifying the connection end points bool updateSegments = false; if (activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint) { ConnectionManager connectionManager = GetService(typeof(ConnectionManager)) as ConnectionManager; FreeformActivityDesigner connectorContainer = ConnectionManager.GetConnectorContainer(activeEditPoint.EditedConnectionPoint.AssociatedDesigner); if (connectionManager != null && connectionManager.SnappedConnectionPoint != null && connectorContainer != null) { //Get the original source and targets ConnectionPoint source = this.editedConnector.Source; ConnectionPoint target = this.editedConnector.Target; //Make sure that we set the source and target correctly if (target.Equals(activeEditPoint.EditedConnectionPoint)) target = connectionManager.SnappedConnectionPoint; else if (source.Equals(activeEditPoint.EditedConnectionPoint)) source = connectionManager.SnappedConnectionPoint; //Check if it is a valid connection ie source can be connected to target if (connectorContainer == ConnectionManager.GetConnectorContainer(target.AssociatedDesigner) && connectorContainer.CanConnectContainedDesigners(source, target)) { this.editedConnector.Source = source; this.editedConnector.Target = target; if (this.editedConnector.ParentDesigner == null) { this.editedConnector = connectorContainer.AddConnector(source, target); WorkflowDesignerLoader loader = GetService(typeof(WorkflowDesignerLoader)) as WorkflowDesignerLoader; if (loader != null) loader.SetModified(true); } connectorContainer.OnContainedDesignersConnected(source, target); } updateSegments = true; } } else { updateSegments = true; } //Make sure that we apply the edit points to the connector if (updateSegments) { this.editedConnector.SetConnectorSegments(GetPointsFromEditPoints(this.editPoints)); if (this.editedConnector.ParentDesigner != null) { this.editedConnector.ParentDesigner.OnConnectorChanged(new ConnectorEventArgs(this.editedConnector)); WorkflowDesignerLoader loader = GetService(typeof(WorkflowDesignerLoader)) as WorkflowDesignerLoader; if (loader != null) loader.SetModified(true); } } PerformLayout(); } Invalidate(); } public bool HitTest(Point point) { for (int i = 0; i < this.editPoints.Count; i++) { EditPoint editPoint = this.editPoints[i]; if (editPoint.Bounds.Contains(point)) return true; } return false; } public void OnPaint(ActivityDesignerPaintEventArgs e, bool drawSelected, bool drawPrimarySelection) { List segments = new List (); List segmentEditPoints = new List (); for (int i = 0; i < this.editPoints.Count; i++) { EditPoint editPoint = this.editPoints[i]; if (editPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint || editPoint.Type == EditPoint.EditPointTypes.MultiSegmentEditPoint) segments.Add(editPoint.Location); else segmentEditPoints.Add(editPoint.Location); } //If the editing is in progress then we want to draw the dashed lines if (drawSelected) this.editedConnector.OnPaintSelected(e, drawPrimarySelection, segmentEditPoints.ToArray()); if (this.activeEditPoint != null) this.editedConnector.OnPaintEdited(e, segments.ToArray(), segmentEditPoints.ToArray()); // #if DISPLAYESCAPEREGIONS if (this.activeEditPoint != null && this.activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint) { object source = null, target = null; if (this.activeEditPoint.EditedConnectionPoint.Equals(Target)) { target = this.activeEditPoint.Location; source = Source; } else { source = this.activeEditPoint.Location; target = Target; } List rectanglesToExclude; List linesToExclude, pointsToExclude; ActivityDesignerConnectorRouter.GetRoutingObstacles(this.serviceProvider, source, target, out rectanglesToExclude, out linesToExclude, out pointsToExclude); ICollection userDefinedObstacles = this.editedConnector.ExcludedRoutingRectangles; if (userDefinedObstacles != null) { foreach (Rectangle rectangle in userDefinedObstacles) e.Graphics.DrawRectangle(Pens.DarkGreen, rectangle); } foreach (Rectangle rectangle in rectanglesToExclude) e.Graphics.DrawRectangle(Pens.Red, rectangle); for (int i = 0; i < linesToExclude.Count / 2; i++) e.Graphics.DrawLine(Pens.Red, linesToExclude[i * 2], linesToExclude[(i * 2) + 1]); } #endif } #region Helpers #region EditPointUpdation Logic private ConnectionPoint Source { get { return this.editedConnector.Source; } } private ConnectionPoint Target { get { return this.editedConnector.Target; } } private void PerformLayout() { WorkflowView workflowView = GetService(typeof(WorkflowView)) as WorkflowView; if (workflowView != null) workflowView.PerformLayout(false); } private void Invalidate() { WorkflowView workflowView = GetService(typeof(WorkflowView)) as WorkflowView; if (workflowView != null) { Rectangle bounds = DesignerGeometryHelper.RectangleFromLineSegments(GetPointsFromEditPoints(this.editPoints).ToArray()); bounds.Inflate(1, 1); workflowView.InvalidateLogicalRectangle(bounds); } } private object GetService(Type serviceType) { object service = null; if (this.serviceProvider != null) service = this.serviceProvider.GetService(serviceType); return service; } private void CreateEditPoints() { this.editPoints.Clear(); AddEditPoints(EditPoint.EditPointTypes.ConnectionEditPoint); AddEditPoints(EditPoint.EditPointTypes.MultiSegmentEditPoint); AddEditPoints(EditPoint.EditPointTypes.MidSegmentEditPoint); bool validEditPoints = ValidateEditPoints(); Debug.Assert(validEditPoints); } private void UpdateEditPoints(Point newPoint) { if (this.editPoints.Count < 2 || this.editPoints[0].Type != EditPoint.EditPointTypes.ConnectionEditPoint || this.editPoints[this.editPoints.Count - 1].Type != EditPoint.EditPointTypes.ConnectionEditPoint) { Debug.Assert(false); return; } //STEP1: First we delete all the midsegmentpoints except the one which is being edited for simplicity RemoveEditPoints(EditPoint.EditPointTypes.MidSegmentEditPoint); //STEP2: Update points as per the type of edit point if (this.activeEditPoint != null) { int activeEditPointIndex = this.editPoints.IndexOf(this.activeEditPoint); EditPoint previous = (activeEditPointIndex > 0) ? this.editPoints[activeEditPointIndex - 1] : null; EditPoint next = (activeEditPointIndex < this.editPoints.Count - 1) ? this.editPoints[activeEditPointIndex + 1] : null; //Note that extra edit points are only added if we are connected to connection point if (previous != null && previous.Type == EditPoint.EditPointTypes.ConnectionEditPoint) { float slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, this.activeEditPoint.Location); Orientation orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical; int editPointOffset = Convert.ToInt32(DesignerGeometryHelper.DistanceBetweenPoints(previous.Location, (next != null) ? next.Location : this.activeEditPoint.Location)) / 4; if (orientation == Orientation.Horizontal) editPointOffset *= (previous.Location.X < this.activeEditPoint.Location.X) ? 1 : -1; else editPointOffset *= (previous.Location.Y < this.activeEditPoint.Location.X) ? 1 : -1; activeEditPointIndex = this.editPoints.IndexOf(this.activeEditPoint); Point editPointLocation = (orientation == Orientation.Horizontal) ? new Point(previous.Location.X + editPointOffset, previous.Location.Y) : new Point(previous.Location.X, previous.Location.Y + editPointOffset); previous = new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, editPointLocation); this.editPoints.InsertRange(activeEditPointIndex, new EditPoint[] { new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, editPointLocation), previous }); } if (next != null && next.Type == EditPoint.EditPointTypes.ConnectionEditPoint) { float slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(this.activeEditPoint.Location, next.Location); Orientation orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical; int editPointOffset = Convert.ToInt32(DesignerGeometryHelper.DistanceBetweenPoints((previous != null) ? previous.Location : this.activeEditPoint.Location, next.Location)) / 4; if (orientation == Orientation.Horizontal) editPointOffset *= (this.activeEditPoint.Location.X < next.Location.X) ? -1 : 1; else editPointOffset *= (this.activeEditPoint.Location.Y < next.Location.Y) ? -1 : 1; activeEditPointIndex = this.editPoints.IndexOf(this.activeEditPoint); Point editPointLocation = (orientation == Orientation.Horizontal) ? new Point(next.Location.X + editPointOffset, next.Location.Y) : new Point(next.Location.X, next.Location.Y + editPointOffset); next = new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, editPointLocation); this.editPoints.InsertRange(activeEditPointIndex + 1, new EditPoint[] { next, new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, editPointLocation) }); } //STEP2: UPDATE THE EDIT POINTS if (this.activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint) { this.activeEditPoint.Location = newPoint; //When we start editing the end point we need to clear the slate and start over RemoveEditPoints(EditPoint.EditPointTypes.MultiSegmentEditPoint); object source = null, target = null; if (this.activeEditPoint.EditedConnectionPoint.Equals(Target)) { target = newPoint; source = Source; } else { source = newPoint; target = Target; } int newEditPointIndex = (this.editPoints.Count == 2) ? 1 : 0; List newEditPoints = new List (); Point[] points = ActivityDesignerConnectorRouter.Route(this.serviceProvider, source, target, this.editedConnector.ExcludedRoutingRectangles); for (int i = newEditPointIndex; i < points.Length - newEditPointIndex; i++ ) newEditPoints.Add(new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, points[i])); this.editPoints.InsertRange(1, newEditPoints.ToArray()); } else if (this.activeEditPoint.Type == EditPoint.EditPointTypes.MultiSegmentEditPoint) { if (previous != null && previous.Type != EditPoint.EditPointTypes.ConnectionEditPoint && next != null && next.Type != EditPoint.EditPointTypes.ConnectionEditPoint) { //Update the previous point float slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, this.activeEditPoint.Location); Orientation orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical; previous.Location = (orientation == Orientation.Horizontal) ? new Point(previous.Location.X, newPoint.Y) : new Point(newPoint.X, previous.Location.Y); //Update the next point slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(this.activeEditPoint.Location, next.Location); orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical; next.Location = (orientation == Orientation.Horizontal) ? new Point(next.Location.X, newPoint.Y) : new Point(newPoint.X, next.Location.Y); //Update the current point this.activeEditPoint.Location = newPoint; } else { Debug.Assert(false); } } else if (this.activeEditPoint.Type == EditPoint.EditPointTypes.MidSegmentEditPoint) { if (previous != null && previous.Type != EditPoint.EditPointTypes.ConnectionEditPoint && next != null && next.Type != EditPoint.EditPointTypes.ConnectionEditPoint) { float slopeOfLine = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, next.Location); Orientation orientation = (Math.Abs(slopeOfLine) < 1) ? Orientation.Horizontal : Orientation.Vertical; //If the orientation is horizontal then we need to move the points vertically else we need to move the points horizontally if (orientation == Orientation.Horizontal) { previous.Location = new Point(previous.Location.X, newPoint.Y); next.Location = new Point(next.Location.X, newPoint.Y); this.activeEditPoint.Location = new Point(this.activeEditPoint.Location.X, newPoint.Y); } else { previous.Location = new Point(newPoint.X, previous.Location.Y); next.Location = new Point(newPoint.X, next.Location.Y); this.activeEditPoint.Location = new Point(newPoint.X, this.activeEditPoint.Location.Y); } } else { Debug.Assert(false); } } } //STEP3: Remove all the redundant edit points RemoveCoincidingEditPoints(); //STEP4: Add back the segment mid points AddEditPoints(EditPoint.EditPointTypes.MidSegmentEditPoint); bool validEditPoints = ValidateEditPoints(); Debug.Assert(validEditPoints); } //Add edit points of specified type private void AddEditPoints(EditPoint.EditPointTypes editPointType) { if (editPointType == EditPoint.EditPointTypes.ConnectionEditPoint) { if (this.editPoints.Count == 0 || !this.editPoints[0].EditedConnectionPoint.Equals(Source)) this.editPoints.Insert(0, new EditPoint(this, Source)); if (this.editPoints.Count < 2 || !this.editPoints[this.editPoints.Count - 1].EditedConnectionPoint.Equals(Target)) editPoints.Add(new EditPoint(this, Target)); } else if (editPointType == EditPoint.EditPointTypes.MidSegmentEditPoint) { int minLengthForSegmentEditPoint = Source.Bounds.Width * 4; for (int i = 0; i < this.editPoints.Count - 1; i++) { if (this.editPoints[i].Type != EditPoint.EditPointTypes.MidSegmentEditPoint && this.editPoints[i + 1].Type != EditPoint.EditPointTypes.MidSegmentEditPoint && DesignerGeometryHelper.DistanceOfLineSegments(new Point[] { this.editPoints[i].Location, this.editPoints[i + 1].Location }) > minLengthForSegmentEditPoint) { Point midPoint = DesignerGeometryHelper.MidPointOfLineSegment(this.editPoints[i].Location, this.editPoints[i + 1].Location); this.editPoints.Insert(i + 1, new EditPoint(this, EditPoint.EditPointTypes.MidSegmentEditPoint, midPoint)); } } } else if (editPointType == EditPoint.EditPointTypes.MultiSegmentEditPoint) { if (this.editPoints.Count == 2) { List segments = new List (this.editedConnector.ConnectorSegments); if (segments.Count > 0 && segments[0] == Source.Location) segments.RemoveAt(0); if (segments.Count > 0 && segments[segments.Count - 1] == Target.Location) segments.RemoveAt(segments.Count - 1); List editPointsToAdd = new List (); for (int i = 0; i < segments.Count; i++) editPointsToAdd.Add(new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, segments[i])); this.editPoints.InsertRange(this.editPoints.Count - 1, editPointsToAdd.ToArray()); } else { Debug.Assert(false); } } } //Remove edit points of specified type private void RemoveEditPoints(EditPoint.EditPointTypes editPointType) { List editPointsToRemove = new List (); for (int i = 0; i < this.editPoints.Count; i++) { EditPoint editPoint = this.editPoints[i]; if (editPoint.Type == editPointType) editPointsToRemove.Add(editPoint); } for (int i = 0; i < editPointsToRemove.Count; i++) { EditPoint editPoint = editPointsToRemove[i]; if (editPoint != this.activeEditPoint) this.editPoints.Remove(editPoint); } } //Remove points with same slope private void RemoveCoincidingEditPoints() { if (this.editPoints.Count < 2 || this.editPoints[0].Type != EditPoint.EditPointTypes.ConnectionEditPoint || this.editPoints[this.editPoints.Count - 1].Type != EditPoint.EditPointTypes.ConnectionEditPoint || (this.activeEditPoint != null && this.activeEditPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint)) { return; } //Just make sure that there are no mid segmment edit points or algorithm will fail RemoveEditPoints(EditPoint.EditPointTypes.MidSegmentEditPoint); //Create list of points to retain List editPointsToRetain = new List (); for (int i = 0; i < this.editPoints.Count; i++) { if (this.editPoints[i].Type != EditPoint.EditPointTypes.MultiSegmentEditPoint || this.editPoints[i] == this.activeEditPoint || (i > 0 && this.editPoints[i - 1].Type == EditPoint.EditPointTypes.MidSegmentEditPoint) || (i < this.editPoints.Count - 1 && this.editPoints[i + 1].Type == EditPoint.EditPointTypes.MidSegmentEditPoint)) { editPointsToRetain.Add(this.editPoints[i]); } } //Step1: Get rid of all the line segments which are within tolerance range for (int i = 1; i < this.editPoints.Count - 1; i++) { EditPoint previous = this.editPoints[i - 1]; EditPoint current = this.editPoints[i]; EditPoint next = this.editPoints[i + 1]; if (!editPointsToRetain.Contains(current)) { double distance = DesignerGeometryHelper.DistanceOfLineSegments(new Point[] { previous.Location, current.Location }); if ((distance < current.Bounds.Width || distance < current.Bounds.Height) && next.Type == EditPoint.EditPointTypes.MultiSegmentEditPoint) { float slope = DesignerGeometryHelper.SlopeOfLineSegment(current.Location, next.Location); next.Location = (slope < 1) ? new Point(next.Location.X, previous.Location.Y) : new Point(previous.Location.X, next.Location.Y); this.editPoints.Remove(current); i -= 1; } else { distance = DesignerGeometryHelper.DistanceOfLineSegments(new Point[] { current.Location, next.Location }); if ((distance < current.Bounds.Width || distance < current.Bounds.Height) && previous.Type == EditPoint.EditPointTypes.MultiSegmentEditPoint) { float slope = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, current.Location); previous.Location = (slope < 1) ? new Point(previous.Location.X, next.Location.Y) : new Point(next.Location.X, previous.Location.Y); this.editPoints.Remove(current); i -= 1; } } } } //Step2: We should make sure that the active edit point is always retained but those points which are coincidental are always removed for (int i = 1; i < this.editPoints.Count - 1; i++) { EditPoint current = this.editPoints[i]; EditPoint previous = this.editPoints[i - 1]; EditPoint next = this.editPoints[i + 1]; if (!editPointsToRetain.Contains(current)) { float slope1 = DesignerGeometryHelper.SlopeOfLineSegment(previous.Location, current.Location); float slope2 = DesignerGeometryHelper.SlopeOfLineSegment(current.Location, next.Location); if (Math.Abs(slope1) == Math.Abs(slope2)) { this.editPoints.Remove(current); i -= 1; } } } //Step3: Go thorugh each segment and ensure that there all the segments are either vertical or horizontal for (int i = 0; i < this.editPoints.Count - 1; i++) { EditPoint current = this.editPoints[i]; EditPoint next = this.editPoints[i + 1]; float slope = DesignerGeometryHelper.SlopeOfLineSegment(current.Location, next.Location); if (slope != 0 && slope != float.MaxValue) { Point location = (slope < 1) ? new Point(next.Location.X, current.Location.Y) : new Point(current.Location.X, next.Location.Y); this.editPoints.Insert(i + 1, new EditPoint(this, EditPoint.EditPointTypes.MultiSegmentEditPoint, location)); } } } private bool ValidateEditPoints() { if (this.editPoints.Count < 2) return false; ConnectionPoint sourceConnection = this.editPoints[0].EditedConnectionPoint; if (sourceConnection == null || !sourceConnection.Equals(Source)) return false; ConnectionPoint targetConnection = this.editPoints[this.editPoints.Count - 1].EditedConnectionPoint; if (targetConnection == null || !targetConnection.Equals(Target)) return false; for (int i = 0; i < this.editPoints.Count - 1; i++) { if (this.editPoints[i].Type == EditPoint.EditPointTypes.MidSegmentEditPoint && this.editPoints[i + 1].Type == EditPoint.EditPointTypes.MidSegmentEditPoint) return false; } return true; } #endregion private List GetPointsFromEditPoints(List editPoints) { List segments = new List (); for (int i = 0; i < editPoints.Count; i++) { EditPoint editPoint = editPoints[i]; if (editPoint.Type == EditPoint.EditPointTypes.ConnectionEditPoint || editPoint.Type == EditPoint.EditPointTypes.MultiSegmentEditPoint) segments.Add(editPoint.Location); } return segments; } #endregion #region Class EditPoint private sealed class EditPoint { public enum EditPointTypes { ConnectionEditPoint = 1, MultiSegmentEditPoint, MidSegmentEditPoint }; private ConnectorEditor owner; private EditPointTypes editPointType; private Point point; private ConnectionPoint connectionPoint; public EditPoint(ConnectorEditor owner, EditPointTypes editPointType, Point point) { this.owner = owner; this.editPointType = editPointType; this.point = point; } public EditPoint(ConnectorEditor owner, ConnectionPoint connectionPoint) { this.owner = owner; this.editPointType = EditPointTypes.ConnectionEditPoint; this.connectionPoint = connectionPoint; this.point = connectionPoint.Location; } public EditPointTypes Type { get { return this.editPointType; } } public Point Location { get { return this.point; } set { this.point = value; } } public Rectangle Bounds { get { Size controlPointSize = this.owner.Source.Bounds.Size; return new Rectangle(this.point.X - controlPointSize.Width / 2, this.point.Y - controlPointSize.Height / 2, controlPointSize.Width, controlPointSize.Height); } } public ConnectionPoint EditedConnectionPoint { get { return this.connectionPoint; } } } #endregion } #endregion #region Class ActivityDesignerConnectorRouter internal static class ActivityDesignerConnectorRouter { public static Point[] Route(IServiceProvider serviceProvider, object source, object target, ICollection userDefinedRoutingObstacles) { //Now call routing algorithm List rectanglesToExclude; List linesToExclude, pointsToExclude; ActivityDesignerConnectorRouter.GetRoutingObstacles(serviceProvider, source, target, out rectanglesToExclude, out linesToExclude, out pointsToExclude); if (userDefinedRoutingObstacles != null) rectanglesToExclude.AddRange(userDefinedRoutingObstacles); ActivityDesigner rootDesigner = ActivityDesigner.GetSafeRootDesigner(serviceProvider); AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme; Point sourcePoint = (source is ConnectionPoint) ? ((ConnectionPoint)source).Location : (Point)source; Point targetPoint = (target is ConnectionPoint) ? ((ConnectionPoint)target).Location : (Point)target; Point[] routedPoints = ConnectorRouter.Route(sourcePoint, targetPoint, new Size(2 * ambientTheme.Margin.Width, 2 * ambientTheme.Margin.Height), rootDesigner.Bounds, rectanglesToExclude.ToArray(), linesToExclude.ToArray(), pointsToExclude.ToArray()); // if (!AreAllSegmentsVerticalOrHorizontal(routedPoints)) routedPoints = ConnectorRouter.Route(sourcePoint, targetPoint, ambientTheme.Margin, rootDesigner.Bounds, new Rectangle[] { }, linesToExclude.ToArray(), new Point[] { }); //FALLBACK1 if (!AreAllSegmentsVerticalOrHorizontal(routedPoints)) { float slope = DesignerGeometryHelper.SlopeOfLineSegment(sourcePoint, targetPoint); Point intermediatePoint = (slope < 1) ? new Point(targetPoint.X, sourcePoint.Y) : new Point(sourcePoint.X, targetPoint.Y); routedPoints = new Point[] { sourcePoint, intermediatePoint, targetPoint }; } return routedPoints; } public static void GetRoutingObstacles(IServiceProvider serviceProvider, object source, object target, out List rectanglesToExclude, out List linesToExclude, out List pointsToExclude) { //Source or Targets can be either ConnectionPoint or a Point AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme; ActivityDesigner rootDesigner = ActivityDesigner.GetSafeRootDesigner(serviceProvider); ConnectionPoint sourceConnectionPoint = source as ConnectionPoint; Point sourcePoint = (sourceConnectionPoint != null) ? sourceConnectionPoint.Location : (Point)source; ActivityDesigner sourceDesigner = (sourceConnectionPoint != null) ? sourceConnectionPoint.AssociatedDesigner : rootDesigner.HitTest(sourcePoint).AssociatedDesigner; ConnectionPoint targetConnectionPoint = target as ConnectionPoint; Point targetPoint = (targetConnectionPoint != null) ? targetConnectionPoint.Location : (Point)target; ActivityDesigner targetDesigner = (targetConnectionPoint != null) ? targetConnectionPoint.AssociatedDesigner : rootDesigner.HitTest(targetPoint).AssociatedDesigner; //Collect the common parent chain of source and target Dictionary parentDesignerDictionary = new Dictionary (); if (sourceDesigner != null) { //Collect designers in the source parent chain CompositeActivityDesigner parentDesigner = sourceDesigner.ParentDesigner; while (parentDesigner != null) { if (!parentDesignerDictionary.ContainsKey(parentDesigner.GetHashCode())) parentDesignerDictionary.Add(parentDesigner.GetHashCode(), parentDesigner); else break; parentDesigner = parentDesigner.ParentDesigner; } } if (targetDesigner != null) { //Collect designer from target chain which are not in source chain CompositeActivityDesigner parentDesigner = targetDesigner.ParentDesigner; while (parentDesigner != null) { if (!parentDesignerDictionary.ContainsKey(parentDesigner.GetHashCode())) parentDesignerDictionary.Add(parentDesigner.GetHashCode(), parentDesigner); else break; parentDesigner = parentDesigner.ParentDesigner; } } //Now go through the dictionary and add all the children that are not in the chain rectanglesToExclude = new List (); pointsToExclude = new List (); foreach (CompositeActivityDesigner parentDesigner in parentDesignerDictionary.Values) { ReadOnlyCollection containedDesigners = parentDesigner.ContainedDesigners; for (int j = 0; j < containedDesigners.Count; j++) { ActivityDesigner activityDesigner = containedDesigners[j]; if (activityDesigner.IsVisible && !parentDesignerDictionary.ContainsKey(activityDesigner.GetHashCode()) && activityDesigner != sourceDesigner && activityDesigner != targetDesigner) { Rectangle rectangleToExclude = activityDesigner.Bounds; rectangleToExclude.Inflate(ambientTheme.Margin); rectanglesToExclude.Add(rectangleToExclude); } } // } //Now get the exclusion paths for source designer and target designer linesToExclude = new List (); if (sourceDesigner != null && sourceDesigner == targetDesigner && !sourceDesigner.IsRootDesigner) { linesToExclude.AddRange(GetDesignerEscapeCover(sourceDesigner, new object[] { source, target })); } else { if (sourceDesigner != null && !sourceDesigner.IsRootDesigner) linesToExclude.AddRange(GetDesignerEscapeCover(sourceDesigner, new object[] { source })); if (targetDesigner != null && !targetDesigner.IsRootDesigner) { bool needToEscapeTargetDesigner = true; CompositeActivityDesigner sourceParentDesigner = (sourceDesigner != null) ? sourceDesigner.ParentDesigner : null; while (sourceParentDesigner != null) { if (targetDesigner == sourceParentDesigner) { needToEscapeTargetDesigner = false; break; } sourceParentDesigner = (sourceDesigner != null) ? sourceParentDesigner.ParentDesigner : null; } //need to escape the target designer only if the source is not inside the parent if(needToEscapeTargetDesigner) linesToExclude.AddRange(GetDesignerEscapeCover(targetDesigner, new object[] { target })); } } } private static IList GetDesignerEscapeCover(ActivityDesigner designer, ICollection
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FileDialog_Vista.cs
- XmlSortKeyAccumulator.cs
- WebBrowser.cs
- SqlUserDefinedTypeAttribute.cs
- CodeCompileUnit.cs
- BitmapDecoder.cs
- Object.cs
- CorrelationKeyCalculator.cs
- ScrollViewer.cs
- DbConnectionHelper.cs
- WebPartMenuStyle.cs
- XPathBinder.cs
- XPathDocumentNavigator.cs
- OrderedDictionaryStateHelper.cs
- AspCompat.cs
- TextElementCollection.cs
- RegexGroup.cs
- exports.cs
- CapacityStreamGeometryContext.cs
- EventHandlerList.cs
- QueryExpr.cs
- MatchingStyle.cs
- DefaultWorkflowSchedulerService.cs
- DrawingVisualDrawingContext.cs
- TargetInvocationException.cs
- SqlTriggerAttribute.cs
- UnicodeEncoding.cs
- TriggerCollection.cs
- ItemsControl.cs
- Inline.cs
- Size3D.cs
- TokenBasedSet.cs
- TreeViewDataItemAutomationPeer.cs
- CngKeyCreationParameters.cs
- precedingquery.cs
- TabletDeviceInfo.cs
- CanonicalXml.cs
- SystemColorTracker.cs
- UInt16Converter.cs
- SqlCacheDependencyDatabase.cs
- PeerNodeTraceRecord.cs
- HttpProxyTransportBindingElement.cs
- GetReadStreamResult.cs
- PopupRoot.cs
- ResourceDisplayNameAttribute.cs
- WmlControlAdapter.cs
- __ConsoleStream.cs
- ZipFileInfoCollection.cs
- MDIControlStrip.cs
- SoapObjectReader.cs
- ObjRef.cs
- TraceSwitch.cs
- OleDbDataReader.cs
- ListItemCollection.cs
- XsltCompileContext.cs
- PolyLineSegmentFigureLogic.cs
- AutomationElementCollection.cs
- ProxyBuilder.cs
- ProfileGroupSettings.cs
- PartitionResolver.cs
- FieldInfo.cs
- StorageRoot.cs
- QuaternionRotation3D.cs
- ConnectionsZone.cs
- InvalidProgramException.cs
- XmlTextReaderImpl.cs
- SqlTypesSchemaImporter.cs
- TableStyle.cs
- CommunicationObjectFaultedException.cs
- XmlAtomicValue.cs
- XmlSerializer.cs
- BamlResourceSerializer.cs
- uribuilder.cs
- IODescriptionAttribute.cs
- TreeChangeInfo.cs
- GreenMethods.cs
- ResXResourceSet.cs
- UrlAuthFailedErrorFormatter.cs
- HtmlPageAdapter.cs
- WebSysDefaultValueAttribute.cs
- ApplicationTrust.cs
- PropertyTabChangedEvent.cs
- DataGridHyperlinkColumn.cs
- FixUp.cs
- TextEvent.cs
- BooleanExpr.cs
- AppDomainFactory.cs
- CursorConverter.cs
- TypeUtils.cs
- ControlDesignerState.cs
- ActionItem.cs
- Setter.cs
- _NativeSSPI.cs
- PolyLineSegment.cs
- OdbcEnvironmentHandle.cs
- TableLayoutStyleCollection.cs
- UshortList2.cs
- DesignerHelpers.cs
- ContextInformation.cs
- PlainXmlDeserializer.cs