// 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;
            }
        }
        // All the connectors are directly contained by the statemachine editor. This is because connectors can go across states.
        void OnEditingScopeCompleted(object sender, EditingScopeEventArgs e)
        {
            foreach (ModelItem item in e.EditingScope.ItemsRemoved)
            {
                modelItemToGuid.Remove(item);
            }

            if (ShouldSuppressAddingConnectorsWhenAddingStateVisuals(e.EditingScope))
            {
                this.suppressAddingConnectorsWhenAddingStateVisuals = true;
            }
            else
            {
                this.suppressAddingConnectorsWhenAddingStateVisuals = false;
            }

            foreach (Change change in e.EditingScope.Changes)
            {
                if (change is PropertyChange)
                {
                    PropertyChange propertyChange = change as PropertyChange;
                    if (propertyChange.Owner.ItemType == typeof(Transition)
                        && propertyChange.PropertyName == TransitionDesigner.ToPropertyName
                        && propertyChange.NewValue != propertyChange.OldValue
                        && !this.transitionModelItemsRemoved.Contains(propertyChange.Owner)
                        && !this.transitionModelItemsAdded.Contains(propertyChange.Owner)
                        && this.modelItemToUIElement.ContainsKey(propertyChange.NewValue))
                    {
                        if (propertyChange.OldValue != null)
                        {
                            Connector connector = this.GetConnectorInStateMachine(propertyChange.Owner);
                            if (connector != null)
                            {
                                this.Remove(connector);
                            }
                        }

                        if (propertyChange.NewValue != null)
                        {
                            this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
                            {
                                if (this.populated)
                                {
                                    this.AddTransitionVisual(propertyChange.Owner);
                                }
                            }));
                        }
                    }
                }
            }

            if (!IsTransitionReordering(e.EditingScope))
            {
                if (this.transitionModelItemsAdded.Count > 0)
                {
                    // We need to wait until after the state visuals are updated
                    this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
                    {
                        if (this.populated)
                        {
                            foreach (ModelItem transition in this.transitionModelItemsAdded)
                            {
                                if (transition.Properties[TransitionDesigner.ToPropertyName].Value != null)
                                {
                                    this.AddTransitionVisual(transition);
                                }
                            }
                        }
                        this.transitionModelItemsAdded.Clear();
                    }));
                }

                if (this.transitionModelItemsRemoved.Count > 0)
                {
                    foreach (ModelItem transition in this.transitionModelItemsRemoved)
                    {
                        Connector connector = this.GetConnectorInStateMachine(transition);
                        if (connector != null)
                        {
                            this.Remove(connector);
                        }
                    }
                    this.transitionModelItemsRemoved.Clear();
                }
            }

            if (this.initialStateChanged)
            {
                Fx.Assert(this.ModelItem.ItemType == typeof(StateMachine), "Only StateMachine should have initial state");
                Fx.Assert(this.initialNode != null, "Initial node should not be null");

                // Remove the old link
                if (GetAttachedConnectors(this.initialNode).Count > 0)
                {
                    this.Remove(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(() =>
                    {
                        if (this.populated)
                        {
                            this.AddInitialNodeConnector(GetStateView(initialStateModelItem));
                        }
                    }));
                }
                this.initialStateChanged = false;
            }
        }
コード例 #3
0
 void OnEditingScopeCompleted(object sender, EditingScopeEventArgs e)
 {
     this.isModelTreeChanged = true;
 }
コード例 #4
0
 private void OnEditingScopeCompleted(object sender, EditingScopeEventArgs e)
 {
     Fx.Assert(e.EditingScope != null, "e.EditingScope should not be null.");
     foreach (ModelItem removedModelItem in e.EditingScope.ItemsRemoved)
     {
         DeleteModelItem(removedModelItem);
     }
 }
        //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);
                                }
                            }
                        }
                    }
                }
            }
        }
コード例 #6
0
 void OnEditingScopeCompleted(object sender, EditingScopeEventArgs e)
 {
     this.isModelTreeChanged = true;
 }
コード例 #7
0
        void OnEditingScopeCompleted(object sender, EditingScopeEventArgs e)
        {
            if (e.EditingScope.HasEffectiveChanges)
            {
                NotifyModelChanged();

                // The undo unit of an ImmediateEditingScope is added into undo engine in ImmediateEditingScope.Complete
                // so we only handle non ImmediateEditingScope here
                if (!this.modelTreeManager.RedoUndoInProgress
                    && !(e.EditingScope is ImmediateEditingScope)
                    && undoEngine != null
                    && !e.EditingScope.SuppressUndo)
                {
                    undoEngine.AddUndoUnit(new EditingScopeUndoUnit(this.Context, this.modelTreeManager, e.EditingScope));
                }
            }
        }