public TransitionDesigner() { InitializeComponent(); this.Loaded += (sender, e) => { this.ModelItem.PropertyChanged += OnModelItemPropertyChanged; this.transitionsSharingTrigger.Clear(); ModelItem parentStateModelItem = StateContainerEditor.GetParentStateModelItemForTransition(this.ModelItem); ModelItem triggerModelItem = this.ModelItem.Properties[TriggerPropertyName].Value; if (triggerModelItem != null) { foreach (ModelItem transitionModelItem in parentStateModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection) { if (transitionModelItem != this.ModelItem) { if (triggerModelItem == transitionModelItem.Properties[TriggerPropertyName].Value) { this.transitionsSharingTrigger.Add(transitionModelItem); } } } } // Connectors starting from the same point should share the same trigger else { PointCollection thisPointCollection = this.ViewStateService.RetrieveViewState(this.ModelItem, StateContainerEditor.ConnectorLocationViewStateKey) as PointCollection; if (thisPointCollection != null && thisPointCollection.Count > 1) { foreach (ModelItem transitionModelItem in parentStateModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection) { if (transitionModelItem != this.ModelItem) { PointCollection pointCollection = this.ViewStateService.RetrieveViewState(transitionModelItem, StateContainerEditor.ConnectorLocationViewStateKey) as PointCollection; if (pointCollection != null && pointCollection.Count > 1) { if (pointCollection[0].IsEqualTo(thisPointCollection[0])) { Debug.Assert(transitionModelItem.Properties[TriggerPropertyName].Value == null, "Transition trigger should be null."); this.transitionsSharingTrigger.Add(transitionModelItem); } } } } } } if (this.transitionsSharingTrigger.Count > 0) { this.IsTriggerShared = true; } }; this.Unloaded += (sender, e) => { this.ModelItem.PropertyChanged -= OnModelItemPropertyChanged; this.transitionsSharingTrigger.Clear(); }; }
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(); } } }
// All the connectors are directly contained by the outmost editor. This is because connectors can go across states. void OnEditingScopeCompleted(object sender, EditingScopeEventArgs e) { Debug.Assert(this.IsOutmostStateContainerEditor(), "Only the outmost editor should listen to the EditingScopeCompleted events of the model tree."); if (this.transitionModelItemsAdded.Count > 0) { // We need to wait until after the state visuals are updated this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => { foreach (ModelItem transition in this.transitionModelItemsAdded) { ModelItem srcStateModelItem = StateContainerEditor.GetParentStateModelItemForTransition(transition); this.AddTransitionVisual(transition); } this.transitionModelItemsAdded.Clear(); })); } if (this.initialStateChanged) { Debug.Assert(this.ModelItem.ItemType == typeof(StateMachine), "Only StateMachine should have initial state"); Debug.Assert(this.initialNode != null, "Initial node should not be null"); // Remove the old link if (GetAttachedConnectors(this.initialNode).Count > 0) { this.RemoveConnectorOnOutmostEditor(GetAttachedConnectors(this.initialNode)[0]); } // Add the new link if the new initial state is not null ModelItem initialStateModelItem = this.ModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].Value; if (initialStateModelItem != null) { // We need to wait until after the state visuals are updated this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => { this.AddInitialNodeConnector(); })); } this.initialStateChanged = false; } }