Connector CreateLink(ConnectionPoint sourceConnectionPoint, UIElement dest, ModelItem linkModelItem) { Connector newConnector = null; ConnectionPoint destConnectionPoint = null; if (this.srcConnectionPointForAutoConnect != null) { Fx.Assert(this.srcConnectionPointForAutoConnect == sourceConnectionPoint, "sourceConnectionPoint should equal to this.srcConnectionPointForAutoConnect"); destConnectionPoint = FlowchartDesigner.GetDestinationConnectionPointForAutoConnect(dest, sourceConnectionPoint); this.srcConnectionPointForAutoConnect = null; } else if (this.srcConnectionPointForAutoSplit == sourceConnectionPoint) { destConnectionPoint = this.GetDestinationConnectionPointForAutoSplit(this.srcConnectionPointForAutoSplit, dest); this.srcConnectionPointForAutoSplit = null; } else { string errorMessage; destConnectionPoint = FindBestMatchDestConnectionPoint(sourceConnectionPoint, dest, out errorMessage); } if (destConnectionPoint != null) { newConnector = CreateLink(sourceConnectionPoint, destConnectionPoint, linkModelItem); } return(newConnector); }
Connector CreateLink(UIElement source, UIElement dest, ModelItem linkModelItem) { Connector newConnector = null; ConnectionPoint srcConnPoint = null, destConnPoint = null; if (this.srcConnectionPointForAutoConnect != null) { srcConnPoint = this.srcConnectionPointForAutoConnect; destConnPoint = FlowchartDesigner.GetDestinationConnectionPointForAutoConnect(dest, srcConnPoint); this.srcConnectionPointForAutoConnect = null; } else if (this.srcConnectionPointForAutoSplit != null && this.srcConnectionPointForAutoSplit.ParentDesigner == source) { srcConnPoint = this.srcConnectionPointForAutoSplit; destConnPoint = this.GetDestinationConnectionPointForAutoSplit(srcConnPoint, dest); this.srcConnectionPointForAutoSplit = null; } else if (this.destConnectionPointForAutoSplit != null && this.destConnectionPointForAutoSplit.ParentDesigner == dest) { destConnPoint = this.destConnectionPointForAutoSplit; srcConnPoint = this.GetSourceConnectionPointForAutoSplit(destConnPoint, source); this.destConnectionPointForAutoSplit = null; } else { string errorMessage; GetSrcDestConnectionPoints(source, dest, out srcConnPoint, out destConnPoint, out errorMessage); } if (srcConnPoint != null && destConnPoint != null) { newConnector = CreateLink(srcConnPoint, destConnPoint, linkModelItem); } return(newConnector); }
static List <ConnectionPoint> GetAllConnectionPoints(UIElement shape) { List <ConnectionPoint> allConnectionPoints = new List <ConnectionPoint>(6); allConnectionPoints.AddRange(FlowchartDesigner.GetConnectionPoints(shape)); allConnectionPoints.Add(FlowchartDesigner.GetTrueConnectionPoint(shape)); allConnectionPoints.Add(FlowchartDesigner.GetFalseConnectionPoint(shape)); return(allConnectionPoints); }
void OnModelItemPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Expression") { Update(); } else if (e.PropertyName == "DefaultCaseDisplayName") { // To fix 218600 without losing PropertyGrid focus (Bug 210326), the only workaround is to // update the connector label manually, because FlowSwitchLink.ModelItem["DefaultCaseDisplayName"] // is a FakeModelPropertyImpl, and would not generate a Undo unit // (FakeModelNotifyPropertyChange.GetInverse() returns null). // However, there is a known issue with PropertyGrid bound to a fake ModelItem. The workaround is // to shift the focus to the FlowchartDesigner IF the keyboard focus is on the connector when the user // calls Undo/Redo, to avoid the problem of PropertyGrid not refreshable. FlowchartDesigner flowchartDesigner = VisualTreeUtils.FindVisualAncestor <FlowchartDesigner>(this); Fx.Assert(null != flowchartDesigner, "flowchart designer cannot be null because FlowswitchDesigner must exist within the same visual tree ofthe parent Flowchart."); if (null != flowchartDesigner && null != this.ModelItem.Properties["Default"].Value && this.Context.Services.GetService <UndoEngine>().IsUndoRedoInProgress) { // the designer is available Connector connector = flowchartDesigner.GetLinkOnCanvas(this.ModelItem, this.ModelItem.Properties["Default"].Value, "Default"); Fx.Assert(null != connector, "Connector should not be null."); ModelItem linkModelItem = FlowchartDesigner.GetLinkModelItem(connector); Fx.Assert(linkModelItem is FakeModelItemImpl, "ModelItem of FlowSwitch link is fake."); IFlowSwitchDefaultLink link = (IFlowSwitchDefaultLink)linkModelItem.GetCurrentValue(); string defaultDisplayName = (string)this.ModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].Value.GetCurrentValue(); if (link.DefaultCaseDisplayName != defaultDisplayName) { // the purpose of re-setting the link value during Undo/Redo is to update the FlowSwitch label using (ModelEditingScope scope = this.ModelItem.BeginEdit(SR.FlowSwitchDefaultCaseDisplayNameEditingScopeDesc)) { linkModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(defaultDisplayName); link.DefaultCaseDisplayName = defaultDisplayName; scope.Complete(); } if (Selection.IsSelection(linkModelItem)) { // cause the connector to lose focus, because the PropertyGrid would not have focus. // this scenario only happens if the user explicitly selects the FlowSwitch link after // editing the DefaultDisplayName. This behavior is only a workaround due to the fact // that PropertyGrid does not receive update from change in a FakeModelPropertyImpl // (i.e. FlowSwitchLink). Keyboard.ClearFocus(); Selection.SelectOnly(this.Context, this.ModelItem); linkModelItem.Highlight(); } } } } }
ConnectionPoint ConnectionPointHitTest(UIElement element, Point hitPoint) { List <ConnectionPoint> connectionPoints = new List <ConnectionPoint>(); List <ConnectionPoint> defaultConnectionPoints = FlowchartDesigner.GetConnectionPoints(element); connectionPoints.InsertRange(0, defaultConnectionPoints); connectionPoints.Add(FlowchartDesigner.GetTrueConnectionPoint(element)); connectionPoints.Add(FlowchartDesigner.GetFalseConnectionPoint(element)); return(FreeFormPanel.ConnectionPointHitTest(hitPoint, connectionPoints, this.panel)); }
Connector CreatePropertyLink(ModelItem srcModelItem, ModelItem propertyValue, string propertyName) { Connector newConnector = null; if (typeof(FlowStep).IsAssignableFrom(srcModelItem.ItemType)) { ModelItem src = GetCorrespondingElementOnCanvas(srcModelItem); ModelItem dest = GetCorrespondingElementOnCanvas(propertyValue); newConnector = CreateLink(modelElement[src], modelElement[dest], srcModelItem); } else if (typeof(FlowDecision).IsAssignableFrom(srcModelItem.ItemType)) { ModelItem dest = GetCorrespondingElementOnCanvas(propertyValue); ConnectionPoint srcConnPoint; if (propertyName.Equals("True")) { srcConnPoint = FlowchartDesigner.GetTrueConnectionPoint(modelElement[srcModelItem]); } else { srcConnPoint = FlowchartDesigner.GetFalseConnectionPoint(modelElement[srcModelItem]); } newConnector = CreateLink(srcConnPoint, modelElement[dest], srcModelItem); } else if (GenericFlowSwitchHelper.IsGenericFlowSwitch(srcModelItem.ItemType)) { ModelItem dest = GetCorrespondingElementOnCanvas(propertyValue); IFlowSwitchLink link; if (propertyName.Equals("Default")) { link = GenericFlowSwitchHelper.CreateFlowSwitchLink(srcModelItem.ItemType, srcModelItem, null, true); } else { Fx.Assert(propertyName.Length >= GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier.Length, "Case property names should be prepended by the string GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier"); link = GenericFlowSwitchHelper.CreateFlowSwitchLink(srcModelItem.ItemType, srcModelItem, propertyName.Substring(GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier.Length), false); } IModelTreeItem modelTreeItem = (IModelTreeItem)this.ModelItem; ModelItem linkModelItem = new FakeModelItemImpl(modelTreeItem.ModelTreeManager, link.GetType(), link, null); link.ModelItem = linkModelItem; newConnector = CreateLink(modelElement[srcModelItem], modelElement[dest], linkModelItem); } else // FlowStart { ModelItem dest = GetCorrespondingElementOnCanvas(propertyValue); newConnector = CreateLink(this.StartSymbol, modelElement[dest], this.ModelItem); } return(newConnector); }
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) { if (!this.Disabled) { FlowchartDesigner flowchartDesigner = this.ParentFlowchartDesigner; ModelItem flowchartModelItem = this.ParentFlowchartDesigner.ModelItem; using (ModelEditingScope scope = flowchartModelItem.BeginEdit(SR.FCResizeUndoUnitName)) { TypeDescriptor.GetProperties(flowchartModelItem)[FlowchartSizeFeature.WidthPropertyName].SetValue(flowchartModelItem, flowchartDesigner.FlowchartWidth); TypeDescriptor.GetProperties(flowchartModelItem)[FlowchartSizeFeature.HeightPropertyName].SetValue(flowchartModelItem, flowchartDesigner.FlowchartHeight); scope.Complete(); } Mouse.OverrideCursor = null; Mouse.Capture(null); ParentFlowchartDesigner.IsResizing = false; e.Handled = true; } base.OnPreviewMouseLeftButtonUp(e); }
protected override void OnMouseMove(MouseEventArgs args) { base.OnMouseMove(args); if (!this.Disabled) { if (args.LeftButton == MouseButtonState.Pressed && this.IsMouseCaptured) { FlowchartDesigner flowchartDesigner = this.ParentFlowchartDesigner; FreeFormPanel panel = flowchartDesigner.panel; Grid flowchartGrid = this.ParentGrid; Point currentPosition = Mouse.GetPosition(flowchartGrid); currentPosition.Offset(this.offset.X, this.offset.Y); flowchartDesigner.FlowchartWidth = Math.Min(Math.Max(panel.RequiredWidth, currentPosition.X), flowchartGrid.MaxWidth); flowchartDesigner.FlowchartHeight = Math.Min(Math.Max(panel.RequiredHeight, currentPosition.Y), flowchartGrid.MaxHeight); args.Handled = true; } } }
void RefreshFlowSwitchLinkModelItem(ModelItem flowSwitchModelItem, Connector connector, bool isDefault) { ModelItem oldLinkModelItem = FlowchartDesigner.GetLinkModelItem(connector); IModelTreeItem modelTreeItem = flowSwitchModelItem as IModelTreeItem; IFlowSwitchLink link = GenericFlowSwitchHelper.CreateFlowSwitchLink(flowSwitchModelItem.ItemType, flowSwitchModelItem, ((IFlowSwitchLink)oldLinkModelItem.GetCurrentValue()).CaseObject, isDefault); ModelItem linkModelItem = new FakeModelItemImpl(modelTreeItem.ModelTreeManager, link.GetType(), link, null); link.ModelItem = linkModelItem; FlowchartDesigner.SetLinkModelItem(connector, linkModelItem); connector.SetBinding(Connector.LabelTextProperty, link.CreateConnectorLabelTextBinding()); Selection currentSelection = this.Context.Items.GetValue <Selection>(); if (currentSelection.SelectedObjects.Contains(oldLinkModelItem)) { Selection.Toggle(this.Context, oldLinkModelItem); Selection.Select(this.Context, linkModelItem); } }
/// <summary> /// for connection: /// 1. return all free connection points are available on the object /// 2. return any existing points that are already connected on the object, excluding the unmatched type. /// Fallback: return all connection points of the given object /// </summary> /// <param name="sourceConnectionPoint"></param> /// <param name="dest"></param> /// <param name="errorMessage"></param> /// <returns></returns> ConnectionPoint FindBestMatchDestConnectionPoint(ConnectionPoint sourceConnectionPoint, UIElement dest, out string errorMessage) { List <ConnectionPoint> destConnPoints = FlowchartDesigner.GetConnectionPoints(dest); Fx.Assert(null != destConnPoints && destConnPoints.Any(), "A flownode designer object should have one connection point."); errorMessage = string.Empty; if (sourceConnectionPoint.PointType == ConnectionPointKind.Incoming) { errorMessage = SR.FCInvalidLink; return(null); } ConnectionPoint destConnectionPoint; double minDist; List <ConnectionPoint> candidateDestConnPoints = FindCandidatePointsForLink(destConnPoints, ConnectionPointKind.Outgoing); destConnectionPoint = FindClosestConnectionPoint(sourceConnectionPoint, candidateDestConnPoints, out minDist); return(destConnectionPoint); }
internal bool CreateLinkGesture(UIElement source, ConnectionPoint destConnectionPoint, Point mouseLocation, out string errorMessage, bool isLinkValidDueToLinkMove, IFlowSwitchLink caseKey) { bool linkCreated = false; double minDist; errorMessage = string.Empty; ConnectionPoint sourceConnectionPoint = FindClosestConnectionPoint( mouseLocation, FlowchartDesigner.GetConnectionPoints(source).Where(p => p.PointType != ConnectionPointKind.Incoming).ToList(), out minDist); if (sourceConnectionPoint != null) { linkCreated = CreateLinkGesture(sourceConnectionPoint, destConnectionPoint, out errorMessage, isLinkValidDueToLinkMove, caseKey); } else { errorMessage = SR.FCInvalidLink; } return(linkCreated); }
private IFlowSwitchLink DeleteLinkImpl(Connector link, bool isMoveOrAutoSplit = false, HashSet <ModelItem> referenceUpdatedModelItems = null) { IFlowSwitchLink caseKey = null; ModelItem linkModelItem = FlowchartDesigner.GetLinkModelItem(link); if (referenceUpdatedModelItems != null && referenceUpdatedModelItems.Contains(linkModelItem)) { return(caseKey); } ConnectionPoint srcConnectionPoint = FreeFormPanel.GetSourceConnectionPoint(link); ConnectionPoint destConnectionPoint = FreeFormPanel.GetDestinationConnectionPoint(link); if (typeof(FlowStep).IsAssignableFrom(linkModelItem.ItemType)) { linkModelItem.Properties["Next"].SetValue(null); } else if (typeof(FlowDecision).IsAssignableFrom(linkModelItem.ItemType)) { //Determine if it is True or False branch. if (srcConnectionPoint.Equals(FlowchartDesigner.GetTrueConnectionPoint(srcConnectionPoint.ParentDesigner))) { //True branch linkModelItem.Properties["True"].SetValue(null); } else { linkModelItem.Properties["False"].SetValue(null); } } else if (typeof(IFlowSwitchLink).IsAssignableFrom(linkModelItem.ItemType)) { IFlowSwitchLink flowSwitchLink = (IFlowSwitchLink)linkModelItem.GetCurrentValue(); caseKey = flowSwitchLink; //Transitioning from the fakeModelItem world to the real ModelItem world. FlowNode fs = flowSwitchLink.ParentFlowSwitch; ModelItem realFlowSwitchMI = (this.ModelItem as IModelTreeItem).ModelTreeManager.WrapAsModelItem(fs); if (referenceUpdatedModelItems != null && referenceUpdatedModelItems.Contains(realFlowSwitchMI)) { return(caseKey); } if (flowSwitchLink.IsDefaultCase) { realFlowSwitchMI.Properties["Default"].SetValue(null); if (!isMoveOrAutoSplit) { realFlowSwitchMI.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(FlowSwitchLabelFeature.DefaultCaseDisplayNameDefaultValue); } } else { GenericFlowSwitchHelper.RemoveCase(realFlowSwitchMI.Properties["Cases"], flowSwitchLink.CaseObject); } } else // StartNode { this.ModelItem.Properties["StartNode"].SetValue(null); } this.StoreConnectorViewState(linkModelItem, null, srcConnectionPoint, true); return(caseKey); }
//For flowchart reacting to ModelItem changes we are concerned of the following scenarios: //1. FlowElements being deleted from the Flowchart.Nodes collection or Flowswitch cases being deleted from ItemsCollection //2. FlowElements being added to the Flowchart.Nodes collection or Flowswitch cases being added from ItemsCollection //3. Properties being changed in FlowStep(Next), FlowDecision(True, false), FlowSwitch(Default) (Any of the flowelemnet should be present in the elements collection). //4. Flowswitch cases being added/remove via Cases.Dicitionary void ModelTreeManager_EditingScopeCompleted(object sender, EditingScopeEventArgs e) { Fx.Assert(this.panel != null, "This code should not be hit if panel is null"); foreach (Change change in e.EditingScope.Changes) { //Case 1, 2. if (change is CollectionChange) { CollectionChange collectionChange = change as CollectionChange; if (collectionChange.Collection.Equals(this.ModelItem.Properties["Nodes"].Collection)) { if (collectionChange.Operation == CollectionChange.OperationType.Delete) { this.DeleteShapeVisual(this.flowNodeToUIElement[collectionChange.Item]); } else { this.AddFlowElementsToDesigner(new List <ModelItem> { collectionChange.Item }); //An editing scope change references the ModelItem. //Hence in case of multiple changes to the same modelItem within the same EditingScope, we will see all the changes on the ModelItem for each change. //Eg. Suppose following two changes are in the same editing scope: 1. Add ModelItem item1 to Collection, 2. Change a property on this MI, item1.Prop1 //In this case, EditingScope.Changes.Count will be 2. //Since an EditingScope change keeps a reference to the ModelItem changed, when we process the first change, the second change would already be reflected on the ModelItem. //Hence, while processing CollectionChange for item1, item1.Prop1 will already reflect the new value. //Also there will be another change notifying the change in item1.Prop1. //AddFlowElementsToDesigner() method, walks through the properties of a newly added item and creates any links if required. //This is necessary for Paste scenario where we want to create links between Items added to the Nodes Collection. //Because of this behavior of AddFlowElementsToDesigner(), before reacting to a property change for adding a link, we will always verify that the link does not already exists. } } if (collectionChange.Collection.Parent != null && collectionChange.Collection.Parent.Parent != null && this.ModelItem.Properties["Nodes"].Collection.Contains(collectionChange.Collection.Parent.Parent) && collectionChange.Collection.Parent.Parent.ItemType.IsGenericType && collectionChange.Collection.Parent.Parent.ItemType.GetGenericTypeDefinition() == typeof(FlowSwitch <>)) { ModelItem item = collectionChange.Item; string caseName = GenericFlowSwitchHelper.GetString(item.Properties["Key"].ComputedValue, item.Properties["Key"].PropertyType); Connector connector = this.GetLinkOnCanvas(collectionChange.Collection.Parent.Parent, item.Properties["Value"].Value, GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier + caseName); if (collectionChange.Operation == CollectionChange.OperationType.Delete) { if (connector != null) { this.DeleteLinkVisual(connector); } } else if (collectionChange.Operation == CollectionChange.OperationType.Insert) { if (connector == null) { //Prepending GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier to differentiate between the FlowSwitch's Property Default and key Default. connector = this.CreatePropertyLink(collectionChange.Collection.Parent.Parent, item.Properties["Value"].Value, GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier + caseName); Fx.Assert(connector != null, "Link not created"); this.panel.Children.Add(connector); } else { RefreshFlowSwitchLinkModelItem(/* flowSwitchModelItem = */ collectionChange.Collection.Parent.Parent, connector, false); } } } } else if (change is DictionaryChange) { // case 4 DictionaryChange dictionaryChange = change as DictionaryChange; if (dictionaryChange.Dictionary.Parent != null && this.ModelItem.Properties["Nodes"].Collection.Contains(dictionaryChange.Dictionary.Parent) && dictionaryChange.Dictionary.Parent.ItemType.IsGenericType && dictionaryChange.Dictionary.Parent.ItemType.GetGenericTypeDefinition() == typeof(FlowSwitch <>)) { ModelItem flowSwitchModelItem = dictionaryChange.Dictionary.Parent; ModelItem caseTargetModelItem = dictionaryChange.Value; string caseName = GenericFlowSwitchHelper.GetString(dictionaryChange.Key == null ? null : dictionaryChange.Key.GetCurrentValue(), dictionaryChange.Key == null ? null : dictionaryChange.Key.ItemType); string caseNameInModelItem = GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier + caseName; Connector connector = this.GetLinkOnCanvas( flowSwitchModelItem, caseTargetModelItem, caseNameInModelItem); if (dictionaryChange.Operation == DictionaryChange.OperationType.Delete) { if (connector != null) { this.DeleteLinkVisual(connector); } } else if (dictionaryChange.Operation == DictionaryChange.OperationType.Insert) { if (connector == null) { connector = this.CreatePropertyLink( flowSwitchModelItem, caseTargetModelItem, caseNameInModelItem); this.panel.Children.Add(connector); } } } } //Case 3. else if (change is PropertyChange) { PropertyChange propertyChange = change as PropertyChange; if (this.ModelItem.Properties["Nodes"].Collection.Contains(propertyChange.Owner) || (propertyChange.PropertyName == "StartNode" && propertyChange.Owner == this.ModelItem)) { if (propertyChange.OldValue != null && IsFlowNode(propertyChange.OldValue)) { Connector link = GetLinkOnCanvas(propertyChange.Owner, propertyChange.OldValue, propertyChange.PropertyName); //Debug.Assert(link != null, "Link not found on designer"); if (link != null) { this.DeleteLinkVisual(link); } } if (propertyChange.NewValue != null && IsFlowNode(propertyChange.NewValue)) { Connector oldLink = GetLinkOnCanvas(propertyChange.Owner, propertyChange.NewValue, propertyChange.PropertyName); //If this connector has already been added don't add again. if (oldLink == null) { Connector link = CreatePropertyLink(propertyChange.Owner, propertyChange.NewValue, propertyChange.PropertyName); Fx.Assert(link != null, "Link not created"); this.panel.Children.Add(link); } else { if (GenericFlowSwitchHelper.IsGenericFlowSwitch(propertyChange.Owner.ItemType)) { this.RefreshFlowSwitchLinkModelItem(/* flowSwitchModelItem = */ propertyChange.Owner, oldLink, true); } } } //handling for the case where the FlowStep.Action changes: //Explicitly adding a check for FlowStep, because other FlowNodes have properties of type Activity, which we don't want to react to. //AddFlowElementsToDesigner() will add the links originating out of the shape that is changing. //We have to take care of refreshing the links coming into the shape that is changing. if (typeof(FlowStep).IsAssignableFrom(propertyChange.Owner.ItemType)) { List <Connector> oldIncomingConnectors = new List <Connector>(); if (propertyChange.OldValue != null && IsFlowStepAction(propertyChange.OldValue)) { UIElement oldShape = this.flowNodeToUIElement[propertyChange.Owner]; oldIncomingConnectors = this.GetInComingConnectors(oldShape); this.DeleteShapeVisual(oldShape); } if (propertyChange.NewValue != null && IsFlowStepAction(propertyChange.NewValue)) { this.AddFlowElementsToDesigner(new List <ModelItem> { propertyChange.Owner }); foreach (Connector oldConnector in oldIncomingConnectors) { Connector newConnector = CreateLink(FreeFormPanel.GetSourceConnectionPoint(oldConnector), this.flowNodeToUIElement[propertyChange.Owner], FlowchartDesigner.GetLinkModelItem(oldConnector)); this.panel.Children.Add(newConnector); } } } } } } }
internal Connector GetLinkOnCanvas(ModelItem srcFlowElementModelItem, ModelItem destflowElementModelItem, string propertyName) { Connector linkOnCanvas = null; ModelItem shapeModelItem = null; List <Connector> outGoingConnectors = null; if (!srcFlowElementModelItem.Equals(this.ModelItem)) { shapeModelItem = this.GetCorrespondingElementOnCanvas(srcFlowElementModelItem); outGoingConnectors = GetOutGoingConnectors(this.modelElement[shapeModelItem]); } else // Must be startNode { outGoingConnectors = GetOutGoingConnectors(this.StartSymbol); } foreach (Connector connector in outGoingConnectors) { ModelItem connectorDestModelItem = ((VirtualizedContainerService.VirtualizingContainer)FreeFormPanel.GetDestinationConnectionPoint(connector).ParentDesigner).ModelItem; ModelItem connectorDestFlowElementMI = this.GetFlowElementMI(connectorDestModelItem); //Following condition checks if the destination for current connector is equal to the destination passed in. if (destflowElementModelItem != null && destflowElementModelItem.Equals(connectorDestFlowElementMI)) { if (GenericFlowSwitchHelper.IsGenericFlowSwitch(srcFlowElementModelItem.ItemType)) { ModelItem linkModelItem = FlowchartDesigner.GetLinkModelItem(connector); if (linkModelItem.Properties["IsDefaultCase"].Value.GetCurrentValue().Equals(true) && propertyName.Equals("Default")) { linkOnCanvas = connector; break; } else { ModelItem connectorCaseMI = linkModelItem.Properties["Case"].Value; if (linkModelItem.Properties["IsDefaultCase"].Value.GetCurrentValue().Equals(false)) { string caseName = connectorCaseMI == null ? null : GenericFlowSwitchHelper.GetString(connectorCaseMI.GetCurrentValue(), connectorCaseMI.ItemType); if (connectorCaseMI != null && caseName.Equals(propertyName.Substring(GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier.Length))) { linkOnCanvas = connector; break; } else if (connectorCaseMI == null) { if (GenericFlowSwitchHelper.FlowSwitchNullCaseKeyIdentifier.Equals(propertyName.Substring(GenericFlowSwitchHelper.FlowSwitchCasesKeyIdentifier.Length))) { linkOnCanvas = connector; break; } } } } } else if (typeof(FlowDecision).IsAssignableFrom(srcFlowElementModelItem.ItemType)) { ConnectionPoint trueConnPoint = FlowchartDesigner.GetTrueConnectionPoint(this.modelElement[shapeModelItem]); ConnectionPoint falseConnPoint = FlowchartDesigner.GetFalseConnectionPoint(this.modelElement[shapeModelItem]); ConnectionPoint connectorSrcConnPoint = FreeFormPanel.GetSourceConnectionPoint(connector); if ((propertyName.Equals("True") && connectorSrcConnPoint.Equals(trueConnPoint)) || (propertyName.Equals("False") && connectorSrcConnPoint.Equals(falseConnPoint))) { linkOnCanvas = connector; break; } } else //FlowStep case. { linkOnCanvas = connector; break; } } } return(linkOnCanvas); }
void AddFlowElementsToDesigner(IList <ModelItem> flowElementMICollection, bool addConnectorAfterLoaded = false) { Queue <ModelItem> flowElementsToProcess = new Queue <ModelItem>(); List <UIElement> viewsAdded = new List <UIElement>(); foreach (ModelItem model in flowElementMICollection) { ModelItem itemOnCanvas = GetCorrespondingElementOnCanvas(model); if (!this.modelElement.ContainsKey(itemOnCanvas)) { flowElementsToProcess.Enqueue(model); viewsAdded.Add(ProcessAndGetModelView(itemOnCanvas)); } else if (!this.panel.Children.Contains(this.modelElement[itemOnCanvas])) { flowElementsToProcess.Enqueue(model); viewsAdded.Add(this.modelElement[itemOnCanvas]); } } ModelItem startNodeModelItem = null; List <Tuple <UIElement, UIElement, ModelItem> > elem2elemConnections = new List <Tuple <UIElement, UIElement, ModelItem> >(); List <Tuple <ConnectionPoint, UIElement, ModelItem> > point2elemConnections = new List <Tuple <ConnectionPoint, UIElement, ModelItem> >(); while (flowElementsToProcess.Count > 0) { ModelItem currentMI = flowElementsToProcess.Dequeue(); //Create links for the current FlowNode. //First of all check if this is connected to the start node. if (this.ModelItem.Properties["StartNode"].Value != null && this.ModelItem.Properties["StartNode"].Value.Equals(currentMI)) { startNodeModelItem = currentMI; } if (typeof(FlowStep).IsAssignableFrom(currentMI.ItemType)) { ModelItem linkDest = currentMI.Properties["Next"].Value; if (linkDest != null) { ModelItem src = GetCorrespondingElementOnCanvas(currentMI); ModelItem dest = GetCorrespondingElementOnCanvas(linkDest); if (!modelElement.ContainsKey(dest)) { viewsAdded.Add(ProcessAndGetModelView(dest)); flowElementsToProcess.Enqueue(linkDest); } elem2elemConnections.Add(Tuple.Create(modelElement[src], modelElement[dest], currentMI)); } } else if (typeof(FlowDecision).IsAssignableFrom(currentMI.ItemType)) { ModelItem trueDest = currentMI.Properties["True"].Value; ModelItem falseDest = currentMI.Properties["False"].Value; if (trueDest != null) { ConnectionPoint srcConnectionPoint = FlowchartDesigner.GetTrueConnectionPoint(modelElement[currentMI]); ModelItem trueDestOnCanvas = GetCorrespondingElementOnCanvas(trueDest); if (!modelElement.ContainsKey(trueDestOnCanvas)) { viewsAdded.Add(ProcessAndGetModelView(trueDestOnCanvas)); flowElementsToProcess.Enqueue(trueDest); } point2elemConnections.Add(Tuple.Create(srcConnectionPoint, modelElement[trueDestOnCanvas], currentMI)); } if (falseDest != null) { ConnectionPoint srcConnectionPoint = FlowchartDesigner.GetFalseConnectionPoint(modelElement[currentMI]); ModelItem falseDestOnCanvas = GetCorrespondingElementOnCanvas(falseDest); if (!modelElement.ContainsKey(falseDestOnCanvas)) { viewsAdded.Add(ProcessAndGetModelView(falseDestOnCanvas)); flowElementsToProcess.Enqueue(falseDest); } point2elemConnections.Add(Tuple.Create(srcConnectionPoint, modelElement[falseDestOnCanvas], currentMI)); } } else if (GenericFlowSwitchHelper.IsGenericFlowSwitch(currentMI.ItemType)) { IModelTreeItem modelTreeItem = this.ModelItem as IModelTreeItem; ModelItem defaultCase = currentMI.Properties["Default"].Value; if (defaultCase != null) { ModelItem defaultCaseOnCanvas = GetCorrespondingElementOnCanvas(defaultCase); if (!modelElement.ContainsKey(defaultCaseOnCanvas)) { viewsAdded.Add(ProcessAndGetModelView(defaultCaseOnCanvas)); flowElementsToProcess.Enqueue(defaultCase); } IFlowSwitchLink link = GenericFlowSwitchHelper.CreateFlowSwitchLink(currentMI.ItemType, currentMI, null, true); ModelItem linkModelItem = new FakeModelItemImpl(modelTreeItem.ModelTreeManager, link.GetType(), link, null); link.ModelItem = linkModelItem; elem2elemConnections.Add(Tuple.Create(modelElement[currentMI], modelElement[defaultCaseOnCanvas], linkModelItem)); } Type genericType = currentMI.ItemType.GetGenericArguments()[0]; foreach (ModelItem key in GenericFlowSwitchHelper.GetCaseKeys(currentMI.Properties["Cases"])) { ModelItem destFlowElementMI = GenericFlowSwitchHelper.GetCaseModelItem(currentMI.Properties["Cases"], (key == null) ? null : key.GetCurrentValue()); IFlowSwitchLink link = GenericFlowSwitchHelper.CreateFlowSwitchLink(currentMI.ItemType, currentMI, (key == null) ? null : key.GetCurrentValue(), false); ModelItem linkModelItem = new FakeModelItemImpl(modelTreeItem.ModelTreeManager, link.GetType(), link, null); link.ModelItem = linkModelItem; ModelItem destModelItem = GetCorrespondingElementOnCanvas(destFlowElementMI); if (!modelElement.ContainsKey(destModelItem)) { viewsAdded.Add(ProcessAndGetModelView(destModelItem)); flowElementsToProcess.Enqueue(destFlowElementMI); } elem2elemConnections.Add(Tuple.Create(modelElement[currentMI], modelElement[destModelItem], linkModelItem)); } } else { Fx.Assert(false, "Unknown type of FlowNode"); } } if (!this.startNodeAdded) { panel.Children.Add(this.StartSymbol); this.startNodeAdded = true; } foreach (UIElement view in viewsAdded) { panel.Children.Add(view); } // connection between flownode should be create only after all flownodes have been loaded on the canvas if (addConnectorAfterLoaded) { this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => { if (this.isLoaded) { AddConnectorsToPanel(startNodeModelItem, elem2elemConnections, point2elemConnections); } })); } else { AddConnectorsToPanel(startNodeModelItem, elem2elemConnections, point2elemConnections); } }
protected override void OnRender(DrawingContext drawingContext) { const int textCulture = 9; ConnectionPoint trueConnectionPoint = null; ConnectionPoint falseConnectionPoint = null; if (this.connectionPoints.Contains(FlowchartDesigner.GetTrueConnectionPoint(this.AdornedElement))) { trueConnectionPoint = FlowchartDesigner.GetTrueConnectionPoint(this.AdornedElement); } if (this.connectionPoints.Contains(FlowchartDesigner.GetFalseConnectionPoint(this.AdornedElement))) { falseConnectionPoint = FlowchartDesigner.GetFalseConnectionPoint(this.AdornedElement); } Point actualPoint; Point origin = FreeFormPanel.GetLocation(AdornedElement); Thickness margin = ((FrameworkElement)AdornedElement).Margin; origin.X += margin.Left; origin.Y += margin.Top; foreach (ConnectionPoint connPoint in this.connectionPoints) { actualPoint = new Point(connPoint.Location.X - origin.X, connPoint.Location.Y - origin.Y); this.DrawConnectionPoint(connPoint, actualPoint, 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); FormattedText trueMarkerFormattedText = new FormattedText(trueLabelText, new System.Globalization.CultureInfo(textCulture), this.FlowDirection, FlowchartDesigner.FlowElementCaptionTypeface, FlowchartDesigner.FlowNodeCaptionFontSize, new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor)); actualPoint.Y += ConnectionPoint.DrawingLargeSide / 2; actualPoint.X -= trueMarkerFormattedText.WidthIncludingTrailingWhitespace; DrawtWithTransform( drawingContext, this.isTextRightToLeft, // Mirror the left side text to the right side by using this axis when RTL. actualPoint.X, () => { 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); actualPoint.Y += ConnectionPoint.DrawingLargeSide / 2; FormattedText falseMarkerFormattedText = new FormattedText(falseLabelText, new System.Globalization.CultureInfo(textCulture), this.FlowDirection, FlowchartDesigner.FlowElementCaptionTypeface, FlowchartDesigner.FlowNodeCaptionFontSize, new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor)); DrawtWithTransform( drawingContext, this.isTextRightToLeft, // Mirror the left side text to the right side by using this axis when RTL. actualPoint.X, () => { drawingContext.DrawText(falseMarkerFormattedText, actualPoint); }); } base.OnRender(drawingContext); }
// Called by the designer to register any design-time metadata. // // Be aware of the accidential performance impact when adding things into this method. // In particular, pay attention to calls that will lead to loading extra assemblies. // public void Register() { AttributeTableBuilder builder = new AttributeTableBuilder(); //shared component builder.AddCustomAttributes(typeof(Collection <Constraint>), new BrowsableAttribute(false)); builder.AddCustomAttributes(typeof(string), new EditorReuseAttribute(false)); builder.AddCustomAttributes(typeof(ActivityAction), new EditorReuseAttribute(false)); builder.AddCustomAttributes(typeof(XName), new EditorReuseAttribute(false)); //Flowchart activities FlowchartDesigner.RegisterMetadata(builder); FlowSwitchDesigner.RegisterMetadata(builder); FlowDecisionDesigner.RegisterMetadata(builder); // Messaging activities ServiceDesigner.RegisterMetadata(builder); // Registering inline for designers for InitializeCorrelation, Send, Receive, SendReply, ReceiveReply activities to avoid calling // their static constructors. This will avoid instantiating the ResourceDictionary for their PropertyValueEditors during designer load. builder.AddCustomAttributes(typeof(Send), new DesignerAttribute(typeof(SendDesigner))); builder.AddCustomAttributes(typeof(Send), new ActivityDesignerOptionsAttribute { AllowDrillIn = false }); builder.AddCustomAttributes(typeof(Receive), new DesignerAttribute(typeof(ReceiveDesigner))); builder.AddCustomAttributes(typeof(Receive), new ActivityDesignerOptionsAttribute { AllowDrillIn = false }); builder.AddCustomAttributes(typeof(SendReply), new FeatureAttribute(typeof(SendReplyValidationFeature))); builder.AddCustomAttributes(typeof(SendReply), new DesignerAttribute(typeof(SendReplyDesigner))); builder.AddCustomAttributes(typeof(SendReply), new ActivityDesignerOptionsAttribute { AllowDrillIn = false }); CutCopyPasteHelper.AddDisallowedTypeForCopy(typeof(SendReply)); builder.AddCustomAttributes(typeof(ReceiveReply), new FeatureAttribute(typeof(ReceiveReplyValidationFeature))); builder.AddCustomAttributes(typeof(ReceiveReply), new DesignerAttribute(typeof(ReceiveReplyDesigner))); builder.AddCustomAttributes(typeof(ReceiveReply), new ActivityDesignerOptionsAttribute { AllowDrillIn = false }); CutCopyPasteHelper.AddDisallowedTypeForCopy(typeof(ReceiveReply)); builder.AddCustomAttributes(typeof(InitializeCorrelation), new DesignerAttribute(typeof(InitializeCorrelationDesigner))); builder.AddCustomAttributes(typeof(InitializeCorrelation), new ActivityDesignerOptionsAttribute { AllowDrillIn = false }); TransactedReceiveScopeDesigner.RegisterMetadata(builder); CorrelationScopeDesigner.RegisterMetadata(builder); //Procedural activities AssignDesigner.RegisterMetadata(builder); IfElseDesigner.RegisterMetadata(builder); InvokeMethodDesigner.RegisterMetadata(builder); DoWhileDesigner.RegisterMetadata(builder); WhileDesigner.RegisterMetadata(builder); ForEachDesigner.RegisterMetadata(builder); TryCatchDesigner.RegisterMetadata(builder); CatchDesigner.RegisterMetadata(builder); ParallelDesigner.RegisterMetadata(builder); SequenceDesigner.RegisterMetadata(builder); SwitchDesigner.RegisterMetadata(builder); CaseDesigner.RegisterMetadata(builder); //Compensation/Transaction CancellationScopeDesigner.RegisterMetadata(builder); CompensableActivityDesigner.RegisterMetadata(builder); TransactionScopeDesigner.RegisterMetadata(builder); //Misc activities PickDesigner.RegisterMetadata(builder); PickBranchDesigner.RegisterMetadata(builder); WriteLineDesigner.RegisterMetadata(builder); NoPersistScopeDesigner.RegisterMetadata(builder); InvokeDelegateDesigner.RegisterMetadata(builder); // StateMachine StateMachineDesigner.RegisterMetadata(builder); StateDesigner.RegisterMetadata(builder); TransitionDesigner.RegisterMetadata(builder); builder.AddCustomAttributes(typeof(AddToCollection <>), new FeatureAttribute(typeof(UpdatableGenericArgumentsFeature))); builder.AddCustomAttributes(typeof(RemoveFromCollection <>), new FeatureAttribute(typeof(UpdatableGenericArgumentsFeature))); builder.AddCustomAttributes(typeof(ClearCollection <>), new FeatureAttribute(typeof(UpdatableGenericArgumentsFeature))); builder.AddCustomAttributes(typeof(ExistsInCollection <>), new FeatureAttribute(typeof(UpdatableGenericArgumentsFeature))); builder.AddCustomAttributes(typeof(AddToCollection <>), new DefaultTypeArgumentAttribute(typeof(int))); builder.AddCustomAttributes(typeof(RemoveFromCollection <>), new DefaultTypeArgumentAttribute(typeof(int))); builder.AddCustomAttributes(typeof(ClearCollection <>), new DefaultTypeArgumentAttribute(typeof(int))); builder.AddCustomAttributes(typeof(ExistsInCollection <>), new DefaultTypeArgumentAttribute(typeof(int))); MetadataStore.AddAttributeTable(builder.CreateTable()); MorphHelper.AddPropertyValueMorphHelper(typeof(InArgument <>), MorphHelpers.ArgumentMorphHelper); MorphHelper.AddPropertyValueMorphHelper(typeof(OutArgument <>), MorphHelpers.ArgumentMorphHelper); MorphHelper.AddPropertyValueMorphHelper(typeof(InOutArgument <>), MorphHelpers.ArgumentMorphHelper); MorphHelper.AddPropertyValueMorphHelper(typeof(ActivityAction <>), MorphHelpers.ActivityActionMorphHelper); MorphHelper.AddPropertyValueMorphHelper(typeof(ActivityFunc <,>), MorphHelpers.ActivityFuncMorphHelper); // There is no need to keep an reference to this delayed worker since the AppDomain event handler will do it. RegisterMetadataDelayedWorker delayedWorker = new RegisterMetadataDelayedWorker(); delayedWorker.RegisterMetadataDelayed("System.Workflow.Runtime", InteropDesigner.RegisterMetadata); delayedWorker.RegisterMetadataDelayed("System.ServiceModel", RegisterMetadataForMessagingActivitiesSearchMetadata); delayedWorker.RegisterMetadataDelayed("System.ServiceModel", RegisterMetadataForMessagingActivitiesPropertyEditors); delayedWorker.WorkNowIfApplicable(); }
bool UpdateFlowChartObject(ConnectionPoint sourceConnPoint, ConnectionPoint destConnPoint, out string errorMessage, bool isLinkValidDueToLinkMove, IFlowSwitchLink caseKey) { //srcDesigner will be null for the case where source designer is StartSymbol. VirtualizedContainerService.VirtualizingContainer srcDesigner = sourceConnPoint.ParentDesigner as VirtualizedContainerService.VirtualizingContainer; VirtualizedContainerService.VirtualizingContainer destDesigner = destConnPoint.ParentDesigner as VirtualizedContainerService.VirtualizingContainer; ModelItem linkSource; ModelItem linkDest = destDesigner.ModelItem; ModelItem destFlowElementMI = GetFlowElementMI(linkDest); PointCollection connectorViewState = new PointCollection(ConnectorRouter.Route(this.panel, sourceConnPoint, destConnPoint)); errorMessage = string.Empty; if (sourceConnPoint.ParentDesigner is StartSymbol) { linkSource = this.ModelItem; if (linkSource.Properties["StartNode"].Value == null || isLinkValidDueToLinkMove) { this.StoreConnectorViewState(linkSource, connectorViewState, sourceConnPoint); linkSource.Properties["StartNode"].SetValue(destFlowElementMI); } else { errorMessage = SR.FCNextLinkDefined; } } else { linkSource = srcDesigner.ModelItem; ModelItem srcFlowElementMI = GetFlowElementMI(linkSource); if (typeof(FlowStep).IsAssignableFrom(srcFlowElementMI.ItemType)) { if (srcFlowElementMI.Properties["Next"].Value == null || isLinkValidDueToLinkMove) { this.StoreConnectorViewState(srcFlowElementMI, connectorViewState, sourceConnPoint); srcFlowElementMI.Properties["Next"].SetValue(destFlowElementMI); } else { errorMessage = SR.FCNextLinkDefined; } } else if (typeof(FlowDecision).IsAssignableFrom(srcFlowElementMI.ItemType)) { if (sourceConnPoint.Equals(FlowchartDesigner.GetTrueConnectionPoint(this.modelElement[linkSource]))) { if (linkSource.Properties["True"].Value == null || isLinkValidDueToLinkMove) { this.StoreConnectorViewState(srcFlowElementMI, connectorViewState, sourceConnPoint); linkSource.Properties["True"].SetValue(destFlowElementMI); } else { errorMessage = SR.FCTrueBranchExists; } } else if (sourceConnPoint.Equals(FlowchartDesigner.GetFalseConnectionPoint(this.modelElement[linkSource]))) { if (linkSource.Properties["False"].Value == null || isLinkValidDueToLinkMove) { this.StoreConnectorViewState(srcFlowElementMI, connectorViewState, sourceConnPoint); linkSource.Properties["False"].SetValue(destFlowElementMI); } else { errorMessage = SR.FCFalseBranchExists; } } else { errorMessage = SR.FCFlowConditionLinkError; } } else //FlowSwitch { if (!CreateFlowSwitchLink(sourceConnPoint, srcFlowElementMI, destFlowElementMI, caseKey, connectorViewState, ref errorMessage)) { return(false); } } } return(errorMessage.Equals(string.Empty)); }