FlowchartDesigner.xaml.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Core.Presentation / System / Activities / Core / Presentation / FlowchartDesigner.xaml.cs / 1570162 / FlowchartDesigner.xaml.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.Activities.Core.Presentation 
{
    using System.Activities; 
    using System.Activities.Presentation; 
    using System.Activities.Presentation.Hosting;
    using System.Activities.Presentation.Internal.PropertyEditing; 
    using System.Activities.Presentation.Metadata;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.View;
    using System.Activities.Statements; 
    using System.Collections.Generic;
    using System.ComponentModel; 
    using System.Runtime; 
    using System.Windows;
    using System.Windows.Controls; 
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media; 
    using System.Windows.Threading;
 
    [ActivityDesignerOptions(AlwaysCollapseChildren = true)] 
    partial class FlowchartDesigner
    { 
        public static readonly DependencyProperty ConnectionPointsProperty = DependencyProperty.RegisterAttached("ConnectionPoints", typeof(List), typeof(FlowchartDesigner), new FrameworkPropertyMetadata());
        public static readonly DependencyProperty LinkModelItemProperty = DependencyProperty.RegisterAttached("LinkModelItem", typeof(ModelItem), typeof(FlowchartDesigner), new FrameworkPropertyMetadata());
        public static readonly DependencyProperty FlowElementModelItemProperty = DependencyProperty.RegisterAttached("FlowElementModelItem", typeof(ModelItem), typeof(FlowchartDesigner), new FrameworkPropertyMetadata());
 
        public static readonly DependencyProperty FlowchartWidthProperty = DependencyProperty.Register("FlowchartWidth", typeof(double), typeof(FlowchartDesigner), new FrameworkPropertyMetadata());
        public static readonly DependencyProperty FlowchartHeightProperty = DependencyProperty.Register("FlowchartHeight", typeof(double), typeof(FlowchartDesigner), new FrameworkPropertyMetadata()); 
 
        public static readonly DependencyProperty TrueConnectionPointProperty = DependencyProperty.RegisterAttached("TrueConnectionPoint", typeof(ConnectionPoint), typeof(FlowchartDesigner), new FrameworkPropertyMetadata());
        public static readonly DependencyProperty FalseConnectionPointProperty = DependencyProperty.RegisterAttached("FalseConnectionPoint", typeof(ConnectionPoint), typeof(FlowchartDesigner), new FrameworkPropertyMetadata()); 

        public static readonly DependencyProperty ShowAllConditionsProperty = DependencyProperty.Register("ShowAllConditions", typeof(bool), typeof(FlowchartDesigner));

        public static readonly RoutedCommand SetAsStartNodeCommand = new RoutedCommand("SetAsStartNode", typeof(FlowchartDesigner)); 
        //public static readonly RoutedCommand ConnectNodesCommand = new RoutedCommand("ConnectNodes", typeof(FlowchartDesigner));
        public static readonly RoutedCommand ShowAllConditionsCommand = new RoutedCommand("ShowAllConditionsCommand", typeof(FlowchartDesigner)); 
        public static readonly RoutedCommand HideAllConditionsCommand = new RoutedCommand("HideAllConditionsCommand", typeof(FlowchartDesigner)); 

        const double flowElementCaptionFontSize = 11; 
        const double DebugTimeMaxConnectorShapeDist = 10;
        static readonly FontFamily flowElementCaptionFontFamily = new FontFamily("Tohoma");
        static readonly FontStyle flowElementCaptionFontStyle = new FontStyle();
        static readonly Typeface flowElementCaptionTypeface = new Typeface("Tohoma"); 

        internal const double GridSize = 10; 
        internal Dictionary modelElement; 
        //Consider FlowStep.Action = SomeActivity. FlowStep modelItem is referred as FlowNodeMI, SomeActivity modelItem is shapeMI and the designer for SomeActivity is the shape on canvas.
        //To go from the FlowNodeMI to the shape on canvas, we can use the path: FlowNodeMI(FlowStep.Action)-> shapeMI (modelElement Dictionary)-> Actual UIElement shape 
        //However this path does not always work.  For instance in delete case: FlowStep.Action is set to null to update the ModelItem.Parents property on the shapeMI
        //flowNodeToUIElement dictionary is used to solve this problem.
        Dictionary flowNodeToUIElement;
 
        const double startSymbolTopMargin = 10.0;
        const string shapeLocation = "ShapeLocation"; 
        const string shapeSize = "ShapeSize"; 
        const string TrueConnectorViewStateKey = "TrueConnector";
        const string FalseConnectorViewStateKey = "FalseConnector"; 
        const string CaseViewStateKeyAppendString = "Connector";
        const string FlowSwitchDefaultViewStateKey = "Default";
        const string ConnectorViewStateKey = "ConnectorLocation";
        static Color ConnectionPointColor = Colors.LightGray; 
        UIElement lastConnectionPointMouseUpElement = null;
        //shapeLocations is useful to avoid pasting on existing shapes. 
        //This is populated in 2 cases 1. When the shape with existing Viewstate is added 2. On ViewState changed. 
        HashSet shapeLocations = null;
        //selectedConnector is a placeholder for the last connector selected. 
        //This removes the need for a dictionary mapping modelitem to connector for deletion.
        //This will change if in future we plan to support multi-select + delete.
        Connector selectedConnector;
        //srcConnectionPoint is required for link addition gesture to store the source of the link. 
        ConnectionPoint srcConnectionPoint;
        bool internalViewStateChange = false; 
        bool startNodeAdded = false; 
        internal FreeFormPanel panel = null;
        AdornerLayer adornerLayer; 
        MenuItem setAsStartNode;
        public FlowchartDesigner()
        {
            InitializeComponent(); 
            this.modelElement = new Dictionary();
            this.flowNodeToUIElement = new Dictionary(); 
            this.shapeLocations = new HashSet(); 
            this.selectedConnector = null;
            ConstructSetAsStartNodeMenuItem(); 

            this.Loaded += (s, e) =>
            {
                if (this.ShowExpanded) 
                {
                    ((ICompositeViewEvents)this).RegisterDefaultCompositeView(this); 
                } 
                DesignerView designerView = this.Context.Services.GetService() as DesignerView;
                if (!designerView.ContextMenu.Items.Contains(setAsStartNode)) 
                {
                    designerView.ContextMenu.Items.Add(setAsStartNode);
                }
 
                WorkflowCommandExtensionItem item = this.Context.Items.GetValue();
                if (item != null) 
                { 
                    if (item.CommandExtensionCallback is DefaultCommandExtensionCallback)
                    { 
                        this.InputBindings.Add(new KeyBinding(FlowchartDesignerCommands.ConnectNodesCommand, new DefaultCommandExtensionCallback.ChordKeyGesture(Key.E, Key.F)));
                    }
                }
            }; 

            this.Unloaded += (s, e) => 
            { 
                if (object.Equals(this.DefaultCompositeView, this))
                { 
                    ((ICompositeViewEvents)this).UnregisterDefaultCompositeView(this);
                }
                DesignerView designerView = this.Context.Services.GetService() as DesignerView;
                designerView.ContextMenu.Items.Remove(setAsStartNode); 
            };
        } 
 
        public static double FlowNodeCaptionFontSize
        { 
            get { return flowElementCaptionFontSize; }
        }

        public static FontFamily FlowNodeCaptionFontFamily 
        {
            get { return flowElementCaptionFontFamily; } 
        } 

        public static FontStyle FlowNodeCaptionFontStyle 
        {
            get { return flowElementCaptionFontStyle; }
        }
 
        public static Typeface FlowElementCaptionTypeface
        { 
            get { return flowElementCaptionTypeface; } 
        }
 
        void OnSetAsStartNodeCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //The condition is necessary so that the child flowchart inside a flowchart doesn't try to handle the event.
            if (!object.Equals(e.Source, this)) 
            {
                e.CanExecute = !this.IsReadOnly; 
                e.Handled = true; 
            }
        } 

        void OnSetAsStartNodeCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            ModelItem selection = this.Context.Items.GetValue().PrimarySelection; 
            Fx.Assert(this.modelElement.ContainsKey(selection), "Selection is not contained in this container");
            this.ModelItem.Properties["StartNode"].SetValue(this.GetFlowElementMI(selection)); 
            e.Handled = true; 
        }
 
        void ConstructSetAsStartNodeMenuItem()
        {
            setAsStartNode = new MenuItem();
            setAsStartNode.Command = FlowchartDesigner.SetAsStartNodeCommand; 
            setAsStartNode.Header = this.SetAsStartNodeMenuItemHeader;
            setAsStartNode.Visibility = Visibility.Collapsed; 
            setAsStartNode.Loaded += new RoutedEventHandler(OnSetAsStartNodeLoaded); 
            //AutomationProperties
            setAsStartNode.SetValue(System.Windows.Automation.AutomationProperties.AutomationIdProperty, "SetAsStartNodeMenuItem"); 
        }

        string SetAsStartNodeMenuItemHeader
        { 
            get { return (string)this.FindResource("SetAsStartNodeMenuItemHeader"); }
        } 
 
        void OnSetAsStartNodeLoaded(object sender, RoutedEventArgs e)
        { 
            MenuItem setAsStartNodeMenuItem = sender as MenuItem;
            setAsStartNodeMenuItem.Visibility = Visibility.Collapsed;
            Selection selection = this.Context.Items.GetValue();
            if (selection.SelectionCount == 1 && this.modelElement.ContainsKey(selection.PrimarySelection)) 
            {
                setAsStartNodeMenuItem.Visibility = Visibility.Visible; 
            } 
            e.Handled = true;
        } 

        public static void RegisterMetadata(AttributeTableBuilder builder)
        {
            Type type = typeof(Flowchart); 
            builder.AddCustomAttributes(type, new DesignerAttribute(typeof(FlowchartDesigner)));
            builder.AddCustomAttributes(type, type.GetProperty("StartNode"), BrowsableAttribute.No); 
            builder.AddCustomAttributes(type, type.GetProperty("Nodes"), BrowsableAttribute.No); 
            builder.AddCustomAttributes(type, type.GetProperty("Variables"), BrowsableAttribute.No);
            builder.AddCustomAttributes(type, new FeatureAttribute(typeof(FlowchartSizeFeature))); 

            type = typeof(FlowStep);
            builder.AddCustomAttributes(type, type.GetProperty("Action"), BrowsableAttribute.No);
            builder.AddCustomAttributes(type, type.GetProperty("Next"), BrowsableAttribute.No); 

            CutCopyPasteHelper.AddDisallowedTypeForCopy(typeof(FlowStart)); 
        } 

        //Unregister all events. Reset startNodeAdded to enable reuse of the designer. 
        void CleanupFlowchart()
        {
            this.startNodeAdded = false;
            this.panel.Children.Clear(); 
            this.flowNodeToUIElement.Clear();
            // Cleaning up the designers as they might be re-used. 
            foreach (UIElement element in this.modelElement.Values) 
            {
                element.MouseEnter -= new MouseEventHandler(ChildElement_MouseEnter); 
                element.MouseLeave -= new MouseEventHandler(ChildElement_MouseLeave);
            }
            this.panel.LocationChanged -= new LocationChangedEventHandler(OnFreeFormPanelLocationChanged);
            this.panel.ConnectorMoved -= new ConnectorMovedEventHandler(OnFreeFormPanelConnectorMoved); 
            this.panel.LayoutUpdated -= new EventHandler(OnFreeFormPanelLayoutUpdated);
            this.panel.RequiredSizeChanged -= new RequiredSizeChangedEventHandler(OnFreeFormPanelRequiredSizeChanged); 
            this.panel = null; 
            ModelTreeManager modelTreeManager = (this.ModelItem as IModelTreeItem).ModelTreeManager;
            modelTreeManager.EditingScopeCompleted -= new EventHandler(ModelTreeManager_EditingScopeCompleted); 
            this.ViewStateService.ViewStateChanged -= new ViewStateChangedEventHandler(OnViewStateChanged);
        }

        void OnFreeFormPanelLoaded(object sender, RoutedEventArgs eventArgs) 
        {
            //Adding the following check because of 137896: Inside tab control multiple Loaded events happen without an Unloaded event. 
            if(this.panel != null) 
            {
                CleanupFlowchart(); 
            }
            this.panel = (FreeFormPanel)sender;
            if (this.ShowExpanded)
            { 
                PopulateFlowchartChildren();
            } 
        } 

        void OnFreeFormPanelUnLoaded(object sender, RoutedEventArgs eventArgs) 
        {
            Fx.Assert(object.Equals(sender, this.panel), "Unknown panel unloaded");
            CleanupFlowchart();
        } 

 
        void PopulateFlowchartChildren() 
        {
            Fx.Assert(this.ShowExpanded, "This method should be called only when the flowchart designer is shown expanded."); 
            Fx.Assert(this.panel != null, "panel cannot be null");
            this.panel.LocationChanged += new LocationChangedEventHandler(OnFreeFormPanelLocationChanged);
            this.panel.ConnectorMoved += new ConnectorMovedEventHandler(OnFreeFormPanelConnectorMoved);
            this.panel.LayoutUpdated += new EventHandler(OnFreeFormPanelLayoutUpdated); 
            this.panel.RequiredSizeChanged += new RequiredSizeChangedEventHandler(OnFreeFormPanelRequiredSizeChanged);
 
            DesignerPerfEventProvider perfEventProvider = this.Context.Services.GetService(); 
            perfEventProvider.FlowchartDesignerLoadStart();
            ModelTreeManager modelTreeManager = (this.ModelItem as IModelTreeItem).ModelTreeManager; 
            modelTreeManager.EditingScopeCompleted += new EventHandler(ModelTreeManager_EditingScopeCompleted);
            this.ViewStateService.ViewStateChanged += new ViewStateChangedEventHandler(OnViewStateChanged);

            this.startNodeAdded = false; 
            panel.Children.Clear();
            this.modelElement.Clear(); 
            this.flowNodeToUIElement.Clear(); 
            this.shapeLocations.Clear();
 
            this.FlowchartWidth = (double)TypeDescriptor.GetProperties(this.ModelItem)[FlowchartSizeFeature.WidthPropertyName].GetValue(this.ModelItem);
            this.FlowchartHeight = (double)TypeDescriptor.GetProperties(this.ModelItem)[FlowchartSizeFeature.HeightPropertyName].GetValue(this.ModelItem);

            CreateStartSymbol(); 
            AddFlowElementsToDesigner(this.ModelItem.Properties["Nodes"].Collection);
            perfEventProvider.FlowchartDesignerLoadEnd(); 
        } 

        //This is to keep this.selectedConnector upto date. 
        //Eg. cases included 1. create a link, select it and undo, 2. Move a link from one shape to another.
        void OnFreeFormPanelLayoutUpdated(object sender, EventArgs e)
        {
            if (!this.panel.Children.Contains(this.selectedConnector)) 
            {
                this.selectedConnector = null; 
            } 
        }
 
        public UIElement StartSymbol { get; set; }

        internal static List GetConnectionPoints(DependencyObject obj)
        { 
            return (List)obj.GetValue(FlowchartDesigner.ConnectionPointsProperty);
        } 
 
        internal static ConnectionPoint GetFalseConnectionPoint(DependencyObject obj)
        { 
            return (ConnectionPoint)obj.GetValue(FlowchartDesigner.FalseConnectionPointProperty);
        }

        internal static ModelItem GetLinkModelItem(DependencyObject obj) 
        {
            return (ModelItem)obj.GetValue(FlowchartDesigner.LinkModelItemProperty); 
        } 

        internal static ModelItem GetFlowElementModelItem(DependencyObject obj) 
        {
            return (ModelItem)obj.GetValue(FlowchartDesigner.FlowElementModelItemProperty);
        }
 
        internal static ConnectionPoint GetTrueConnectionPoint(DependencyObject obj)
        { 
            return (ConnectionPoint)obj.GetValue(FlowchartDesigner.TrueConnectionPointProperty); 
        }
 
        public double FlowchartWidth
        {
            get { return (double)this.GetValue(FlowchartDesigner.FlowchartWidthProperty); }
            set { this.SetValue(FlowchartDesigner.FlowchartWidthProperty, value); } 
        }
 
        public double FlowchartHeight 
        {
            get { return (double)this.GetValue(FlowchartDesigner.FlowchartHeightProperty); } 
            set { this.SetValue(FlowchartDesigner.FlowchartHeightProperty, value); }
        }

        public bool ShowAllConditions 
        {
            get { return (bool)GetValue(ShowAllConditionsProperty); } 
            set { SetValue(ShowAllConditionsProperty, value); } 
        }
 
        ModelItem GetFlowElementMI(ModelItem shapeModelItem)
        {
            Fx.Assert(this.modelElement.ContainsKey(shapeModelItem), "The ModelItem does not exist.");
            UIElement element = this.modelElement[shapeModelItem]; 
            ModelItem flowElementMI = FlowchartDesigner.GetFlowElementModelItem(element);
            Fx.Assert(flowElementMI != null, "FlowNode dependency property not set."); 
            return flowElementMI; 
        }
 
        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
        } 

        //Returns actual link destination - Activity ModelItem in case of a FlowStep. 
        ModelItem GetCorrespondingElementOnCanvas(ModelItem model) 
        {
            ModelItem destModelItem = model; 
            if (typeof(FlowStep).IsAssignableFrom(model.ItemType)
                && model.Properties["Action"].Value != null)
            {
                destModelItem = model.Properties["Action"].Value; 
            }
            if (typeof(Flowchart) == model.ItemType) 
            { 
                destModelItem = flowStart;
            } 
            return destModelItem;
        }

        private void OnFlowchartGridMouseLeave(object sender, MouseEventArgs e) 
        {
            bool endLinkCreation = !IsVisualHit(sender as UIElement, sender as UIElement, e.GetPosition(sender as IInputElement)); 
            if (endLinkCreation) 
            {
                RemoveAdorner(this.panel, typeof(LinkCreationAdorner)); 
                this.srcConnectionPoint = null;
            }
        }
 
        private void OnFlowchartGridMouseMove(object sender, MouseEventArgs e)
        { 
            if (this.srcConnectionPoint != null) 
            {
                AutoScrollHelper.AutoScroll(e, this); 
                Point[] points = ConnectorRouter.Route(this.panel, this.srcConnectionPoint, e.GetPosition(this.panel));
                List segments = new List(points);
                //Remove the previous adorner.
                RemoveAdorner(this.panel, typeof(LinkCreationAdorner)); 
                //Add new adorner.
                AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.srcConnectionPoint.ParentDesigner); 
                Fx.Assert(adornerLayer != null, "Adorner Layer does not exist"); 
                LinkCreationAdorner newAdorner = new LinkCreationAdorner(this.panel, segments);
                adornerLayer.Add(newAdorner); 
                e.Handled = true;
            }

        } 

        private void OnFlowchartGridMouseUp(object sender, MouseButtonEventArgs e) 
        { 
            if (this.srcConnectionPoint != null)
            { 
                RemoveAdorner(this.panel, typeof(LinkCreationAdorner));
                this.srcConnectionPoint = null;
            }
        } 

 
        static void SetConnectionPoints(DependencyObject obj, List connectionPoints) 
        {
            obj.SetValue(FlowchartDesigner.ConnectionPointsProperty, connectionPoints); 
        }


        static void SetFalseConnectionPoint(DependencyObject obj, ConnectionPoint connectionPoint) 
        {
            obj.SetValue(FlowchartDesigner.FalseConnectionPointProperty, connectionPoint); 
        } 

        static void SetLinkModelItem(DependencyObject obj, ModelItem modelItem) 
        {
            obj.SetValue(FlowchartDesigner.LinkModelItemProperty, modelItem);
        }
 
        static void SetFlowElementModelItem(DependencyObject obj, ModelItem modelItem)
        { 
            obj.SetValue(FlowchartDesigner.FlowElementModelItemProperty, modelItem); 
        }
 
        static void SetTrueConnectionPoint(DependencyObject obj, ConnectionPoint connectionPoint)
        {
            obj.SetValue(FlowchartDesigner.TrueConnectionPointProperty, connectionPoint);
        } 

        void ChildElement_MouseEnter(object sender, MouseEventArgs e) 
        { 
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null");
            VirtualizedContainerService.VirtualizingContainer senderElement = sender as VirtualizedContainerService.VirtualizingContainer; 
            if ((senderElement != null || sender is FlowchartStart) && !this.IsReadOnly)
            {
                AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer((Visual)sender);
                Fx.Assert(adornerLayer != null, "Cannot get AdornerLayer."); 
                ConnectionPointsAdorner adorner = null;
                if (sender is FlowchartStart) 
                { 
                    adorner = new ConnectionPointsAdorner((UIElement)sender, ConnectionPointsToShow((UIElement)sender, this.ModelItem), false);
                } 
                else
                {
                    bool isSenderElementSelected = (((Selection)this.Context.Items.GetValue()).SelectedObjects as ICollection).Contains(senderElement.ModelItem);
                    adorner = new ConnectionPointsAdorner(senderElement, ConnectionPointsToShow(senderElement, senderElement.ModelItem), isSenderElementSelected); 
                }
                adornerLayer.Add(adorner); 
                adorner.MouseDown += new MouseButtonEventHandler(ConnectionPoint_MouseDown); 
                adorner.MouseUp += new MouseButtonEventHandler(ConnectionPoint_MouseUp);
                adorner.MouseLeave += new MouseEventHandler(ConnectionPoint_MouseLeave); 
            }
        }

 
        //This method returns which connection points should be shown on hover of a shape.
        List ConnectionPointsToShow(UIElement element, ModelItem model) 
        { 
            bool isInComingConnection = false;
 
            //This condition checks if it is an incoming connection.
            if (this.srcConnectionPoint != null || (this.panel.connectorEditor != null && this.panel.connectorEditor.IsConnectorEndBeingMoved))
            {
                isInComingConnection = true; 
            }
            List connectionPointsToShow = new List(); 
 
            if (GenericFlowSwitchHelper.IsGenericFlowSwitch(model.ItemType))
            { 
                connectionPointsToShow.AddRange(FlowchartDesigner.GetConnectionPoints(element));
            }
            else if (typeof(FlowDecision).IsAssignableFrom(model.ItemType))
            { 
                if (isInComingConnection)
                { 
                    connectionPointsToShow.AddRange(FlowchartDesigner.GetConnectionPoints(element)); 
                }
                else 
                {
                    connectionPointsToShow.Add(FlowchartDesigner.GetTrueConnectionPoint(element));
                    connectionPointsToShow.Add(FlowchartDesigner.GetFalseConnectionPoint(element));
                    List outGoingConnectors = GetOutGoingConnectors(element); 
                    if (this.panel.connectorEditor != null && this.panel.connectorEditor.IsConnectorStartBeingMoved)
                    { 
                        //If the start of an outgoing connector is moved, its not an outgoing connector any more. 
                        outGoingConnectors.Remove(this.panel.connectorEditor.Connector);
                    } 
                    //Do not show True/False connection point if a link already exists.
                    foreach (Connector connector in outGoingConnectors)
                    {
                        connectionPointsToShow.Remove(FreeFormPanel.GetSourceConnectionPoint(connector)); 
                    }
                } 
            } 
            else// Case where only one out going connector is allowed - Start and FlowStep.
            { 
                ConnectionPointType allowedType = ConnectionPointType.Default;
                bool isConnectionAllowed = false;
                if (isInComingConnection)
                { 
                    allowedType = ConnectionPointType.Incoming;
                    isConnectionAllowed = true; 
                } 
                else
                { 
                    List outGoingConnectors = GetOutGoingConnectors(element);
                    if (this.panel.connectorEditor != null && this.panel.connectorEditor.IsConnectorStartBeingMoved)
                    {
                        outGoingConnectors.Remove(this.panel.connectorEditor.Connector); 
                    }
                    //Outgoing Connection is allowed only if there are no outgoing connectors already. 
                    if (outGoingConnectors.Count == 0) 
                    {
                        allowedType = ConnectionPointType.Outgoing; 
                        isConnectionAllowed = true;
                    }
                }
 
                if (isConnectionAllowed)
                { 
                    foreach (ConnectionPoint connPoint in FlowchartDesigner.GetConnectionPoints(element)) 
                    {
                        if (connPoint.PointType == allowedType || connPoint.PointType == ConnectionPointType.Default) 
                        {
                            connectionPointsToShow.Add(connPoint);
                        }
                    } 
                }
            } 
            //Do not show the connection points of a selected connector. 
            if (this.selectedConnector != null)
            { 
                connectionPointsToShow.Remove(FreeFormPanel.GetSourceConnectionPoint(this.selectedConnector));
                connectionPointsToShow.Remove(FreeFormPanel.GetDestinationConnectionPoint(this.selectedConnector));
            }
            return connectionPointsToShow; 
        }
 
 
        void ChildElement_MouseLeave(object sender, MouseEventArgs e)
        { 
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null");
            bool removeConnectionPointsAdorner = true;
            if (Mouse.DirectlyOver != null)
            { 
                removeConnectionPointsAdorner = !typeof(ConnectionPointsAdorner).IsAssignableFrom(Mouse.DirectlyOver.GetType());
            } 
            if (removeConnectionPointsAdorner) 
            {
                RemoveAdorner(sender as UIElement, typeof(ConnectionPointsAdorner)); 
            }
        }

 
        void ChildSizeChanged(object sender, SizeChangedEventArgs e)
        { 
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null"); 
            VirtualizedContainerService.VirtualizingContainer container = sender as VirtualizedContainerService.VirtualizingContainer;
            if (container != null || sender is FlowchartStart) 
            {
                this.internalViewStateChange = true;
                //Initializing storageModelItem for the case of FlowchartStartNode.
                ModelItem storageModelItem = this.ModelItem; 
                if (container != null)
                { 
                    storageModelItem = GetFlowElementMI(container.ModelItem); 
                }
                this.ViewStateService.StoreViewState(storageModelItem, shapeSize, ((UIElement)sender).DesiredSize); 
                this.internalViewStateChange = false;
            }
        }
 
        void ConnectionPoint_MouseDown(object sender, MouseButtonEventArgs e)
        { 
            UIElement srcElement = ((Adorner)sender).AdornedElement as UIElement; 
            this.srcConnectionPoint = ConnectionPointHitTest(srcElement, e.GetPosition(this.panel));
            e.Handled = true; 
        }

        void ConnectionPoint_MouseLeave(object sender, MouseEventArgs e)
        { 
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null");
            UIElement adornedElement = ((Adorner)sender).AdornedElement as UIElement; 
            RemoveAdorner(adornedElement, typeof(ConnectionPointsAdorner)); 
        }
 

        void ConnectionPoint_MouseUp(object sender, MouseButtonEventArgs e)
        {
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null"); 
            UIElement dest = ((Adorner)sender).AdornedElement as UIElement;
            Fx.Assert(dest != null, "Adorned element is not a UIElement"); 
            if (this.srcConnectionPoint != null) 
            {
                ConnectionPoint destConnectionPoint = ConnectionPointHitTest(dest, e.GetPosition(this.panel)); 
                if (destConnectionPoint != null && !this.srcConnectionPoint.Equals(destConnectionPoint))
                {
                    string errorMessage = string.Empty;
                    if (!CreateLinkGesture(this.srcConnectionPoint, destConnectionPoint, out errorMessage, null) && !errorMessage.Equals(string.Empty)) 
                    {
                        ErrorReporting.ShowErrorMessage(errorMessage); 
                    } 
                }
                this.srcConnectionPoint = null; 
                RemoveAdorner(this.panel, typeof(LinkCreationAdorner));
            }
            else
            { 
                //This will cause the FreeFormPanel to handle the event and is useful while moving connection end points of a connector.
                lastConnectionPointMouseUpElement = dest; 
                dest.RaiseEvent(e); 
            }
        } 

        void OnFreeFormPanelRequiredSizeChanged(object sender, RequiredSizeChangedEventArgs e)
        {
            Dispatcher.BeginInvoke(() => 
            {
                if (e.NewRequiredSize.Width > this.FlowchartWidth) 
                { 
                    this.ViewStateService.StoreViewState(this.ModelItem, FlowchartSizeFeature.WidthPropertyName, e.NewRequiredSize.Width);
                } 
                if (e.NewRequiredSize.Height > this.FlowchartHeight)
                {
                    this.ViewStateService.StoreViewState(this.ModelItem, FlowchartSizeFeature.HeightPropertyName, e.NewRequiredSize.Height);
                } 
            });
        } 
 
        void OnFreeFormPanelLocationChanged(object sender, LocationChangedEventArgs e)
        { 
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null");
            Fx.Assert(sender is UIElement, "Sender should be of type UIElement");
            Connector movedConnector = sender as Connector;
            if (movedConnector != null) 
            {
                //ViewState is undoable only when a user gesture moves a connector. If the freeformpanel routes a connector, 
                //the change is not undoable. 
                bool isUndoableViewState = false;
                ModelItem linkModelItem = FlowchartDesigner.GetLinkModelItem(movedConnector); 
                ConnectionPoint source = FreeFormPanel.GetSourceConnectionPoint(movedConnector);
                string viewStateKey = GetConnectorViewStateKey(linkModelItem, source);
                ModelItem storageModelItem = GetConnectorViewStateStorageModelItem(linkModelItem);
                PointCollection existingVS = this.ViewStateService.RetrieveViewState(storageModelItem, viewStateKey) as PointCollection; 
                if (existingVS != null && existingVS.Count > 0 && movedConnector.Points.Count > 0
                    && existingVS[0].Equals(movedConnector.Points[0]) && existingVS[existingVS.Count - 1].Equals(movedConnector.Points[movedConnector.Points.Count - 1])) 
                { 
                    isUndoableViewState = true;
                } 
                StoreConnectorViewState(movedConnector, isUndoableViewState);
            }
            else
            { 
                //Save the location property of each shape on the CFx object for serialization and viewstate maintenance.
                //This is called only when a shape without viewstate is autolayed out by the freeform panel. 
                VirtualizedContainerService.VirtualizingContainer container = sender as VirtualizedContainerService.VirtualizingContainer; 
                if (container != null)
                { 
                    StoreShapeViewState(container, e.NewLocation);
                }
            }
        } 

 
        void UpdateFlowchartOnLinkVisualMoved(ConnectionPoint knownConnectionPoint, Point newPoint, Connector movedConnector, bool isSourceKnown) 
        {
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null"); 
            HitTestResult hitTestResult = VisualTreeHelper.HitTest(this.panel, newPoint);
            if (hitTestResult == null)
            {
                return; 
            }
            //Test if the last connectionPoint hit, is the new location for the connector. 
            UIElement newViewElement = null; 
            ConnectionPoint newConnectionPoint = null;
 
            //The case where the link is dropped on a connectionpoint.
            if (this.lastConnectionPointMouseUpElement != null)
            {
                newConnectionPoint = this.ConnectionPointHitTest(this.lastConnectionPointMouseUpElement, newPoint); 
                if (newConnectionPoint != null)
                { 
                    newViewElement = this.lastConnectionPointMouseUpElement; 
                }
            } 
            //The case where the link is dropped on a shape.
            if (newViewElement == null)
            {
                newViewElement = VisualTreeUtils.FindVisualAncestor(hitTestResult.VisualHit); 
                if (newViewElement == null)
                { 
                    newViewElement = VisualTreeUtils.FindVisualAncestor(hitTestResult.VisualHit); 
                }
            } 
            if (newViewElement != null)
            {
                if (this.panel.Children.Contains(newViewElement))
                { 
                    using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.FCLinkMove))
                    { 
                        //Delete the existing link and keep the caseKey 
                        IFlowSwitchLink oldCaseKey = this.DeleteLink(movedConnector);
 
                        //Create new link
                        bool linkCreated = false;
                        string errorMessage = string.Empty;
                        if (isSourceKnown) 
                        {
                            if (newConnectionPoint == null) 
                            { 
                                linkCreated = CreateLinkGesture(knownConnectionPoint, newViewElement, out errorMessage, true, oldCaseKey);
                            } 
                            else
                            {
                                linkCreated = CreateLinkGesture(knownConnectionPoint, newConnectionPoint, out errorMessage, true, oldCaseKey);
                            } 
                        }
                        else 
                        { 
                            //If the Link source is dropped onto itself, we need to set the isLinkValidDueToLinkMove flag.
                            bool isLinkValidDueToLinkMove = FreeFormPanel.GetSourceConnectionPoint(movedConnector).ParentDesigner.Equals(newViewElement); 
                            if (newConnectionPoint == null)
                            {
                                linkCreated = CreateLinkGesture(newViewElement, knownConnectionPoint, out errorMessage, isLinkValidDueToLinkMove, oldCaseKey);
                            } 
                            else
                            { 
                                linkCreated = CreateLinkGesture(newConnectionPoint, knownConnectionPoint, out errorMessage, isLinkValidDueToLinkMove, oldCaseKey); 
                            }
                        } 
                        if (!linkCreated)
                        {
                            if (!errorMessage.Equals(string.Empty))
                            { 
                                ErrorReporting.ShowErrorMessage(errorMessage);
                            } 
                            es.Revert(); 
                        }
                        else 
                        {
                            es.Complete();
                        }
                    } 
                }
            } 
        } 

        void OnFreeFormPanelConnectorMoved(object sender, ConnectorMovedEventArgs e) 
        {
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null");
            Connector movedConnector = sender as Connector;
            if (movedConnector != null) 
            {
                Fx.Assert(e.NewConnectorLocation.Count > 0, "Invalid connector editor"); 
                if (e.NewConnectorLocation[0].Equals(movedConnector.Points[0])) 
                {
                    //DestMoved 
                    ConnectionPoint srcConnPoint = FreeFormPanel.GetSourceConnectionPoint(movedConnector);
                    Point destPoint = e.NewConnectorLocation[e.NewConnectorLocation.Count - 1];
                    UpdateFlowchartOnLinkVisualMoved(srcConnPoint, destPoint, movedConnector, true);
                } 
                else
                { 
                    //srcMoved 
                    ConnectionPoint destConnPoint = FreeFormPanel.GetDestinationConnectionPoint(movedConnector);
                    UpdateFlowchartOnLinkVisualMoved(destConnPoint, e.NewConnectorLocation[0], movedConnector, false); 
                }
            }
        }
 

 
 

        MultiBinding GetConnectionPointBinding(FrameworkElement element, double widthFraction, double heightFraction) 
        {
            Fx.Assert(element != null, "FrameworkElement is null.");
            MultiBinding bindings = new MultiBinding();
            Binding sizeBinding = new Binding(); 
            sizeBinding.Source = element;
            sizeBinding.Path = new PropertyPath(FreeFormPanel.ChildSizeProperty); 
            Binding locationBinding = new Binding(); 
            locationBinding.Source = element;
            locationBinding.Path = new PropertyPath(FreeFormPanel.LocationProperty); 
            bindings.Bindings.Add(sizeBinding);
            bindings.Bindings.Add(locationBinding);
            bindings.Converter = new ConnectionPointConverter();
            bindings.ConverterParameter = new List { widthFraction, heightFraction, element.Margin }; 
            return bindings;
        } 
 

        Connector GetConnector(ModelItem linkModelItem, ConnectionPoint srcConnPoint, ConnectionPoint destConnPoint) 
        {
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null");
            Connector connector = new Connector();
            connector.FocusVisualStyle = null; 
            connector.Focusable = true;
            DesignerView.SetCommandMenuMode(connector, CommandMenuMode.NoCommandMenu); 
            SetConnectorLabel(connector, srcConnPoint, linkModelItem); 

            connector.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(OnConnectorGotKeyboardFocus); 
            connector.RequestBringIntoView += new RequestBringIntoViewEventHandler(OnConnectorRequestBringIntoView);
            connector.GotFocus += new RoutedEventHandler(OnConnectorGotFocus);
            connector.LostFocus += new RoutedEventHandler(OnConnectorLostFocus);
            SetConnectorSrcDestConnectionPoints(connector, srcConnPoint, destConnPoint); 
            FlowchartDesigner.SetLinkModelItem(connector, linkModelItem);
            connector.Unloaded += new RoutedEventHandler(OnConnectorUnloaded); 
            return connector; 
        }
 
        void SetConnectorLabel(Connector connector, ConnectionPoint srcConnPoint, ModelItem linkModelItem)
        {
            if (typeof(FlowDecision).IsAssignableFrom(linkModelItem.ItemType))
            { 
                if (FlowchartDesigner.GetTrueConnectionPoint(srcConnPoint.ParentDesigner).Equals(srcConnPoint))
                { 
                    BindingOperations.SetBinding(connector, Connector.LabelTextProperty, new Binding { Source = linkModelItem, Path = new PropertyPath("TrueLabel") }); 
                }
                else 
                {
                    BindingOperations.SetBinding(connector, Connector.LabelTextProperty, new Binding { Source = linkModelItem, Path = new PropertyPath("FalseLabel") });
                }
            } 
            else if (typeof(IFlowSwitchLink).IsAssignableFrom(linkModelItem.ItemType))
            { 
                IFlowSwitchLink flowSwitchLink = (IFlowSwitchLink)linkModelItem.GetCurrentValue(); 
                connector.SetBinding(Connector.LabelTextProperty,
                    new MultiBinding{ 
                        Converter = new FlowSwitchLinkMultiValueConverter(),
                        ConverterParameter = flowSwitchLink.CaseProperty.PropertyType,
                        Bindings =
                        { 
                            new Binding { Source = flowSwitchLink, Path = new PropertyPath(flowSwitchLink.CaseProperty) },
                            new Binding { Source = flowSwitchLink, Path = new PropertyPath(flowSwitchLink.IsDefaultCaseProperty) }, 
                        }, 
                    });
            } 
        }

        void OnConnectorUnloaded(object sender, RoutedEventArgs e)
        { 
            ModelItem primarySelection = this.Context.Items.GetValue().PrimarySelection;
            if (object.Equals(primarySelection, FlowchartDesigner.GetLinkModelItem(sender as DependencyObject))) 
            { 
                if (primarySelection != null)
                { 
                    Selection.Toggle(this.Context, primarySelection);
                }
            }
        } 

        //Marking e.Handled = true to avoid scrolling in large workflows to bring the 
        //area of a connector in the center of the view region. 
        //Area covered by a connector includes the region between 0,0 of the panel and the edges of the connector.
        void OnConnectorRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e) 
        {
            e.Handled = true;
        }
 

 
        //Returns a new connector if viewstate exists, null otherwise. 
        Connector GetConnectorViewState(UIElement source, UIElement dest, ModelItem linkModelItem, ConnectionPoint srcConnectionPoint)
        { 
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null");
            Connector connector = null;
            object connectorLocation = null;
            if (typeof(FlowDecision).IsAssignableFrom(linkModelItem.ItemType)) 
            {
                Fx.Assert(srcConnectionPoint != null, "Source connection point is null."); 
                if (srcConnectionPoint.Equals(FlowchartDesigner.GetTrueConnectionPoint(this.modelElement[linkModelItem]))) 
                {
                    connectorLocation = this.ViewStateService.RetrieveViewState(linkModelItem, TrueConnectorViewStateKey); 
                }
                else
                {
                    connectorLocation = this.ViewStateService.RetrieveViewState(linkModelItem, FalseConnectorViewStateKey); 
                }
            } 
            else if (typeof(IFlowSwitchLink).IsAssignableFrom(linkModelItem.ItemType)) 
            {
                string key = null; 
                IFlowSwitchLink link = (IFlowSwitchLink)linkModelItem.GetCurrentValue();
                if (link.IsDefaultCase)
                {
                    key = FlowSwitchDefaultViewStateKey; 
                }
                else 
                { 
                    key = link.CaseName + CaseViewStateKeyAppendString;
                } 
                //Transitioning from fake ModelItem world to real ModelItem world.
                ModelItem realFSModelItem = (this.ModelItem as IModelTreeItem).ModelTreeManager.WrapAsModelItem(null, link.ParentFlowSwitch);
                connectorLocation = this.ViewStateService.RetrieveViewState(realFSModelItem, key);
            } 
            else
            { 
                connectorLocation = this.ViewStateService.RetrieveViewState(linkModelItem, ConnectorViewStateKey); 
            }
            PointCollection locationPts = connectorLocation as PointCollection; 
            if (locationPts != null)
            {
                ConnectionPoint srcConnPoint, destConnPoint;
                srcConnPoint = ConnectionPointHitTest(source, locationPts[0]); 
                destConnPoint = ConnectionPointHitTest(dest, locationPts[locationPts.Count - 1]);
                //In Debug mode, the size of the designer changes due to the debug adorner(border). Because of this connection points will move and 
                //won't coincide with the viewstate. 
                //The following code path is added for the scenario where we reload the flowchart designer by navigating back and forth on breadcrumb
                //when one of the flowchart activities has the debug border. 
                //In this scenario we try to find the closest connection point from the end point stored in viewstate. If the distance between the two
                //is within the acceptable range, we will reuse the viewstate and avoid re-drawing the connector.
                if (this.IsReadOnly)
                { 
                    ConnectionPoint pt;
                    double dist; 
                    if (srcConnPoint == null) 
                    {
                        pt = FindClosestConnectionPoint(locationPts[0], FlowchartDesigner.GetConnectionPoints(source), out dist); 
                        if (pt != null && pt.PointType != ConnectionPointType.Incoming && dist <= DebugTimeMaxConnectorShapeDist)
                        {
                            srcConnPoint = pt;
                        } 
                    }
                    if (destConnPoint == null) 
                    { 
                        pt = FindClosestConnectionPoint(locationPts[locationPts.Count - 1], FlowchartDesigner.GetConnectionPoints(dest), out dist);
                        if (pt != null && pt.PointType != ConnectionPointType.Outgoing && dist <= DebugTimeMaxConnectorShapeDist) 
                        {
                            destConnPoint = pt;
                        }
                    } 
                }
                if (srcConnPoint != null && destConnPoint != null) 
                { 
                    connector = GetConnector(linkModelItem, srcConnPoint, destConnPoint);
                    connector.Points = locationPts; 
                }
            }
            return connector;
        } 

 
        //Marking e.Handled true for the case where a connector is clicked on. 
        //This is to prevent WorkflowViewElement class from making Flowchart as the current selection.
        void OnConnectorGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) 
        {
            e.Handled = true;
        }
 
        void OnConnectorLostFocus(object sender, RoutedEventArgs e)
        { 
            Connector clickedLine = e.Source as Connector; 

            if (this.panel != null && this.panel.connectorEditor != null && clickedLine.Equals(this.panel.connectorEditor.Connector)) 
            {
                this.panel.RemoveConnectorEditor();
            }
        } 

        void OnConnectorGotFocus(object sender, RoutedEventArgs e) 
        { 
            Connector clickedLine = e.Source as Connector;
            DesignerView designerView = this.Context.Services.GetService(); 

            if (!designerView.IsMultipleSelectionMode)
            {
 
                if (this.panel.connectorEditor == null || !clickedLine.Equals(this.panel.connectorEditor.Connector))
                { 
                    this.panel.RemoveConnectorEditor(); 
                    this.panel.connectorEditor = new ConnectorEditor(this.panel, clickedLine);
                } 

                if (this.panel.Children.Contains(clickedLine))
                {
                    ModelItem lineModelItem = FlowchartDesigner.GetLinkModelItem(clickedLine); 
                    Selection newSelection = new Selection();
                    // If the linkModelItem is FlowDecision or Flowchart, we don't want to add it to the selection 
                    if (IsLinkModelItemSelectable(lineModelItem)) 
                    {
                        newSelection = new Selection(lineModelItem); 
                    }
                    this.Context.Items.SetValue(newSelection);
                    this.selectedConnector = clickedLine;
                    e.Handled = true; 
                }
            } 
        } 

        //widthFraction, heightFraction determine location of connectionpoint on the shape. 
        ConnectionPoint CreateConnectionPoint(UIElement element, double widthFraction, double heightFraction, EdgeLocation location)
        {
            ConnectionPoint connectionPoint = new ConnectionPoint();
            connectionPoint.EdgeLocation = location; 
            connectionPoint.PointType = ConnectionPointType.Default;
            connectionPoint.ParentDesigner = element; 
            BindingOperations.SetBinding(connectionPoint, ConnectionPoint.LocationProperty, GetConnectionPointBinding(element as FrameworkElement, widthFraction, heightFraction)); 
            return connectionPoint;
        } 

        void PopulateConnectionPoints(UIElement element, ModelItem model)
        {
            element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
            List connectionPoints;
            if (model != null && 
                GenericFlowSwitchHelper.IsGenericFlowSwitch(model.ItemType)) 
            {
                connectionPoints = new List 
                    {
                        //Top edge
                        CreateConnectionPoint(element, 0.25, 0, EdgeLocation.Top),
                        CreateConnectionPoint(element, 0.5, 0, EdgeLocation.Top), 
                        CreateConnectionPoint(element, 0.75, 0, EdgeLocation.Top),
                        //Right edge 
                        CreateConnectionPoint(element, 1, 0.25, EdgeLocation.Right), 
                        CreateConnectionPoint(element, 1, 0.50, EdgeLocation.Right),
                        CreateConnectionPoint(element, 1, 0.75, EdgeLocation.Right), 
                        //Bottom edge
                        CreateConnectionPoint(element, 0.25, 1, EdgeLocation.Bottom),
                        CreateConnectionPoint(element, 0.5, 1, EdgeLocation.Bottom),
                        CreateConnectionPoint(element, 0.75, 1, EdgeLocation.Bottom), 
                        //Left edge
                        CreateConnectionPoint(element, 0, 0.25, EdgeLocation.Left), 
                        CreateConnectionPoint(element, 0, 0.50, EdgeLocation.Left), 
                        CreateConnectionPoint(element, 0, 0.75, EdgeLocation.Left),
                    }; 
            }
            else if (model != null && typeof(FlowDecision).IsAssignableFrom(model.ItemType))
            {
                ConnectionPoint trueConnectionPoint = CreateConnectionPoint(element, 0, 0.50, EdgeLocation.Left); 
                trueConnectionPoint.PointType = ConnectionPointType.Outgoing;
                FlowchartDesigner.SetTrueConnectionPoint(element, trueConnectionPoint); 
 
                ConnectionPoint falseConnectionPoint = CreateConnectionPoint(element, 1, 0.50, EdgeLocation.Right);
                falseConnectionPoint.PointType = ConnectionPointType.Outgoing; 
                FlowchartDesigner.SetFalseConnectionPoint(element, falseConnectionPoint);

                connectionPoints = new List
                    { 
                        //Top edge
                        CreateConnectionPoint(element, 0.25, 0, EdgeLocation.Top), 
                        CreateConnectionPoint(element, 0.5, 0, EdgeLocation.Top), 
                        CreateConnectionPoint(element, 0.75, 0, EdgeLocation.Top),
                        //Bottom edge 
                        CreateConnectionPoint(element, 0.5, 1, EdgeLocation.Bottom),
                    };
                connectionPoints.ForEach((point) => point.PointType = ConnectionPointType.Incoming);
            } 
            else
            { 
                //First adding top, right, bottom and left default connection points in that order on all shapes other than flowswitch. 
                //For shapes that do not need any of the points, we will remove that point explicitly.
                connectionPoints = new List 
                    {
                        CreateConnectionPoint(element, 0.5, 0, EdgeLocation.Top),
                        CreateConnectionPoint(element, 1, 0.5, EdgeLocation.Right),
                        CreateConnectionPoint(element, 0.5, 1, EdgeLocation.Bottom), 
                        CreateConnectionPoint(element, 0, 0.5, EdgeLocation.Left)
                    }; 
            } 

            if (model == null) // Start symbol: model = null 
            {
                foreach (ConnectionPoint connPoint in connectionPoints)
                {
                    connPoint.PointType = ConnectionPointType.Outgoing; 
                }
            } 
            FlowchartDesigner.SetConnectionPoints(element, connectionPoints); 
        }
 
        void SetFlowElementModelItem(UIElement view, ModelItem model)
        {
            ModelItem flowElementMI = model;
            if (flowElementMI != null && !typeof(FlowNode).IsAssignableFrom(flowElementMI.ItemType)) 
            {
                ModelItem flowStepMI = null; 
                //Select the right FlowStep ModelItem out of view.ModelItem.Parents. 
                foreach (ModelItem parentModelItem in flowElementMI.Parents)
                { 
                    if (typeof(FlowNode).IsAssignableFrom(parentModelItem.ItemType)
                        && this.ModelItem.Properties["Nodes"].Collection.Contains(parentModelItem))
                    {
                        flowStepMI = parentModelItem; 
                        break;
                    } 
                } 
                flowElementMI = flowStepMI;
            } 
            Fx.Assert(flowElementMI != null, "Non FlowNode present on Flowchart");
            FlowchartDesigner.SetFlowElementModelItem(view as DependencyObject, flowElementMI);
            this.flowNodeToUIElement[flowElementMI] = view;
 
        }
 
        UIElement ProcessAndGetModelView(ModelItem model) 
        {
            Fx.Assert(this.panel != null, "This code should not be hit if panel is null"); 
            UIElement container;
            if (!this.modelElement.TryGetValue(model, out container))
            {
                VirtualizedContainerService containerService = this.Context.Services.GetService(); 
                Fx.Assert(this.ViewService != null, "ViewService is null");
                container = containerService.GetContainer(model, this); 
                //WorkflowViewElement view = (WorkflowViewElement)this.ViewService.GetView(model); 
                //Fx.Assert(view != null, "View does not exist for a model Item");
                //DragDropHelper.SetSourceContainer(view, this); 
                //element = (UIElement)view;
                //element.MouseEnter += new MouseEventHandler(ChildElement_MouseEnter);
                //element.MouseLeave += new MouseEventHandler(ChildElement_MouseLeave);
                container.MouseEnter += new MouseEventHandler(ChildElement_MouseEnter); 
                container.MouseLeave += new MouseEventHandler(ChildElement_MouseLeave);
 
                ((FrameworkElement)container).SizeChanged += new SizeChangedEventHandler(ChildSizeChanged); 
                this.modelElement.Add(model, container);
                PopulateConnectionPoints(container, model); 
                this.SetFlowElementModelItem(container, model);

                //Getting the View state information.
                ModelItem flowElementMI = GetFlowElementMI(model); 
                object locationOfShape = this.ViewStateService.RetrieveViewState(flowElementMI, shapeLocation);
                object sizeOfShape = this.ViewStateService.RetrieveViewState(flowElementMI, shapeSize); 
                if (locationOfShape != null) 
                {
                    Point locationPt = (Point)locationOfShape; 
                    FreeFormPanel.SetLocation(container, locationPt);
                    this.shapeLocations.Add(locationPt);
                }
                if (sizeOfShape != null) 
                {
                    Size size = (Size)sizeOfShape; 
                    FreeFormPanel.SetChildSize(container, size); 
                    VirtualizedContainerService.VirtualizingContainer virtualizingContainer = container as VirtualizedContainerService.VirtualizingContainer;
                    if (virtualizingContainer != null) 
                    {
                        virtualizingContainer.MinWidth = size.Width;
                        virtualizingContainer.MinHeight = size.Height;
                    } 

                } 
            } 
            return container;
        } 

        void GetSrcDestConnectionPoints(UIElement source, UIElement dest, out ConnectionPoint srcConnPoint, out ConnectionPoint destConnPoint, out string errorMessage)
        {
            srcConnPoint = null; 
            destConnPoint = null;
            errorMessage = string.Empty; 
            VirtualizedContainerService.VirtualizingContainer sourceContainer = source as VirtualizedContainerService.VirtualizingContainer; 
            if (sourceContainer != null && typeof(FlowDecision).IsAssignableFrom(sourceContainer.ModelItem.ItemType))
            { 
                srcConnPoint = FindFlowDecisionSrcConnectionPoint(source, out errorMessage);
                if (srcConnPoint != null)
                {
                    destConnPoint = ClosestDestConnectionPoint(srcConnPoint, dest, out errorMessage); 
                }
            } 
            else 
            {
                List srcConnectionPoints = FlowchartDesigner.GetConnectionPoints(source); 
                List destConnectionPoints = FlowchartDesigner.GetConnectionPoints(dest);
                FindClosestConnectionPointPair(srcConnectionPoints, destConnectionPoints, out srcConnPoint, out destConnPoint);
            }
        } 

 
        //This returns the closest non-outgoing connectionPoint on dest. Return value will be different than sourceConnectionPoint. 
        ConnectionPoint ClosestDestConnectionPoint(ConnectionPoint sourceConnectionPoint, UIElement dest, out string errorMessage)
        { 
            ConnectionPoint destConnectionPoint = null;
            errorMessage = string.Empty;
            if (sourceConnectionPoint.PointType != ConnectionPointType.Incoming)
            { 
                destConnectionPoint = FindClosestConnectionPointNotOfType(sourceConnectionPoint, FlowchartDesigner.GetConnectionPoints(dest), ConnectionPointType.Outgoing);
            } 
            else 
            {
                errorMessage = SR.FCInvalidLink; 
            }
            return destConnectionPoint;

        } 

 
 
        //This returns the closest non-Incoming connectionPoint on source. Return value will be different than destConnectionPoint.
        ConnectionPoint ClosestSrcConnectionPoint(UIElement src, ConnectionPoint destConnectionPoint, out string errorMessage) 
        {
            ConnectionPoint srcConnectionPoint = null;
            errorMessage = string.Empty;
            if (destConnectionPoint.PointType != ConnectionPointType.Outgoing) 
            {
                VirtualizedContainerService.VirtualizingContainer srcContainer = src as VirtualizedContainerService.VirtualizingContainer; 
                if (srcContainer != null && typeof(FlowDecision).IsAssignableFrom(srcContainer.ModelItem.ItemType)) 
                {
                    srcConnectionPoint = FindFlowDecisionSrcConnectionPoint(src, out errorMessage); 
                }
                else
                {
                    srcConnectionPoint = FindClosestConnectionPointNotOfType(destConnectionPoint, FlowchartDesigner.GetConnectionPoints(src), ConnectionPointType.Incoming); 
                }
            } 
            else 
            {
                errorMessage = SR.FCInvalidLink; 
            }
            return srcConnectionPoint;
        }
 
        //Priority of selection: 1st true then false.
        ConnectionPoint FindFlowDecisionSrcConnectionPoint(UIElement decisionDesigner, out string errorMessage) 
        { 
            ConnectionPoint srcConnectionPoint = null;
            errorMessage = string.Empty; 
            ConnectionPoint trueConnPoint = FlowchartDesigner.GetTrueConnectionPoint(decisionDesigner);
            ConnectionPoint falseConnPoint = FlowchartDesigner.GetFalseConnectionPoint(decisionDesigner);
            if (trueConnPoint.AttachedConnectors.Count == 0)
            { 
                srcConnectionPoint = trueConnPoint;
            } 
            else if (falseConnPoint.AttachedConnectors.Count == 0) 
            {
                srcConnectionPoint = falseConnPoint; 
            }
            else
            {
                errorMessage = SR.FCFlowConditionLinksExist; 
            }
            return srcConnectionPoint; 
        } 

        void SetConnectorSrcDestConnectionPoints(Connector connector, ConnectionPoint srcConnectionPoint, ConnectionPoint destConnectionPoint) 
        {
            FreeFormPanel.SetSourceConnectionPoint(connector, srcConnectionPoint);
            FreeFormPanel.SetDestinationConnectionPoint(connector, destConnectionPoint);
            srcConnectionPoint.AttachedConnectors.Add(connector); 
            destConnectionPoint.AttachedConnectors.Add(connector);
        } 
 
        //Save the connector.Points property on the CFx object for serialization and viewstate maintenance.
        void StoreConnectorViewState(ModelItem linkModelItem, PointCollection viewState, ConnectionPoint srcConnPoint, bool isUndoableViewState) 
        {
            ModelItem storageModelItem = GetConnectorViewStateStorageModelItem(linkModelItem);
            string viewStateKey = GetConnectorViewStateKey(linkModelItem, srcConnPoint);
            StoreConnectorViewState(storageModelItem, viewStateKey, viewState, isUndoableViewState); 
        }
 
        void StoreConnectorViewState(ModelItem storageModelItem, string viewStateKey, PointCollection viewState, bool isUndoableViewState) 
        {
            if (isUndoableViewState) 
            {
                this.ViewStateService.StoreViewStateWithUndo(storageModelItem, viewStateKey, viewState);
            }
            else 
            {
                this.ViewStateService.StoreViewState(storageModelItem, viewStateKey, viewState); 
            } 
        }
 
        void StoreConnectorViewState(ModelItem linkModelItem, PointCollection viewState, ConnectionPoint srcConnPoint)
        {
            StoreConnectorViewState(linkModelItem, viewState, srcConnPoint, true);
        } 

        void StoreConnectorViewState(Connector connector, bool isUndoableViewState) 
        { 
            //This method will be called whenever the FreeFormPanel raises a location changed event on a connector.
            //Such location changed events are a result of changes already commited in the UI. Hence we do not want to react to such view state changes. 
            //Using internalViewStateChange flag for that purpose.
            this.internalViewStateChange = true;
            this.StoreConnectorViewState(FlowchartDesigner.GetLinkModelItem(connector), connector.Points, FreeFormPanel.GetSourceConnectionPoint(connector), isUndoableViewState);
            this.internalViewStateChange = false; 
        }
 
        string GetConnectorViewStateKey(ModelItem linkModelItem, ConnectionPoint srcConnPoint) 
        {
            string viewStateKey = ConnectorViewStateKey; 
            if ((typeof(FlowDecision).IsAssignableFrom(linkModelItem.ItemType)))
            {
                if (srcConnPoint.Equals(FlowchartDesigner.GetTrueConnectionPoint(this.modelElement[linkModelItem])))
                { 
                    viewStateKey = TrueConnectorViewStateKey;
                } 
                else 
                {
                    viewStateKey = FalseConnectorViewStateKey; 
                }
            }
            else if (typeof(IFlowSwitchLink).IsAssignableFrom(linkModelItem.ItemType))
            { 
                IFlowSwitchLink link = (IFlowSwitchLink)linkModelItem.GetCurrentValue();
                if (link.IsDefaultCase) 
                { 
                    viewStateKey = FlowSwitchDefaultViewStateKey;
                } 
                else
                {
                    viewStateKey = link.CaseName + CaseViewStateKeyAppendString;
                } 
            }
            return viewStateKey; 
        } 

        ModelItem GetConnectorViewStateStorageModelItem(ModelItem linkModelItem) 
        {
            ModelItem storageModelItem = linkModelItem;
            if (typeof(IFlowSwitchLink).IsAssignableFrom(linkModelItem.ItemType))
            { 
                IFlowSwitchLink link = (IFlowSwitchLink)linkModelItem.GetCurrentValue();
                //Getting FlowSwitch ModelItem since there is no CFx object for linkModelItem. 
                IModelTreeItem modelTreeItem = this.ModelItem as IModelTreeItem; 
                storageModelItem = modelTreeItem.ModelTreeManager.WrapAsModelItem(null, link.ParentFlowSwitch);
            } 
            return storageModelItem;
        }

 
        //Save the shape location on the CFx object for serialization and viewstate maintenance.
        void StoreShapeViewState(UIElement movedElement, Point newLocation) 
        { 
            ModelItem storageModelItem;
            if (movedElement is FlowchartStart) 
            {
                storageModelItem = this.ModelItem;
            }
            else 
            {
                ModelItem model = ((VirtualizedContainerService.VirtualizingContainer)movedElement).ModelItem; 
                storageModelItem = GetFlowElementMI(model); 
            }
            StoreShapeViewState(storageModelItem, newLocation); 
        }

        void StoreShapeViewState(ModelItem storageModelItem, Point newLocation)
        { 
            if (this.ViewStateService.RetrieveViewState(storageModelItem, shapeLocation) != null)
            { 
                this.ViewStateService.StoreViewStateWithUndo(storageModelItem, shapeLocation, newLocation); 
            }
            else 
            {
                this.ViewStateService.StoreViewState(storageModelItem, shapeLocation, newLocation);
            }
        } 

 
        void PerformInternalMove(UIElement movedElement, Point newPoint, Point shapeAnchorPoint) 
        {
            using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.FCLinkMove)) 
            {
                RemoveAdorner(movedElement, typeof(ConnectionPointsAdorner));
                Point shapeLocation = SnapVisualToGrid(movedElement, newPoint, shapeAnchorPoint);
                StoreShapeViewState(movedElement, shapeLocation); 
                RerouteAttachedConnectors(movedElement);
                es.Complete(); 
            } 
        }
 
        void RerouteAttachedConnectors(UIElement movedElement)
        {
            foreach (Connector connector in GetAttachedConnectors(movedElement))
            { 
                Reroute(connector, true);
            } 
        } 

        void Reroute(Connector connector, bool withUndo) 
        {
            ConnectionPoint source = FreeFormPanel.GetSourceConnectionPoint(connector);
            ConnectionPoint destination = FreeFormPanel.GetDestinationConnectionPoint(connector);
 
            //Nulling out the PointCollection so that it doesn't interfere in line routing.
            connector.Points = new PointCollection(); 
            PointCollection viewState = new PointCollection(ConnectorRouter.Route(this.panel, source, destination)); 
            StoreConnectorViewState(FlowchartDesigner.GetLinkModelItem(connector), viewState, source, withUndo);
        } 


        private void OnFlowchartGridDrop(object sender, DragEventArgs e)
        { 
            e.Effects = DragDropEffects.None;
            Object droppedObject = DragDropHelper.GetDroppedObject(this, e, Context); 
            //Marking the event as being handled. In whichever case we want to route the event, it will be unmarked explicitly. 
            e.Handled = true;
            if (droppedObject != null) 
            {
                ModelItem newFlowStepMI = null;
                Point anchorPoint = DragDropHelper.GetDragDropAnchorPoint(e);
                ModelItem droppedModelItem = droppedObject as ModelItem; 
                Object srcContainer = DragDropHelper.GetCompositeView(e);
                if (droppedModelItem != null && srcContainer != null && srcContainer.Equals(this)) 
                { 
                    //InternalMove
                    PerformInternalMove(modelElement[droppedModelItem], e.GetPosition(this.panel), anchorPoint); 
                }
                else
                {
                    //External model Item drop. 
                    if (droppedModelItem != null)
                    { 
                        if (typeof(Activity).IsAssignableFrom(droppedModelItem.ItemType) 
                            && !IsParentOf(droppedModelItem, this.ModelItem))
                        { 
                            FlowStep flowStep = new FlowStep();
                            flowStep.Action = (Activity)droppedModelItem.GetCurrentValue();
                            newFlowStepMI = this.ModelItem.Properties["Nodes"].Collection.Add(flowStep);
                        } 
                        else if (typeof(FlowNode).IsAssignableFrom(droppedModelItem.ItemType))
                        { 
                            this.ModelItem.Properties["Nodes"].Collection.Add(droppedModelItem); 
                        }
                        else 
                        {
                            //We want to route the event in the case that the flowchart is dropped upon itself.
                            if (droppedModelItem.Equals(this.ModelItem))
                            { 
                                e.Handled = false;
                            } 
                            //Don't add anything for what is neither a Activity nor a flowlink. 
                            droppedModelItem = null;
                        } 
                    }
                    //Tool box drop.
                    else
                    { 
                        if (typeof(Activity).IsAssignableFrom(droppedObject.GetType()))
                        { 
                            FlowStep flowStep = new FlowStep(); 
                            flowStep.Action = (Activity)droppedObject;
                            newFlowStepMI = this.ModelItem.Properties["Nodes"].Collection.Add(flowStep); 
                            droppedModelItem = newFlowStepMI.Properties["Action"].Value;
                        }
                        else if (typeof(FlowNode).IsAssignableFrom(droppedObject.GetType()))
                        { 
                            droppedModelItem = this.ModelItem.Properties["Nodes"].Collection.Add(droppedObject);
                        } 
                    } 
                    if (droppedModelItem != null)
                    { 
                        WorkflowViewElement view = droppedModelItem.View as WorkflowViewElement;
                        if (view == null || view.ExpandState)
                        {
                            //Creating a new view to get the size of collapsed view. 
                            view = this.ViewService.GetView(droppedModelItem) as WorkflowViewElement;
                            view.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
                        } 
                        //If drag anchor point is beyond the size of the shape being dropped,
                        //(can happen when an expanded shape is dropped into flowchart) then the drop point will coincide with the center of the shape. 
                        if (anchorPoint.X > view.DesiredSize.Width || anchorPoint.Y > view.DesiredSize.Height)
                        {
                            anchorPoint = new Point(-1, -1);
                        } 
                        if (view != null)
                        { 
                            Point shapeLocation = SnapVisualToGrid(view, e.GetPosition(this.panel), anchorPoint); 
                            this.StoreShapeViewState(newFlowStepMI != null ? newFlowStepMI : droppedModelItem, shapeLocation);
                        } 
                        DragDropHelper.SetDragDropCompletedEffects(e, DragDropEffects.Move);
                        this.Dispatcher.BeginInvoke(() =>
                        {
                            Selection.SelectOnly(this.Context, droppedModelItem); 
                            Keyboard.Focus((IInputElement)droppedModelItem.View);
                        } 
                            , DispatcherPriority.ApplicationIdle); 
                    }
                } 
            }
        }

 
        private void OnFlowchartGridDragEnter(object sender, DragEventArgs e)
        { 
            OnFlowchartGridDrag(sender, e); 
        }
 
        private void OnFlowchartGridDragOver(object sender, DragEventArgs e)
        {
            OnFlowchartGridDrag(sender, e);
        } 

        private void OnFlowchartGridDrag(object sender, DragEventArgs e) 
        { 
            if (!e.Handled)
            { 
                if (!DragDropHelper.AllowDrop(e.Data, this.Context, typeof(Activity), typeof(FlowNode), typeof(FlowStart)))
                {
                    e.Effects = DragDropEffects.None;
                } 
                e.Handled = true;
            } 
        } 

        static bool IsLinkModelItemSelectable(ModelItem linkModelItem) 
        {
            return linkModelItem != null &&
                // link from FlowDecision
                   !typeof(FlowDecision).IsAssignableFrom(linkModelItem.ItemType) && 
                // link from StartNode
                   !typeof(Flowchart).IsAssignableFrom(linkModelItem.ItemType); 
        } 

        private void OnFlowchartGridKeyDown(object sender, KeyEventArgs e) 
        {
            Selection currentSelection = this.Context.Items.GetValue();
            if (e.Key == Key.Delete && this.selectedConnector != null)
            { 
                ModelItem primarySelection = currentSelection.PrimarySelection;
                //Delete connector 
                ModelItem linkModelItem = FlowchartDesigner.GetLinkModelItem(this.selectedConnector); 
                if ((primarySelection == null && !IsLinkModelItemSelectable(linkModelItem)) ||
                    object.Equals(primarySelection, linkModelItem)) 
                {
                    DeleteLink(this.selectedConnector);
                    this.selectedConnector = null;
                    e.Handled = true; 
                }
            } 
            else if ((new List { Key.Left, Key.Right, Key.Up, Key.Down }).Contains(e.Key) 
                && currentSelection.SelectionCount == 1
                && this.modelElement.ContainsKey(currentSelection.PrimarySelection)) 
            {
                KeyboardMove(e.Key);
                e.Handled = true;
            } 
        }
 
        void KeyboardMove(Key key) 
        {
            UIElement shapeToMove = this.modelElement[this.Context.Items.GetValue().PrimarySelection]; 
            Point currentLocation = FreeFormPanel.GetLocation(shapeToMove);
            switch (key)
            {
                case Key.Down: 
                    PerformInternalMove(shapeToMove, new Point(currentLocation.X, currentLocation.Y + FlowchartDesigner.GridSize), new Point(0, 0));
                    break; 
                case Key.Up: 
                    PerformInternalMove(shapeToMove, new Point(currentLocation.X, currentLocation.Y - FlowchartDesigner.GridSize), new Point(0, 0));
                    break; 
                case Key.Right:
                    PerformInternalMove(shapeToMove, new Point(currentLocation.X + FlowchartDesigner.GridSize, currentLocation.Y), new Point(0, 0));
                    break;
                case Key.Left: 
                    PerformInternalMove(shapeToMove, new Point(currentLocation.X - FlowchartDesigner.GridSize, currentLocation.Y), new Point(0, 0));
                    break; 
                default: 
                    Fx.Assert(false, "Invalid case");
                    break; 
            }
        }

 
        private void OnFlowchartGridPreviewMouseDown(object sender, MouseButtonEventArgs e)
        { 
            this.selectedConnector = null; 
        }
 
        private void OnFlowchartGridPreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            if (this.srcConnectionPoint != null)
            { 
                UIElement destElement = VisualTreeUtils.FindVisualAncestor(e.OriginalSource as DependencyObject);
                if (destElement != null && this.panel.Children.Contains(destElement)) 
                { 
                    string errorMessage = string.Empty;
                    if (!CreateLinkGesture(this.srcConnectionPoint, destElement, out errorMessage, null) && !errorMessage.Equals(string.Empty)) 
                    {
                        ErrorReporting.ShowErrorMessage(errorMessage);
                    }
                    this.srcConnectionPoint = null; 
                    RemoveAdorner(this.panel, typeof(LinkCreationAdorner));
                } 
            } 
        }
 

        enum ConnectorType
        {
            Default = 0, ErrorConnector = 1 
        };
 
        void OnConnectNodesCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) 
        {
            e.CanExecute = false; 
            Selection selection = this.Context.Items.GetValue();
            if (selection.SelectionCount > 1)
            {
                e.CanExecute = true; 
                foreach (ModelItem item in selection.SelectedObjects)
                { 
                    if (!this.modelElement.ContainsKey(item)) 
                    {
                        e.CanExecute = false; 
                        break;
                    }
                }
            } 
            e.Handled = true;
        } 
 
        void OnConnectNodesCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        { 
            using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.FCCreateLink))
            {
                List selectedFlowchartItems = new List(this.Context.Items.GetValue().SelectedObjects);
                selectedFlowchartItems.Reverse(); 
                CreateLinks(selectedFlowchartItems);
                es.Complete(); 
            } 
        }
 
        void OnShowAllConditionsCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            this.ShowAllConditions = false;
            this.ShowAllConditions = true; 
        }
 
        void OnShowAllConditionsCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) 
        {
            e.CanExecute = true; 
            e.Handled = true;
        }

        void OnHideAllConditionsCommandExecuted(object sender, ExecutedRoutedEventArgs e) 
        {
            this.ShowAllConditions = true; 
            this.ShowAllConditions = false; 
        }
 
        void OnHideAllConditionsCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
            e.Handled = true; 
        }
 
        internal static void DropActivityBelow(ViewStateService viewStateService, ModelItem modelItem, Activity activity, double interval) 
        {
            // Extracting information 
            ModelItem flowStep = modelItem.Parent;
            ModelItemCollection nodes = flowStep.Parent as ModelItemCollection;
            ModelItem flowchart = nodes.Parent;
            FlowchartDesigner flowchartDesigner = ((FlowchartDesigner)flowchart.View); 

            // Creating FlowStep ModelItem 
            ModelTreeManager modelTreeManager = (modelItem as IModelTreeItem).ModelTreeManager; 
            FlowStep step = new FlowStep() { Action = activity };
            ModelItem activityModelItem = modelTreeManager.WrapAsModelItem(nodes, step); 

            // Compute the 'correct' location
            Point point = (Point)viewStateService.RetrieveViewState(flowStep, shapeLocation);
            point.Y += (((WorkflowViewElement)modelItem.View).ActualHeight + interval); 
            viewStateService.StoreViewState(activityModelItem, shapeLocation, point);
            flowchartDesigner.UpdateViewStateToAvoidOverlapOnPaste(new List { activityModelItem }); 
 
            // Add it to the model tree
            nodes.Add(activityModelItem); 
        }

        void OnAdornerDecoratorLoaded(object sender, RoutedEventArgs e)
        { 
            this.adornerLayer = ((AdornerDecorator)sender).AdornerLayer;
            // This might not be the best event to handle, ideally we would like to have the event when the list of adorner changes. 
            this.adornerLayer.LayoutUpdated += new EventHandler(OnAdornerLayerLayoutUpdated); 
        }
 
        void OnAdornerLayerLayoutUpdated(object sender, EventArgs e)
        {
            // Extract the set of all adorners
            List adornerList = new List(); 
            foreach (object logicalChild in LogicalTreeHelper.GetChildren(adornerLayer))
            { 
                Fx.Assert(logicalChild is Adorner, "What else could an adornerLayer hold?"); 
                adornerList.Add((Adorner)logicalChild);
            } 
            Adorner[] adorners = adornerList.ToArray();
            if (FlowchartDesigner.Pack(adorners, (adorner => adorner is FlowchartExpressionAdorner)))
            {
                foreach (Adorner adorner in adorners) 
                {
                    adornerLayer.Remove(adorner); 
                } 
                foreach (Adorner adorner in adorners)
                { 
                    adornerLayer.Add(adorner);
                }
            }
        } 

        sealed class LinkCreationAdorner : Adorner 
        { 
            List linkPoints;
            public LinkCreationAdorner(UIElement adornedElement, List linkPoints) 
                : base(adornedElement)
            {
                Fx.Assert(adornedElement != null, "adornedElement is null");
                this.IsHitTestVisible = false; 
                this.linkPoints = linkPoints;
            } 
 
            protected override void OnRender(DrawingContext drawingContext)
            { 
                SolidColorBrush renderBrush = new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementSelectedBorderColor);
                Pen renderPen = new Pen(renderBrush, FreeFormPanel.ConnectorEditorThickness);
                for (int i = 0; i < linkPoints.Count - 1; i++)
                { 
                    drawingContext.DrawLine(renderPen, linkPoints[i], linkPoints[i + 1]);
                } 
                base.OnRender(drawingContext); 
            }
        } 
    }

    sealed internal class ConnectionPointsAdorner : Adorner
    { 
        List connectionPoints;
        ConnectionPoint trueConnectionPoint = null; 
        ConnectionPoint falseConnectionPoint = null; 
        bool isParentShapeSelected = false;
        public ConnectionPointsAdorner(UIElement adornedElement, List connectionPointsToShow, bool isParentShapeSelected) 
            : base(adornedElement)
        {
            Fx.Assert(adornedElement != null, "adornedElement is null");
            this.IsHitTestVisible = true; 
            connectionPoints = connectionPointsToShow;
            this.isParentShapeSelected = isParentShapeSelected; 
        } 
        protected override void OnRender(DrawingContext drawingContext)
        { 
            SolidColorBrush renderBrush;
            Pen renderPen;
            if (this.isParentShapeSelected)
            { 
                renderBrush = new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementSelectedBackgroundColor);
                renderPen = new Pen(new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementSelectedBorderColor), 1.0); 
            } 
            else
            { 
                renderBrush = new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementBackgroundColor);
                renderPen = new Pen(new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementBorderColor), 1.0);
            }
 
            const int textCulture = 9;
 
            if (connectionPoints.Contains(FlowchartDesigner.GetTrueConnectionPoint(this.AdornedElement))) 
            {
                trueConnectionPoint = FlowchartDesigner.GetTrueConnectionPoint(this.AdornedElement); 
                connectionPoints.Remove(trueConnectionPoint);
            }
            if (connectionPoints.Contains(FlowchartDesigner.GetFalseConnectionPoint(this.AdornedElement)))
            { 
                falseConnectionPoint = FlowchartDesigner.GetFalseConnectionPoint(this.AdornedElement);
                connectionPoints.Remove(falseConnectionPoint); 
            } 

            Point actualPoint; 
            Point origin = FreeFormPanel.GetLocation(AdornedElement);
            Thickness margin = ((FrameworkElement)AdornedElement).Margin;
            origin.X += margin.Left;
            origin.Y += margin.Top; 

            foreach (ConnectionPoint connPoint in connectionPoints) 
            { 
                actualPoint = new Point(connPoint.Location.X - origin.X, connPoint.Location.Y - origin.Y);
                DrawConnectionPoint(connPoint, actualPoint, renderBrush, renderPen, drawingContext); 
            }
            if (trueConnectionPoint != null)
            {
                string trueLabelText = String.Empty; 

                VirtualizedContainerService.VirtualizingContainer virtualizingContainer = (VirtualizedContainerService.VirtualizingContainer)trueConnectionPoint.ParentDesigner; 
                if (virtualizingContainer != null && virtualizingContainer.ModelItem != null) 
                {
                    trueLabelText = (string)virtualizingContainer.ModelItem.Properties["TrueLabel"].ComputedValue; 
                }

                actualPoint = new Point(trueConnectionPoint.Location.X - origin.X, trueConnectionPoint.Location.Y - origin.Y);
                DrawConnectionPoint(trueConnectionPoint, actualPoint, renderBrush, renderPen, drawingContext); 
                FormattedText trueMarkerFormattedText = new FormattedText(trueLabelText, new System.Globalization.CultureInfo(textCulture),
                    FlowDirection.LeftToRight, FlowchartDesigner.FlowElementCaptionTypeface, FlowchartDesigner.FlowNodeCaptionFontSize, 
                    new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor)); 
                actualPoint.Y += ConnectionPoint.DrawingLargeSide / 2;
                actualPoint.X -= trueMarkerFormattedText.WidthIncludingTrailingWhitespace; 
                drawingContext.DrawText(trueMarkerFormattedText, actualPoint);
            }
            if (falseConnectionPoint != null)
            { 
                string falseLabelText = String.Empty;
 
                VirtualizedContainerService.VirtualizingContainer virtualizingContainer = (VirtualizedContainerService.VirtualizingContainer)falseConnectionPoint.ParentDesigner; 
                if (virtualizingContainer != null && virtualizingContainer.ModelItem != null)
                { 
                    falseLabelText = (string)virtualizingContainer.ModelItem.Properties["FalseLabel"].ComputedValue;
                }

                actualPoint = new Point(falseConnectionPoint.Location.X - origin.X, falseConnectionPoint.Location.Y - origin.Y); 
                DrawConnectionPoint(falseConnectionPoint, actualPoint, renderBrush, renderPen, drawingContext);
                actualPoint.Y += ConnectionPoint.DrawingLargeSide / 2; 
                drawingContext.DrawText(new FormattedText(falseLabelText, new System.Globalization.CultureInfo(textCulture), 
                    FlowDirection.LeftToRight, FlowchartDesigner.FlowElementCaptionTypeface, FlowchartDesigner.FlowNodeCaptionFontSize,
                    new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor)), actualPoint); 
            }
            base.OnRender(drawingContext);
        }
        protected override void OnMouseMove(MouseEventArgs e) 
        {
            base.OnMouseMove(e); 
            AdornedElement.RaiseEvent(e); 
        }
 
        void DrawConnectionPoint(ConnectionPoint connPoint, Point actualLocation, Brush renderBrush, Pen renderPen, DrawingContext drawingContext)
        {
            // actualLocation is the point on the Edge with respect to the coordinate system defined by the topLeft corner of the parentActivity
            // We will need this transparent rectangle to make sure OnMouseOver event can be triggered, for hit test. 
            drawingContext.DrawRectangle(Brushes.Transparent, new Pen(Brushes.Transparent, 0),
                new Rect(actualLocation + connPoint.HitTestOffset, connPoint.HitTestSize)); 
            drawingContext.DrawRectangle(renderBrush, renderPen, 
                new Rect(actualLocation + connPoint.DrawingOffset, connPoint.DrawingSize));
        } 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK