src/Misc/EFTools/EntityDesignEntityDesigner/CustomCode/DomainClasses/EntityDesignerViewModel.cs
/// <summary>
///     This method iterates through model changes and update the corresponding DSL model and presentation elements.
///     The method consist of 2 steps:
///     1. The first step makes sure that DSL model elements are created and in sync with our Escher model.
///     2. The second step is to apply layout information from Diagram-Model to DSL PEL.
///     We also update Escher and DSL model Xref information.
/// </summary>
This method iterates through model changes and update the corresponding DSL model and presentation elements.
The method consist of 2 steps:
1. The first step makes sure that DSL model elements are created and in sync with our Escher model.
2. The second step is to apply layout information from Diagram-Model to DSL PEL.
We also update Escher and DSL model Xref information.
This method iterates through model changes and update the corresponding DSL model and presentation elements . The method consist of 2 steps : 1 . The first step makes sure that DSL model elements are created and in sync with our Escher model . 2 . The second step is to apply layout information from Diagram - Model to DSL PEL . We also update Escher and DSL model Xref information .
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private void ProcessModelChanges(EfiChangeGroup changeGroup)
        {
            EntityDesignerDiagram diagram = null;
            diagram = GetDiagram();
            var disableFixUpDiagramSelection = false;
            if (diagram == null)
            {
                return;
            }
            disableFixUpDiagramSelection = diagram.DisableFixUpDiagramSelection;
            try
            {
                 This turns off layout during "serialization" and fixes bad perf during update-model scenarios.
                 We set this to true here, and then set it false in the finally block because there were some problems with 
                 the DSL fix not drawing self-associations correctly when this is set to true all the time. 
                if (changeGroup.Transaction != null
                    && (changeGroup.Transaction.OriginatorId == EfiTransactionOriginator.UpdateModelFromDatabaseId ||
                        changeGroup.Transaction.OriginatorId == EfiTransactionOriginator.UndoRedoOriginatorId))
                {
                    Store.PropertyBag["WorkaroundFixSerializationTransaction"] = true;
                }
                     If coming from property window, we don't want the selection to change.
                else if (changeGroup.Transaction.OriginatorId == EfiTransactionOriginator.PropertyWindowOriginatorId
                         && diagram != null)
                {
                    diagram.DisableFixUpDiagramSelection = true;
                }
                 sort changes and discover the artifact that has changed
                var extraElementsToProcess = new HashSet<EFObject>();
                var changes = changeGroup.SortChangesForProcessing(new ChangeComparer());
                var artifacts = CurrentArtifactsInView;
                /
                 FIRST STEP: updating DSL Model Elements.
                /
                 tx name is not shown anywhere since we don't use the DSL undo manager
                using (var t = Store.TransactionManager.BeginTransaction(
                        InternalTransactionIdPrefix + changeGroup.Transaction.OriginatorId, true))
                {
                     start auto-arranger for arranging new elements
                     don't do this for undo/redo because we will translate the new diagram EFObject information into the DSL ShapeElements
                     don't do this for update model because we want to set up an entirely new transaction for auto-layout with the new shapes
                    if (changeGroup.Transaction.OriginatorId != EfiTransactionOriginator.UndoRedoOriginatorId
                        && changeGroup.Transaction.OriginatorId != EfiTransactionOriginator.UpdateModelFromDatabaseId)
                    {
                        if (diagram != null)
                        {
                            diagram.Arranger.Start(PointD.Empty);
                        }
                    }
                    var hasChangesForCurrentArtifactInView = false;
                    foreach (var change in changes)
                    {
                        if (artifacts.Contains(change.Changed.Artifact))
                        {
                             only process changes if the artifact is designer-safe.  
                            if (change.Changed.Artifact.IsDesignerSafe)
                            {
                                hasChangesForCurrentArtifactInView = true;
                                if (change.Changed is ModelDiagram.BaseDiagramObject)
                                {
                                    ProcessSingleDiagramModelChange(change, extraElementsToProcess);
                                }
                                else if (ProcessSingleModelChange(change))
                                {
                                    break;
                                }
                            }
                        }
                    }
                    foreach (var efobject in extraElementsToProcess)
                    {
                        var et = efobject as ConceptualEntityType;
                        if (et != null)
                        {
                            foreach (var p in et.Properties())
                            {
                                OnEFObjectCreatedOrUpdated(p, ModelXRef);
                            }
                            foreach (var np in et.NavigationProperties())
                            {
                                OnEFObjectCreatedOrUpdated(np, ModelXRef);
                            }
                            if (et.BaseType.Target != null)
                            {
                                OnEFObjectCreatedOrUpdated(et.BaseType, ModelXRef);
                            }
                        }
                        else
                        {
                            Debug.Fail("Unexpected type of model node in extraElementsToProcess");
                        }
                    }
                    if (hasChangesForCurrentArtifactInView & t.HasPendingChanges)
                    {
                        t.Commit();
                    }
                    if (changeGroup.Transaction.OriginatorId != EfiTransactionOriginator.UndoRedoOriginatorId
                        && changeGroup.Transaction.OriginatorId != EfiTransactionOriginator.UpdateModelFromDatabaseId)
                    {
                        Debug.Assert(diagram != null, "Should have discovered the diagram if autoArrange == true");
                        if (diagram != null)
                        {
                            diagram.Arranger.End();
                        }
                    }
                    if (ModelHasElements() == false)
                    {
                        var edd = GetDiagram();
                        if (edd != null)
                        {
                            edd.ResetWatermark(edd.ActiveDiagramView);
                        }
                    }
                }
                 we need to keep track of the entity shapes that needed to be auto layout.
                var shapesToAutoLayout = new List<ShapeElement>();
                /
                 SECOND STEP: updating DSL Presentation Elements.
                /
                 Given the changegroup and any transaction that originates from the model, see if there were any diagram EFObjects were changed. 
                 Go through each one, find the corresponding ShapeElement (DSL presentation element) that was created, and add it to the view model xref.
                if (changeGroup.Transaction != null)
                {
                    using (var t = Store.TransactionManager.BeginTransaction(
                            InternalTransactionIdPrefix + changeGroup.Transaction.OriginatorId, true))
                    {
                        var hasDiagramObjectChanges = false;
                        var moveDiagram2Shapes =
                            (changeGroup.Transaction.OriginatorId == EfiTransactionOriginator.UndoRedoOriginatorId ||
                             changeGroup.Transaction.OriginatorId == EfiTransactionOriginator.UpdateModelFromDatabaseId);
                        foreach (var change in changes)
                        {
                            if (artifacts.Contains(change.Changed.Artifact))
                            {
                                if (change.Changed.Artifact.IsDesignerSafe)
                                {
                                    if (change.Changed is DefaultableValue
                                        && change.Changed.Parent is ModelDesigner.Diagram
                                        && ModelXRef.ContainsKey(change.Changed.Parent))
                                    {
                                        hasDiagramObjectChanges = true;
                                        ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext)
                                            .SynchronizeSingleDslModelElement(this, change.Changed.Parent);
                                    }
                                    else
                                    {
                                         this will set the ShapeElements to their original position as well as add them to the XRef
                                        ModelDiagram.BaseDiagramObject modelDiagramObject = null;
                                        var currentNode = change.Changed;
                                        while (currentNode != null)
                                        {
                                            var baseDiagram = currentNode as ModelDiagram.BaseDiagramObject;
                                            if (baseDiagram != null)
                                            {
                                                modelDiagramObject = baseDiagram;
                                                break;
                                            }
                                            currentNode = currentNode.Parent;
                                        }
                                         Call TranslateDiagramObject to sync Escher Designer Model element and DSL PEL (Presentation Element).
                                         We need to call this even when the change type is 'delete' because it might affect DSL PEL.
                                         (For example: when you change entity type shape's FillColor to a default color, the FillColor attribute will be deleted since it is not needed,
                                         in that case, we still need to update DSL PEL).
                                        if (modelDiagramObject != null
                                            && modelDiagramObject.Diagram != null
                                            && modelDiagramObject.Diagram.Id == DiagramId)
                                        {
                                            hasDiagramObjectChanges = true;
                                            EntityModelToDslModelTranslatorStrategy.TranslateDiagramObject(
                                                this, modelDiagramObject, moveDiagram2Shapes, shapesToAutoLayout);
                                        }
                                    }
                                }
                            }
                        }
                        if (hasDiagramObjectChanges && t.HasPendingChanges)
                        {
                            t.Commit();
                        }
                    }
                }
                if (changeGroup.Transaction != null
                    && shapesToAutoLayout.Count > 0)
                {
                    diagram.AutoLayoutDiagram(shapesToAutoLayout);
                }
            }
            finally
            {
                Store.PropertyBag["WorkaroundFixSerializationTransaction"] = false;
                if (diagram != null)
                {
                    diagram.DisableFixUpDiagramSelection = disableFixUpDiagramSelection;
                }
            }
            if (_shouldClearAndReloadDiagram)
            {
                try
                {
                    ClearAndReloadDiagram();
                }
                finally
                {
                    _shouldClearAndReloadDiagram = false;
                }
            }
        }
