protected override bool LoadView() { var ret = false; var isDocDataDirty = 0; // Save IsDocDataDirty flag here to be set back later. // This is because loading-view can cause the flag to be set since a new diagram could potentially created. DocData.IsDocDataDirty(out isDocDataDirty); IsLoading = true; try { var uri = Utils.FileName2Uri(DocData.FileName); _context = PackageManager.Package.DocumentFrameMgr.EditingContextManager.GetNewOrExistingContext(uri); Debug.Assert(_context != null, "_context should not be null"); // Set DSL Diagram instance and values. // Note: the code should be executed before we suspend rule notification. The diagram shapes will not created correctly if we don't. // When document is reloaded, a new diagram will be created; so we always need to check for the new view diagram every time LoadView is called. var currentDiagram = GetNewOrExistingViewDiagram(); if (Diagram != currentDiagram) { Diagram = currentDiagram; } // Ensure that cache _xRef is cleared. _xRef = null; // The only case where diagram is null at this point is that VS tries to open diagram that doesn't exist in our model. // One of the possibilities: the user creates multiple diagrams, open the diagrams in VS, then close the project without saving the document. // When the project is reopened in the same VS, VS remembers any opened windows and will try to reopen it. // In this case, we should close the frame. if (Diagram == null) { // Return false will force the window frame to be closed. return false; } ApplyLayoutInformationFromModelDiagram(); Debug.Assert(DocData.Store.RuleManager.IsRuleSuspended == false, "The rule notification should not be suspended."); DocData.Store.RuleManager.SuspendRuleNotification(); // We don't call base.LoadView() because the code assumes there is only 1 diagram (will assert otherwise), // and will always choose the first diagram. if (BaseLoadView()) { // Normally our toolbox items get populated only when the window is activated, but // in certain circumstances we may switch the mode of our designer (normal/safe-mode/etc) // when the window is already active. This is an expensive operation so we only need it when // we reload the active document. var escherDocData = DocData as MicrosoftDataEntityDesignDocData; if (escherDocData != null && escherDocData.IsHandlingDocumentReloaded) { ToolboxService.Refresh(); } ret = true; } // Listen to Diagram Title change event so we can update our window caption with the information. var entityDesignerDiagram = Diagram as EntityDesignerDiagram; Debug.Assert(entityDesignerDiagram != null, "The diagram is not the type of EntityDesignerDiagram"); if (entityDesignerDiagram != null) { entityDesignerDiagram.OnDiagramTitleChanged += OnDiagramTitleChanged; } UpdateWindowFrameCaption(); } finally { // After Diagram is set, DSL code enabled DSL Undo Manager, so the code below is to disable it. if (DocData.Store.UndoManager.UndoState == DslModeling.UndoState.Enabled) { DocData.Store.UndoManager.UndoState = DslModeling.UndoState.Disabled; } if (DocData.Store.RuleManager.IsRuleSuspended) { DocData.Store.RuleManager.ResumeRuleNotification(); } DocData.SetDocDataDirty(isDocDataDirty); IsLoading = false; } return ret; }
/// <summary> /// Updates corresponding view model item. /// For simplicity each change updates all item values. /// </summary> private void OnEFObjectUpdated(EfiChange change, ModelToDesignerModelXRefItem xref) { Debug.Assert(change.Changed != null); var efObject = change.Changed; // Updating a base type is a special case, because it really means creating or deleting an inheritance connector var baseType = efObject as EntityTypeBaseType; if (baseType != null) { if (xref.ContainsKey(baseType.Parent)) { // always recreate inheritance OnEFObjectDeleted(baseType, xref); if (xref.ContainsKey(baseType.Parent)) { ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext).SynchronizeSingleDslModelElement(this, efObject); } } return; } // for AssociationEnd we want to update parent Association var associationEnd = efObject as AssociationEnd; if (associationEnd != null) { efObject = associationEnd.Parent; } // regardless the change always update whole element (it shouldn't be too big overhead) OnEFObjectCreatedOrUpdated(efObject, xref); }
private void OnEFObjectCreatedOrUpdated(EFObject efObject, ModelToDesignerModelXRefItem xref) { Debug.Assert(efObject != null); if (false == ModelHelper.IsInConceptualModel(efObject)) { return; // ignore events from storage model } // special case for creating base type var baseType = efObject as EntityTypeBaseType; if (baseType != null) { if (xref.ContainsKey(baseType.Parent)) { ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext).SynchronizeSingleDslModelElement(this, efObject); } return; } var efElement = efObject as EFElement; if (efElement == null) { efElement = efObject.Parent as EFElement; } if (efElement != null) { var modelRoot = efElement as ConceptualEntityModel; if (modelRoot != null) { Namespace = modelRoot.Namespace.Value; return; } var modelEntityType = efElement as ConceptualEntityType; if (modelEntityType != null) { var viewEntityType = xref.GetExisting(modelEntityType) as EntityType; if (viewEntityType != null) { //update only ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(this, modelEntityType); } // Check to see if EFObject is type of ConceptualEntityType. // This is to prevent that the scenario updating entity-type name causes a new entity-type to be created in different diagram. else if (efObject is ConceptualEntityType) { //create EntityType and add it to the view model viewEntityType = ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(this, modelEntityType) as EntityType; EntityTypes.Add(viewEntityType); } return; } var modelProperty = efElement as Model.Entity.Property; if (modelProperty != null) { var entityType = modelProperty.Parent as Model.Entity.EntityType; if (entityType != null) { var viewEntityType = xref.GetExisting(entityType) as EntityType; // If the view Entity Type does not exist skip, continue since nothing to update. if (viewEntityType != null) { var viewProperty = xref.GetExisting(modelProperty) as Property; if (viewProperty != null) { //update only ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(viewEntityType, modelProperty); } else { //create property and add it to view's EntityType viewProperty = ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(viewEntityType, modelProperty) as Property; Debug.Assert(viewProperty != null, "Why DSL property is null?"); if (viewProperty != null) { // Determine where we should insert the new property by getting the previous sibling. var previousSibling = FindPreviousProperty(viewProperty) as Property; if (previousSibling != null) { // Get the index of the previous sibling. var propertyIndex = viewEntityType.Properties.IndexOf(previousSibling); Debug.Assert( propertyIndex >= 0, "Unable to find index of DSL property: " + previousSibling.Name + " in entity:" + viewEntityType.Name); if (propertyIndex >= 0) { viewEntityType.Properties.Insert(propertyIndex + 1, viewProperty); } } else { // if previous sibling is null, that means we need to insert the property as the first property of the entity-type. viewEntityType.Properties.Insert(0, viewProperty); } } } } } return; } var modelAssociationEnd = efElement as AssociationEnd; if (modelAssociationEnd != null) { // change focus to the association and it will be processed below efElement = modelAssociationEnd.Parent as EFElement; } var modelAssociation = efElement as Model.Entity.Association; if (modelAssociation != null) { // this will create association if necessary (if not it's update only) ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(this, modelAssociation); return; } var modelNavigationProperty = efElement as Model.Entity.NavigationProperty; if (modelNavigationProperty != null) { var entityType = modelNavigationProperty.Parent as Model.Entity.EntityType; Debug.Assert(entityType != null); var viewEntityType = xref.GetExisting(entityType) as EntityType; if (viewEntityType != null) { var viewNavigationProperty = xref.GetExisting(modelNavigationProperty) as NavigationProperty; if (viewNavigationProperty != null) { //update only ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(viewEntityType, modelNavigationProperty); } else { //create navigation property and add it to view's EntityType viewNavigationProperty = ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(viewEntityType, modelNavigationProperty) as NavigationProperty; Debug.Assert(viewNavigationProperty != null, "Why DSL navigation property is null?"); if (viewNavigationProperty != null) { var previousSibling = FindPreviousProperty(viewNavigationProperty) as NavigationProperty; if (previousSibling != null) { var propertyIndex = viewEntityType.NavigationProperties.IndexOf(previousSibling); Debug.Assert( propertyIndex >= 0, "Unable to find index of DSL navigation property: " + previousSibling.Name + " in entity:" + viewEntityType.Name); if (propertyIndex >= 0) { viewEntityType.NavigationProperties.Insert(propertyIndex + 1, viewNavigationProperty); } } else { // if previous sibling is null, that means we need to insert the property as the first navigation property of the entity-type. viewEntityType.NavigationProperties.Insert(0, viewNavigationProperty); } } } } return; } // see if we are creating the Key element or just a PropertyRef var key = efElement as Key; var propertyRefs = new List<PropertyRef>(); if (key != null) { // if this is true, we are not necessarily creating the Key element with only one property ref element - // we may be handling an undo operation, and there may be more than one property ref element. foreach (var propRef in key.PropertyRefs) { propertyRefs.Add(propRef); } } else { var propertyRef = efElement as PropertyRef; if (propertyRef != null) { propertyRefs.Add(propertyRef); } } if (propertyRefs.Count > 0) { foreach (var propRef in propertyRefs) { if (propRef != null && propRef.Parent is Key) { var property = propRef.Name.Target; if (property != null) { var entityType = property.Parent as Model.Entity.EntityType; Debug.Assert(entityType != null); var viewEntityType = xref.GetExisting(entityType) as EntityType; if (viewEntityType != null) { ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(viewEntityType, property); } } } } return; } } }
private void OnEFObjectDeleted(EFObject efObject, ModelToDesignerModelXRefItem xref) { Debug.Assert(efObject != null); // deleting key means that we will have to re-translate the properties of the // EntityType because the propertyRefs were deleted var key = efObject as Key; if (key != null && key.Parent != null) { var entityType = key.Parent as Model.Entity.EntityType; if (entityType != null) { var viewEntityType = xref.GetExisting(entityType) as EntityType; if (viewEntityType != null) { // Only translate properties that are in the view model foreach (var property in entityType.Properties().Where(p => xref.GetExisting(p) != null)) { ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(viewEntityType, property); } } } return; } // deleting key's propertyref means removing property from entity's key var propertyRef = efObject as PropertyRef; if (propertyRef != null && propertyRef.Parent is Key) { var property = propertyRef.Name.Target; if (property != null) { var entityType = property.Parent as Model.Entity.EntityType; Debug.Assert(entityType != null); var viewEntityType = xref.GetExisting(entityType) as EntityType; var viewProperty = xref.GetExisting(property) as Property; // if we are deleting whole EntityType this will be null if (viewEntityType != null && viewProperty != null) { ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(viewEntityType, property); } } return; } var modelProperty = efObject.Parent as ComplexConceptualProperty; if (modelProperty != null) { var entityType = modelProperty.Parent as Model.Entity.EntityType; if (entityType != null) { var viewEntityType = xref.GetExisting(entityType) as EntityType; if (viewEntityType != null) { Debug.Assert(xref.ContainsKey(modelProperty), "view for modelProperty not found"); ModelTranslatorContextItem.GetEntityModelTranslator(EditingContext) .SynchronizeSingleDslModelElement(viewEntityType, modelProperty); } } return; } ModelElement modelElement = null; var et = efObject as ConceptualEntityType; if (et != null) { foreach (var prop in et.Properties()) { modelElement = xref.GetExisting(prop); if (modelElement != null) { ModelXRef.Remove(prop, modelElement); modelElement.Delete(); } } foreach (var prop in et.NavigationProperties()) { modelElement = xref.GetExisting(prop); if (modelElement != null) { ModelXRef.Remove(prop, modelElement); modelElement.Delete(); } } } // If a diagram is deleted and the diagram is the only diagram that is opened in VS, we need to open the first diagram. // The assumption is that there will be another diagram exists in the model because the user can't delete a diagram if the diagram is the only diagram in the model. // We need to do this to ensure Model-Browser window is not closed and there at least 1 active designer for the EDMX in VS. var modelDiagram = efObject as ModelDesigner.Diagram; var currentDiagram = GetDiagram(); if (null != currentDiagram && null != modelDiagram && currentDiagram.DiagramId == modelDiagram.Id.Value) { var foundAnotherActiveDiagram = false; // Check if there is any active diagram in VS. foreach (var diagram in Store.ElementDirectory.FindElements<EntityDesignerDiagram>()) { if (currentDiagram != diagram && diagram.ActiveDiagramView != null && diagram.IsDeleted == false && diagram.IsDeleting == false) { foundAnotherActiveDiagram = true; break; } } if (!foundAnotherActiveDiagram) { var service = EditingContext.GetEFArtifactService(); var entityDesignArtifact = service.Artifact as EntityDesignArtifact; Debug.Assert(entityDesignArtifact != null, "EFArtifactService's artifact is null."); if (entityDesignArtifact != null) { var firstModelDiagram = entityDesignArtifact.DesignerInfo.Diagrams.FirstDiagram; // firstModelDiagram should never be equal to the diagram that was deleted. Debug.Assert( firstModelDiagram != null && firstModelDiagram != modelDiagram, "There is no valid diagram in the model."); if (firstModelDiagram != null && firstModelDiagram != modelDiagram) { // Change the DiagramID and reload. currentDiagram.DiagramId = firstModelDiagram.Id.Value; // Unfortunately we could not call ClearAndReloadDiagram here because a DSL transaction has been opened before this method is called; // Need to make wait until the transaction is committed. _shouldClearAndReloadDiagram = true; return; } } } } modelElement = xref.GetExisting(efObject); if (modelElement != null) { ModelXRef.Remove(efObject, modelElement); modelElement.Delete(); } }