2 // Copyright (c) Microsoft Corporation. All rights reserved.
5 namespace System.Activities.Presentation
7 using System.Activities.Debugger;
8 using System.Activities.Presentation.Model;
9 using System.Activities.Presentation.Services;
10 using System.Activities.Presentation.Validation;
11 using System.Activities.Presentation.Xaml;
12 using System.Collections.Generic;
16 /// This interface is used by visual studio integration to acquire a AppDomain serialization friendly reference to an object.
18 public sealed class ObjectReferenceService
20 private Dictionary<Guid, object> objectReferenceIds;
21 private Dictionary<Guid, int> objectReferenceCount;
22 private HashSet<Guid> subscribedForSourceLocationChanges;
23 private EditingContext context;
24 private ModelSearchServiceImpl modelSearchService;
25 private ModelTreeManager modelTreeManager;
28 /// This interface is used by visual studio integration to acquire a AppDomain serialization friendly reference to an object.
30 /// <param name="context">The EditingContext of the current WorkflowDesigner.</param>
31 public ObjectReferenceService(EditingContext context)
35 throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
38 this.context = context;
39 this.context.Services.Subscribe<ModelSearchService>(new SubscribeServiceCallback<ModelSearchService>(this.OnModelSearchServiceAvailable));
40 this.context.Services.Subscribe<ModelTreeManager>(new SubscribeServiceCallback<ModelTreeManager>(this.OnModelTreeManagerAvailable));
44 /// Fire an event when the SourceLocation of an ObjectReference might be updated because of a Save operation.
46 public event EventHandler<SourceLocationUpdatedEventArgs> SourceLocationUpdated;
48 private Dictionary<Guid, object> ObjectReferenceIds
52 if (this.objectReferenceIds == null)
54 this.objectReferenceIds = new Dictionary<Guid, object>();
57 return this.objectReferenceIds;
61 private Dictionary<Guid, int> ObjectReferenceCount
65 if (this.objectReferenceCount == null)
67 this.objectReferenceCount = new Dictionary<Guid, int>();
70 return this.objectReferenceCount;
74 private HashSet<Guid> SubscribedForSourceLocationChanges
78 if (this.subscribedForSourceLocationChanges == null)
80 this.subscribedForSourceLocationChanges = new HashSet<Guid>();
83 return this.subscribedForSourceLocationChanges;
88 /// Acquire a reference by the SourceLocation of the object.
89 /// Notice this method will automatically register the object to listen to SourceLocationUpdated, if available.
91 /// <param name="startLine">The start line of the object.</param>
92 /// <param name="startColumn">The start column of the object.</param>
93 /// <param name="endLine">The end line of the object.</param>
94 /// <param name="endColumn">The end column of the object.</param>
95 /// <returns>The object reference.</returns>
96 public Guid AcquireObjectReference(int startLine, int startColumn, int endLine, int endColumn)
98 if (this.modelSearchService != null)
100 ModelItem modelItem = this.modelSearchService.FindModelItem(startLine, startColumn, endLine, endColumn);
101 if (modelItem != null)
103 object searchObject = modelItem.GetCurrentValue();
104 Guid result = this.AcquireObjectReference(searchObject);
105 this.SubscribedForSourceLocationChanges.Add(result);
114 /// Acquire a reference of an object by its actual reference.
116 /// <param name="obj">The object which we need to acquire a reference for.</param>
117 /// <returns>The object reference.</returns>
118 public Guid AcquireObjectReference(object obj)
122 throw FxTrace.Exception.AsError(new ArgumentNullException("obj"));
126 Guid objectReferenceId = Guid.NewGuid();
127 foreach (KeyValuePair<Guid, object> kvp in this.ObjectReferenceIds)
129 if (object.ReferenceEquals(kvp.Value, obj))
131 objectReferenceId = kvp.Key;
139 this.ObjectReferenceIds.Add(objectReferenceId, obj);
142 this.IncreaseReferenceCount(objectReferenceId);
143 return objectReferenceId;
147 /// Release the activity reference - this allow the designer infrastructure to release the actual reference to the activity - thus avoiding memory leak.
149 /// <param name="objectReferenceId">The activity reference.</param>
150 public void ReleaseObjectReference(Guid objectReferenceId)
152 if (this.DecreaseReferenceCount(objectReferenceId))
154 this.ObjectReferenceIds.Remove(objectReferenceId);
155 if (this.SubscribedForSourceLocationChanges.Contains(objectReferenceId))
157 this.SubscribedForSourceLocationChanges.Remove(objectReferenceId);
163 /// Obtain the actual reference to the object by its ObjectReference - this method should be called within the designer AppDomain only.
165 /// <param name="objectReferenceId">The activity reference.</param>
166 /// <param name="obj">The de-referenced activity, if the reference is available, or null otherwise.</param>
167 /// <returns>True if the activity reference can be successfully de-referenced.</returns>
168 public bool TryGetObject(Guid objectReferenceId, out object obj)
170 return this.ObjectReferenceIds.TryGetValue(objectReferenceId, out obj);
173 internal void OnSaveCompleted()
175 if (this.SourceLocationUpdated != null)
177 if (this.modelSearchService != null)
179 foreach (Guid subscribedObjectReference in this.SubscribedForSourceLocationChanges)
181 object subscribedObject = this.ObjectReferenceIds[subscribedObjectReference];
182 SourceLocation updatedSourceLocation = this.modelSearchService.FindSourceLocation(this.modelTreeManager.GetModelItem(subscribedObject));
183 if (updatedSourceLocation != null)
185 this.SourceLocationUpdated(null, new SourceLocationUpdatedEventArgs(subscribedObjectReference, updatedSourceLocation));
192 private void OnModelSearchServiceAvailable(ModelSearchService modelSearchService)
194 if (modelSearchService != null)
196 this.modelSearchService = modelSearchService as ModelSearchServiceImpl;
200 private void OnModelTreeManagerAvailable(ModelTreeManager modelTreeManager)
202 if (modelTreeManager != null)
204 this.modelTreeManager = modelTreeManager as ModelTreeManager;
208 private void IncreaseReferenceCount(Guid objectReferenceId)
211 if (!this.ObjectReferenceCount.TryGetValue(objectReferenceId, out referenceCount))
217 this.ObjectReferenceCount[objectReferenceId] = referenceCount;
220 private bool DecreaseReferenceCount(Guid objectReferenceId)
222 Fx.Assert(this.ObjectReferenceCount.ContainsKey(objectReferenceId), "DecreaseReferenceCount should not be called when there is no reference.");
223 if (this.ObjectReferenceCount.ContainsKey(objectReferenceId))
225 int referenceCount = this.ObjectReferenceCount[objectReferenceId] - 1;
226 if (referenceCount == 0)
228 this.ObjectReferenceCount.Remove(objectReferenceId);
233 this.ObjectReferenceCount[objectReferenceId] = referenceCount;