[ SuppressMessage ( " " , " " ) ] [ SuppressMessage ( " " , " " ) ] private void ProcessModelChanges ( EfiChangeGroup changeGroup ) { EntityDesignerDiagram diagram = null ; diagram = GetDiagram ( ) ; var disableFixUpDiagramSelection = false ; if ( diagram == null ) { return ; } disableFixUpDiagramSelection = diagram . DisableFixUpDiagramSelection ; try { if ( changeGroup . Transaction != null && ( changeGroup . Transaction . OriginatorId == EfiTransactionOriginator . UpdateModelFromDatabaseId || changeGroup . Transaction . OriginatorId == EfiTransactionOriginator . UndoRedoOriginatorId ) ) { Store . PropertyBag [ " " ] = true ; } else if ( changeGroup . Transaction . OriginatorId == EfiTransactionOriginator . PropertyWindowOriginatorId && diagram != null ) { diagram . DisableFixUpDiagramSelection = true ; } var extraElementsToProcess = new HashSet < EFObject > ( ) ; var changes = changeGroup . SortChangesForProcessing ( new ChangeComparer ( ) ) ; var artifacts = CurrentArtifactsInView ; using ( var t = Store . TransactionManager . BeginTransaction ( InternalTransactionIdPrefix + changeGroup . Transaction . OriginatorId , true ) ) { if ( changeGroup . Transaction . OriginatorId != EfiTransactionOriginator . UndoRedoOriginatorId && changeGroup . Transaction . OriginatorId != EfiTransactionOriginator . UpdateModelFromDatabaseId ) { if ( diagram != null ) { diagram . Arranger . Start ( PointD . Empty ) ; } } var hasChangesForCurrentArtifactInView = false ; foreach ( var change in changes ) { if ( artifacts . Contains ( change . Changed . Artifact ) ) { if ( change . Changed . Artifact . IsDesignerSafe ) { hasChangesForCurrentArtifactInView = true ; if ( change . Changed is ModelDiagram . BaseDiagramObject ) { ProcessSingleDiagramModelChange ( change , extraElementsToProcess ) ; } else if ( ProcessSingleModelChange ( change ) ) { break ; } } } } foreach ( var efobject in extraElementsToProcess ) { var et = efobject as ConceptualEntityType ; if ( et != null ) { foreach ( var p in et . Properties ( ) ) { OnEFObjectCreatedOrUpdated ( p , ModelXRef ) ; } foreach ( var np in et . NavigationProperties ( ) ) { OnEFObjectCreatedOrUpdated ( np , ModelXRef ) ; } if ( et . BaseType . Target != null ) { OnEFObjectCreatedOrUpdated ( et . BaseType , ModelXRef ) ; } } else { Debug . Fail ( " " ) ; } } if ( hasChangesForCurrentArtifactInView & t . HasPendingChanges ) { t . Commit ( ) ; } if ( changeGroup . Transaction . OriginatorId != EfiTransactionOriginator . UndoRedoOriginatorId && changeGroup . Transaction . OriginatorId != EfiTransactionOriginator . UpdateModelFromDatabaseId ) { Debug . Assert ( diagram != null , " " ) ; if ( diagram != null ) { diagram . Arranger . End ( ) ; } } if ( ModelHasElements ( ) == false ) { var edd = GetDiagram ( ) ; if ( edd != null ) { edd . ResetWatermark ( edd . ActiveDiagramView ) ; } } } var shapesToAutoLayout = new List < ShapeElement > ( ) ; if ( changeGroup . Transaction != null ) { using ( var t = Store . TransactionManager . BeginTransaction ( InternalTransactionIdPrefix + changeGroup . Transaction . OriginatorId , true ) ) { var hasDiagramObjectChanges = false ; var moveDiagram2Shapes = ( changeGroup . Transaction . OriginatorId == EfiTransactionOriginator . UndoRedoOriginatorId || changeGroup . Transaction . OriginatorId == EfiTransactionOriginator . UpdateModelFromDatabaseId ) ; foreach ( var change in changes ) { if ( artifacts . Contains ( change . Changed . Artifact ) ) { if ( change . Changed . Artifact . IsDesignerSafe ) { if ( change . Changed is DefaultableValue && change . Changed . Parent is ModelDesigner . Diagram && ModelXRef . ContainsKey ( change . Changed . Parent ) ) { hasDiagramObjectChanges = true ; ModelTranslatorContextItem . GetEntityModelTranslator ( EditingContext ) . SynchronizeSingleDslModelElement ( this , change . Changed . Parent ) ; } else { ModelDiagram . BaseDiagramObject modelDiagramObject = null ; var currentNode = change . Changed ; while ( currentNode != null ) { var baseDiagram = currentNode as ModelDiagram . BaseDiagramObject ; if ( baseDiagram != null ) { modelDiagramObject = baseDiagram ; break ; } currentNode = currentNode . Parent ; } if ( modelDiagramObject != null && modelDiagramObject . Diagram != null && modelDiagramObject . Diagram . Id == DiagramId ) { hasDiagramObjectChanges = true ; EntityModelToDslModelTranslatorStrategy . TranslateDiagramObject ( this , modelDiagramObject , moveDiagram2Shapes , shapesToAutoLayout ) ; } } } } } if ( hasDiagramObjectChanges && t . HasPendingChanges ) { t . Commit ( ) ; } } } if ( changeGroup . Transaction != null && shapesToAutoLayout . Count > 0 ) { diagram . AutoLayoutDiagram ( shapesToAutoLayout ) ; } } finally { Store . PropertyBag [ " " ] = false ; if ( diagram != null ) { diagram . DisableFixUpDiagramSelection = disableFixUpDiagramSelection ; } } if ( _shouldClearAndReloadDiagram ) { try { ClearAndReloadDiagram ( ) ; } finally { _shouldClearAndReloadDiagram = false ; } } }
This method iterates through model changes and update the corresponding DSL model and presentation elements.
This method iterates through model changes and update the corresponding DSL model and presentation elements .
// If diagram is null it might have been deleted, in this case just return. // Store the value of the disableFixUpDiagramSelection. // // This turns off layout during "serialization" and fixes bad perf during update-model scenarios. // We set this to true here, and then set it false in the finally block because there were some problems with  // the DSL fix not drawing self-associations correctly when this is set to true all the time.  // // If coming from property window, we don't want the selection to change. // sort changes and discover the artifact that has changed /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // FIRST STEP: updating DSL Model Elements. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // tx name is not shown anywhere since we don't use the DSL undo manager // start auto-arranger for arranging new elements // don't do this for undo/redo because we will translate the new diagram EFObject information into the DSL ShapeElements // don't do this for update model because we want to set up an entirely new transaction for auto-layout with the new shapes // only process changes if the artifact is designer-safe.   // we need to keep track of the entity shapes that needed to be auto layout. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SECOND STEP: updating DSL Presentation Elements. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given the changegroup and any transaction that originates from the model, see if there were any diagram EFObjects were changed.  // Go through each one, find the corresponding ShapeElement (DSL presentation element) that was created, and add it to the view model xref. // this will set the ShapeElements to their original position as well as add them to the XRef // Call TranslateDiagramObject to sync Escher Designer Model element and DSL PEL (Presentation Element). // We need to call this even when the change type is 'delete' because it might affect DSL PEL. // (For example: when you change entity type shape's FillColor to a default color, the FillColor attribute will be deleted since it is not needed, // in that case, we still need to update DSL PEL).
changeGroup
EfiChangeGroup