void StoreConnectorLocationViewState(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 committed 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.StoreConnectorLocationViewState(StateContainerEditor.GetConnectorModelItem(connector), connector.Points, isUndoableViewState); this.internalViewStateChange = false; }
void DoDeleteItems(List <ModelItem> itemsToDelete, bool removeIncomingConnectors) { HashSet <Connector> connectorsToDelete = new HashSet <Connector>(); List <ModelItem> allStateModelItemsToDelete = new List <ModelItem>(); IEnumerable <ModelItem> selectedStateModelItems = this.Context.Items.GetValue <Selection>().SelectedObjects. Where <ModelItem>((p) => { return(p.ItemType == typeof(State)); }); foreach (ModelItem stateModelItem in itemsToDelete) { allStateModelItemsToDelete.Add(stateModelItem); allStateModelItemsToDelete.AddRange(GetAllChildStateModelItems(stateModelItem)); } foreach (ModelItem modelItem in allStateModelItemsToDelete) { // We only need to delete incoming connectors to the states to be deleted; outgoing connectors will be deleted // automatically when the containing state is deleted. List <Connector> incomingConnectors = StateContainerEditor.GetIncomingConnectors((UIElement)modelItem.View); foreach (Connector connector in incomingConnectors) { ModelItem transitionModelItem = StateContainerEditor.GetConnectorModelItem(connector); // If the transition is contained by the states to delete, we don't bother to delete it separately. if (!StateContainerEditor.IsTransitionModelItemContainedByStateModelItems(transitionModelItem, selectedStateModelItems)) { connectorsToDelete.Add(connector); } } } // If we don't need to remove incoming connectors, we still remove the transitions but then add them back later. // This is in order to create an undo unit that contains the change notifications needed to make undo/redo work correctly. foreach (Connector connector in connectorsToDelete) { ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector); if (removeIncomingConnectors || connectorModelItem.ItemType == typeof(Transition)) { this.DeleteConnectorModelItem(connector); } } if (!removeIncomingConnectors) { foreach (Connector connector in connectorsToDelete) { ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector); if (connectorModelItem.ItemType == typeof(Transition)) { StateContainerEditor.GetParentStateModelItemForTransition(connectorModelItem).Properties[StateDesigner.TransitionsPropertyName].Collection.Add(connectorModelItem); } } } if (null != itemsToDelete) { itemsToDelete.ForEach(p => this.DeleteState(p, removeIncomingConnectors)); } }
internal void DeleteConnectorModelItem(Connector connector) { ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector); if (connectorModelItem.ItemType == typeof(Transition)) { StateContainerEditor.GetParentStateModelItemForTransition(connectorModelItem).Properties[StateDesigner.TransitionsPropertyName].Collection.Remove(connectorModelItem); } // Connector from initial node else if (connectorModelItem.ItemType == typeof(StateMachine)) { using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.ClearInitialState)) { connectorModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(null); es.Complete(); } } }
// referenceTransitionModelItem is used when a connector is re-linked. void CreateTransition(ConnectionPoint sourceConnPoint, ConnectionPoint destConnPoint, ModelItem referenceTransitionModelItem, bool isSourceMoved) { Debug.Assert(this.IsOutmostStateContainerEditor(), "Should only be called by the outmost editor."); WorkflowViewElement srcDesigner = sourceConnPoint.ParentDesigner as WorkflowViewElement; WorkflowViewElement destDesigner = destConnPoint.ParentDesigner as WorkflowViewElement; Debug.Assert(srcDesigner is StateDesigner && destDesigner is StateDesigner, "The source and destination designers should both be StateDesigner"); ModelItem srcModelItem = srcDesigner.ModelItem; ModelItem destModelItem = destDesigner.ModelItem; ModelItem transitionModelItem = null; // We are moving the connector. if (referenceTransitionModelItem != null && referenceTransitionModelItem.ItemType == typeof(Transition)) { transitionModelItem = referenceTransitionModelItem; // We are moving the start of the connector. We only preserve the trigger if it is not shared. if (isSourceMoved) { Transition referenceTransition = referenceTransitionModelItem.GetCurrentValue() as Transition; ModelItem stateModelItem = GetParentStateModelItemForTransition(referenceTransitionModelItem); State state = stateModelItem.GetCurrentValue() as State; bool isTriggerShared = false; foreach (Transition transition in state.Transitions) { if (transition != referenceTransition && transition.Trigger == referenceTransition.Trigger) { isTriggerShared = true; break; } } if (isTriggerShared) { transitionModelItem.Properties[TransitionDesigner.TriggerPropertyName].SetValue(null); } } transitionModelItem.Properties[TransitionDesigner.ToPropertyName].SetValue(destModelItem); srcModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(transitionModelItem); } // We are creating a new connector. else { Transition newTransition = new Transition() { DisplayName = string.Empty }; newTransition.To = destModelItem.GetCurrentValue() as State; // Assign the shared trigger. if (sourceConnPoint.AttachedConnectors.Count > 0) { Connector connector = sourceConnPoint.AttachedConnectors[0]; Transition existingTransition = StateContainerEditor.GetConnectorModelItem(connector).GetCurrentValue() as Transition; newTransition.Trigger = existingTransition.Trigger; } transitionModelItem = srcModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(newTransition); } if (transitionModelItem != null) { PointCollection connectorViewState = new PointCollection(ConnectorRouter.Route(this.panel, sourceConnPoint, destConnPoint)); this.StoreConnectorLocationViewState(transitionModelItem, connectorViewState, true); } }
// referenceConnector is used when we are re-linking the connector. internal ConnectorCreationResult CreateConnectorGesture(ConnectionPoint sourceConnectionPoint, ConnectionPoint destConnectionPoint, Connector referenceConnector, bool isConnectorStartMoved) { Debug.Assert(this.IsOutmostStateContainerEditor(), "Should only be called by the outmost editor."); Debug.Assert(sourceConnectionPoint != null, "sourceConnectionPoint is null."); Debug.Assert(destConnectionPoint != null, "destConnectionPoint is null."); ConnectorCreationResult result = ConnectorCreationResult.OtherFailure; if (destConnectionPoint.PointType != ConnectionPointType.Outgoing && sourceConnectionPoint.PointType != ConnectionPointType.Incoming) { if (sourceConnectionPoint.ParentDesigner is StateDesigner) { bool sameDestination = false; ModelItem refTransitionModelItem = null; if (referenceConnector != null) { refTransitionModelItem = StateContainerEditor.GetConnectorModelItem(referenceConnector); ModelItem destStateModelItem = ((StateDesigner)destConnectionPoint.ParentDesigner).ModelItem; if (refTransitionModelItem != null && refTransitionModelItem.Properties[TransitionDesigner.ToPropertyName].Value == destStateModelItem) { sameDestination = true; } } // We do not allow transitions to composite states unless we don't change the transition destination // (e.g., we are moving the start of a connector). if (!sameDestination && !((StateDesigner)destConnectionPoint.ParentDesigner).IsSimpleState()) { result = ConnectorCreationResult.CannotCreateTransitionToCompositeState; } // We do not allow transitions from an ancestor to its descendant else if (StateContainerEditor.IsDescendantStateOf(((StateDesigner)destConnectionPoint.ParentDesigner).ModelItem, ((StateDesigner)sourceConnectionPoint.ParentDesigner).ModelItem)) { result = ConnectorCreationResult.CannotCreateTransitionFromAncestorToDescendant; } else { using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.CreateTransition)) { if (refTransitionModelItem != null) { this.CreateTransition(sourceConnectionPoint, destConnectionPoint, refTransitionModelItem, isConnectorStartMoved); } else { this.CreateTransition(sourceConnectionPoint, destConnectionPoint, null, false); } result = ConnectorCreationResult.Success; es.Complete(); } } } else if (sourceConnectionPoint.ParentDesigner is InitialNode) { StateDesigner destDesigner = (StateDesigner)destConnectionPoint.ParentDesigner; // We only allow simple states to be set as the initial state if (!destDesigner.IsSimpleState()) { result = ConnectorCreationResult.CannotSetCompositeStateAsInitialState; } else if (destDesigner.IsFinalState()) { result = ConnectorCreationResult.CannotSetFinalStateAsInitialState; } else { ModelItem destModelItem = destDesigner.ModelItem; using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.SetInitialState)) { this.StateMachineModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(destModelItem); PointCollection connectorViewState = new PointCollection(ConnectorRouter.Route(this.panel, sourceConnectionPoint, destConnectionPoint)); this.StoreConnectorLocationViewState(this.StateMachineModelItem, connectorViewState, true); result = ConnectorCreationResult.Success; es.Complete(); } } } } return(result); }