1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.Activities.Presentation.Debug
8 using System.Activities;
9 using System.Activities.Debugger;
10 using System.Activities.Presentation;
11 using System.Activities.Presentation.Hosting;
12 using System.Activities.Presentation.Model;
13 using System.Activities.Presentation.Services;
14 using System.Activities.Presentation.Validation;
15 using System.Activities.Presentation.View;
16 using System.Activities.Presentation.Xaml;
17 using System.Activities.XamlIntegration;
18 using System.Collections.Generic;
21 using System.Windows.Documents;
22 using System.Windows.Threading;
24 [Fx.Tag.XamlVisible(false)]
25 public class DebuggerService : IDesignerDebugView
27 EditingContext context;
28 ModelItem selectedModelItem;
29 SourceLocation currentLocation;
30 SourceLocation currentContext;
31 ModelItem currentModelItem;
32 ModelItem currentModelItemContext;
33 WorkflowViewService viewService;
34 ModelSearchServiceImpl modelSearchService;
35 ModelTreeManager modelTreeManager;
36 const string unresolvedPrefix = "unresolved:";
38 AttachedProperty<bool> isBreakpointEnabledProperty;
39 AttachedProperty<bool> isBreakpointBoundedProperty;
40 AttachedProperty<bool> isBreakpointConditionalProperty;
41 AttachedProperty<bool> isCurrentLocationProperty;
42 AttachedProperty<bool> isCurrentContextProperty;
44 Dictionary<object, SourceLocation> instanceToSourceLocationMapping;
45 Dictionary<ModelItem, SourceLocation> modelItemToSourceLocation;
46 Dictionary<SourceLocation, ModelItem> sourceLocationToModelItem;
48 Dictionary<ModelItem, BreakpointTypes> breakpoints; // The map contains breakpoint that has its ModelItem on the modelTree.
49 Dictionary<ModelItem, BreakpointTypes> transientBreakpoints; // The map contains breakpoint that has its ModelItem not on the modelTree.
50 Dictionary<SourceLocation, BreakpointTypes> unmappedBreakpoints; // The map contains breakpoint that has no ModelItem
52 // This is used to generate unique source line no when the view element does not have a source location
53 int lastSourceLineNo = 1;
55 bool isReadOnly = false;
56 bool isDebugging = false;
57 private string fileName;
58 private bool requiresUpdateSourceLocation;
60 // Storing background BringToViewCurrentLocation operation.
61 DispatcherOperation bringToViewCurrentLocationOperation = null;
63 public DebuggerService(EditingContext context)
67 throw FxTrace.Exception.ArgumentNull("context");
70 this.context = context;
71 this.modelItemToSourceLocation = new Dictionary<ModelItem, SourceLocation>();
72 this.sourceLocationToModelItem = new Dictionary<SourceLocation, ModelItem>();
73 this.breakpoints = new Dictionary<ModelItem, BreakpointTypes>();
74 // Breakpoints transiently removed from the document (copy/paste/undo/redo).
75 this.transientBreakpoints = new Dictionary<ModelItem, BreakpointTypes>();
76 this.unmappedBreakpoints = new Dictionary<SourceLocation, BreakpointTypes>(4);
77 this.instanceToSourceLocationMapping = new Dictionary<object, SourceLocation>();
79 this.context.Items.Subscribe<Selection>(new SubscribeContextCallback<Selection>(this.SelectionChanged));
80 this.context.Services.Subscribe<ViewService>(new SubscribeServiceCallback<ViewService>(this.OnViewServiceAvailable));
81 this.context.Services.Subscribe<ModelSearchService>(new SubscribeServiceCallback<ModelSearchService>(this.OnModelSearchServiceAvailable));
82 this.context.Services.Subscribe<AttachedPropertiesService>(new SubscribeServiceCallback<AttachedPropertiesService>(this.OnAttachedPropertiesServiceAvailable));
83 this.context.Services.Subscribe<ModelTreeManager>(new SubscribeServiceCallback<ModelTreeManager>(this.OnModelTreeManagerServiceAvailable));
85 this.requiresUpdateSourceLocation = true;
90 // Get the currently selected location from the designer
91 // generally this is the location of the object currently selected by the user
92 public SourceLocation SelectedLocation
96 return (this.selectedModelItem != null && AllowBreakpointAttribute.IsBreakpointAllowed(this.selectedModelItem.ItemType)) ?
97 this.GetSourceLocationFromModelItem(this.selectedModelItem) : null;
101 // Set current location of execution.
102 // The location to shown the "yellow" arrow.
103 public SourceLocation CurrentLocation
107 return this.currentLocation;
112 this.currentLocation = value;
113 ModelItem previousModelItem = this.currentModelItem;
114 UpdateCurrentModelItem();
115 if (this.currentLocation != null && this.currentModelItem == null)
116 { // This is a rare case but it happens when the designer is not all done with bringing up the view but
117 // Debugger already set this location.
118 PostBringToViewCurrentLocation(previousModelItem);
122 BringToViewCurrentLocation(previousModelItem);
127 public void EnsureVisible(SourceLocation sourceLocation)
129 SourceLocation exactLocation = GetExactLocation(sourceLocation);
130 ModelItem mi = this.GetModelItemFromSourceLocation(exactLocation, /* forceCreate */ true);
137 void BringToViewCurrentLocation(ModelItem previousModelItem)
139 SetPropertyValue(previousModelItem, isCurrentLocationProperty, this.currentModelItem);
140 if (this.currentModelItem != this.currentModelItemContext)
142 BringToView(this.currentModelItem);
146 // Post new BringToViewCurrentLocation operation
147 void PostBringToViewCurrentLocation(ModelItem previousModelItem)
149 // Abort pending operation.
150 if (this.bringToViewCurrentLocationOperation != null)
152 this.bringToViewCurrentLocationOperation.Abort();
153 this.bringToViewCurrentLocationOperation = null;
156 // Post a new background operation.
157 this.bringToViewCurrentLocationOperation = Dispatcher.CurrentDispatcher.BeginInvoke(
158 DispatcherPriority.Background,
159 (DispatcherOperationCallback)delegate(object arg)
161 this.UpdateCurrentModelItem();
162 this.BringToViewCurrentLocation(previousModelItem);
163 this.bringToViewCurrentLocationOperation = null;
170 // Set current context (stack frame scope).
171 // The highlighted scope of execution.
172 public SourceLocation CurrentContext
176 return this.currentContext;
180 this.currentContext = value;
181 ModelItem previousModelItem = this.currentModelItemContext;
182 UpdateCurrentModelItemContext();
183 SetPropertyValue(previousModelItem, this.isCurrentContextProperty, this.currentModelItemContext);
184 BringToView(this.currentModelItemContext);
188 // Set to true while debugging
189 public bool IsDebugging
193 return this.isDebugging;
198 ReadOnlyState readOnlyState = this.context.Items.GetValue<ReadOnlyState>();
199 if (readOnlyState != null)
202 if (value && !this.isDebugging)
204 this.isDebugging = true;
205 // backup the read-only state
206 this.isReadOnly = readOnlyState.IsReadOnly;
207 readOnlyState.IsReadOnly = true;
210 else if (!value && this.isDebugging)
212 this.isDebugging = false;
213 // restore to previous state before debugging
214 readOnlyState.IsReadOnly = this.isReadOnly;
216 this.context.Items.SetValue(new ReadOnlyState() { IsReadOnly = readOnlyState.IsReadOnly });
221 public bool HideSourceFileName
227 void UpdateCurrentModelItem()
229 this.currentModelItem = this.GetModelItemFromSourceLocation(this.currentLocation, /* forceCreate */ true);
232 void UpdateCurrentModelItemContext()
234 this.currentModelItemContext = this.GetModelItemFromSourceLocation(this.currentContext, /* forceCreate */ true);
237 void BringToView(ModelItem modelItem)
239 if (modelItem != null)
245 void OnAttachedPropertiesServiceAvailable(AttachedPropertiesService attachedPropertiesService)
247 this.isBreakpointEnabledProperty = new AttachedProperty<bool>()
249 Getter = (modelItem) => IsBreakpointOfType(modelItem, BreakpointTypes.Enabled),
250 Name = "IsBreakpointEnabled",
251 OwnerType = typeof(object)
254 this.isBreakpointBoundedProperty = new AttachedProperty<bool>()
256 Getter = (modelItem) => IsBreakpointOfType(modelItem, BreakpointTypes.Bounded),
257 Name = "IsBreakpointBounded",
258 OwnerType = typeof(object)
261 this.isBreakpointConditionalProperty = new AttachedProperty<bool>()
263 Getter = (modelItem) => IsBreakpointOfType(modelItem, BreakpointTypes.Conditional),
264 Name = "IsBreakpointConditional",
265 OwnerType = typeof(object)
268 this.isCurrentLocationProperty = new AttachedProperty<bool>()
270 Getter = (modelItem) => IsCurrentLocation(modelItem),
271 Name = "IsCurrentLocation",
272 OwnerType = typeof(object)
275 this.isCurrentContextProperty = new AttachedProperty<bool>()
277 Getter = (modelItem) => IsCurrentContext(modelItem),
278 Name = "IsCurrentContext",
279 OwnerType = typeof(object)
282 attachedPropertiesService.AddProperty(isBreakpointEnabledProperty);
283 attachedPropertiesService.AddProperty(isBreakpointBoundedProperty);
284 attachedPropertiesService.AddProperty(isBreakpointConditionalProperty);
285 attachedPropertiesService.AddProperty(isCurrentLocationProperty);
286 attachedPropertiesService.AddProperty(isCurrentContextProperty);
289 void OnModelTreeManagerServiceAvailable(ModelTreeManager modelTreeManager)
291 this.modelTreeManager = modelTreeManager;
292 this.modelTreeManager.EditingScopeCompleted += OnEditingScopeCompleted;
295 private void OnEditingScopeCompleted(object sender, EditingScopeEventArgs e)
297 Fx.Assert(e.EditingScope != null, "e.EditingScope should not be null.");
298 foreach (ModelItem removedModelItem in e.EditingScope.ItemsRemoved)
300 DeleteModelItem(removedModelItem);
304 private void DeleteModelItem(ModelItem modelItem)
306 if (modelItem != null)
308 BreakpointTypes breakpointType;
309 if (this.breakpoints.TryGetValue(modelItem, out breakpointType))
311 this.transientBreakpoints[modelItem] = breakpointType; // cache it in case it's added later (move case).
312 SetBreakpointType(modelItem, BreakpointTypes.None); // clear breakpoint
315 DeleteFromMapping(modelItem.GetCurrentValue());
319 // Delete a single object from the mappings.
320 // We only delete unresolved object, i.e. object that never been
321 // saved. We leave the resolved object untouch (otherwise undoing
322 // the removed object will make it as "unresolved" the next time around).
323 void DeleteFromMapping(object unresolvedObject)
325 SourceLocation sourceLocation;
326 if (this.instanceToSourceLocationMapping.TryGetValue(unresolvedObject, out sourceLocation))
328 if (IsUnresolved(sourceLocation))
330 this.instanceToSourceLocationMapping.Remove(unresolvedObject);
332 if (this.sourceLocationToModelItem.TryGetValue(sourceLocation, out modelItem))
334 this.sourceLocationToModelItem.Remove(sourceLocation);
335 this.modelItemToSourceLocation.Remove(modelItem);
341 bool IsCurrentLocation(ModelItem modelItem)
343 UpdateCurrentModelItem();
344 return this.currentModelItem == modelItem;
347 bool IsCurrentContext(ModelItem modelItem)
349 UpdateCurrentModelItemContext();
350 return this.currentModelItemContext == modelItem;
353 void SelectionChanged(Selection selection)
355 this.selectedModelItem = selection.PrimarySelection;
358 // Check if unmapped breakpoint exists for the given sourceLocation,
359 // if so, mapped it to the given model item & remove it from unmapped breakpoints.
360 void TryActivateUnmappedBreakpoint(SourceLocation sourceLocation, ModelItem modelItem)
362 BreakpointTypes breakpointType;
363 if (this.unmappedBreakpoints.TryGetValue(sourceLocation, out breakpointType))
365 this.SetBreakpointType(modelItem, breakpointType);
366 this.unmappedBreakpoints.Remove(sourceLocation);
370 void TryActivateAllUnmappedBreakpoints()
372 if (this.unmappedBreakpoints.Count > 0)
374 List<SourceLocation> unmappedLocations = new List<SourceLocation>();
375 unmappedLocations.AddRange(this.unmappedBreakpoints.Keys);
376 foreach (SourceLocation unmappedLocation in unmappedLocations)
378 ModelItem modelItem = this.GetModelItemFromSourceLocation(unmappedLocation);
379 if (modelItem != null)
381 TryActivateUnmappedBreakpoint(unmappedLocation, modelItem);
387 bool IsBreakpointOfType(ModelItem modelItem, BreakpointTypes breakpointType)
390 BreakpointTypes actualBreakpointType;
391 TryActivateAllUnmappedBreakpoints();
392 if (this.breakpoints.TryGetValue(modelItem, out actualBreakpointType))
394 result = (actualBreakpointType & breakpointType) > 0;
399 void SetBreakpointType(ModelItem modelItem, BreakpointTypes newBreakpointType)
401 BreakpointTypes oldBreakpointType = BreakpointTypes.None;
402 if (this.breakpoints.TryGetValue(modelItem, out oldBreakpointType))
404 Fx.Assert(oldBreakpointType != BreakpointTypes.None, "Should not store BreakpointType.None");
405 if (newBreakpointType == BreakpointTypes.None)
407 this.breakpoints.Remove(modelItem);
411 this.breakpoints[modelItem] = newBreakpointType;
414 else if (newBreakpointType != BreakpointTypes.None)
416 this.breakpoints.Add(modelItem, newBreakpointType);
419 // Now notifying corresponding properties.
420 if ((oldBreakpointType & BreakpointTypes.Bounded) !=
421 (newBreakpointType & BreakpointTypes.Bounded))
423 this.isBreakpointBoundedProperty.NotifyPropertyChanged(modelItem);
426 if ((oldBreakpointType & BreakpointTypes.Enabled) !=
427 (newBreakpointType & BreakpointTypes.Enabled))
429 this.isBreakpointEnabledProperty.NotifyPropertyChanged(modelItem);
432 if ((oldBreakpointType & BreakpointTypes.Conditional) !=
433 (newBreakpointType & BreakpointTypes.Conditional))
435 this.isBreakpointConditionalProperty.NotifyPropertyChanged(modelItem);
439 // Return exact source location given approximate location.
440 public SourceLocation GetExactLocation(SourceLocation approximateLocation)
442 this.EnsureSourceLocationUpdated();
444 if (approximateLocation == null)
446 throw FxTrace.Exception.ArgumentNull("approximateLocation");
449 SourceLocation exactLocation = null;
451 foreach (SourceLocation sourceLocation in this.instanceToSourceLocationMapping.Values)
453 if (sourceLocation.StartLine == approximateLocation.StartLine)
455 exactLocation = sourceLocation;
460 if (exactLocation == null)
462 exactLocation = FindClosestSourceLocation(approximateLocation, this.instanceToSourceLocationMapping.Values);
465 return exactLocation;
468 // This method tries to find the inner most outer source location from a list
469 // The outer source locations of a source location is ones that contains it
470 // The inner most outer source location is the one nested most deeply, right outside of the source location being contained.
471 private static SourceLocation FindInnerMostContainer(SourceLocation approximateLocation, IEnumerable<SourceLocation> availableSourceLocations)
473 Fx.Assert(approximateLocation != null && availableSourceLocations != null, "Argument should not be null");
475 SourceLocation innerMostOuterSourceLocation = null;
477 foreach (SourceLocation sourceLocation in availableSourceLocations)
479 if (sourceLocation.Contains(approximateLocation))
481 if (innerMostOuterSourceLocation == null)
483 innerMostOuterSourceLocation = sourceLocation;
487 if (innerMostOuterSourceLocation.Contains(sourceLocation))
489 innerMostOuterSourceLocation = sourceLocation;
495 return innerMostOuterSourceLocation;
498 internal static SourceLocation FindClosestSourceLocation(SourceLocation approximateLocation, IEnumerable<SourceLocation> availableSourceLocations)
500 Fx.Assert(approximateLocation != null && availableSourceLocations != null, "Argument should not be null");
502 SourceLocation exactLocation = null;
503 SourceLocation innerMostOuterSourceLocation =
504 FindInnerMostContainer(approximateLocation, availableSourceLocations);
506 if (innerMostOuterSourceLocation != null)
508 exactLocation = innerMostOuterSourceLocation;
512 // Find the next line of the approximateLocation.
513 int minimumDistance = int.MaxValue;
514 foreach (SourceLocation sourceLocation in availableSourceLocations)
516 int lineDistance = sourceLocation.StartLine - approximateLocation.StartLine;
517 if ((lineDistance > 0) &&
518 ((lineDistance < minimumDistance) ||
519 ((lineDistance == minimumDistance) && (sourceLocation.StartColumn < exactLocation.StartColumn)))) // if same distance, then compare the start column
521 exactLocation = sourceLocation;
522 minimumDistance = lineDistance;
527 return exactLocation;
530 // Called after a Save by AddIn to update breakpoints with new locations
531 public IDictionary<SourceLocation, BreakpointTypes> GetBreakpointLocations()
533 IDictionary<SourceLocation, BreakpointTypes> breakpointLocations = new Dictionary<SourceLocation, BreakpointTypes>();
535 // Collect source locations of model items with breakpoints
536 if (this.breakpoints.Count > 0 || this.unmappedBreakpoints.Count > 0)
538 foreach (KeyValuePair<ModelItem, BreakpointTypes> entry in this.breakpoints)
540 SourceLocation breakpointLocation = this.GetSourceLocationFromModelItem(entry.Key);
541 // BreakpointLocation can be null, if the model item is deleted but without notification
542 // through OnModelChanged. This happens when the breakpoint is located inside child
543 // of a deleted object.
544 if (breakpointLocation != null)
546 breakpointLocations.Add(breakpointLocation, entry.Value);
549 foreach (KeyValuePair<SourceLocation, BreakpointTypes> entry in this.unmappedBreakpoints)
551 breakpointLocations.Add(entry.Key, entry.Value);
554 return breakpointLocations;
557 // Inserting a new breakpoint of a given type.
558 public void InsertBreakpoint(SourceLocation sourceLocation, BreakpointTypes breakpointType)
560 this.UpdateBreakpoint(sourceLocation, breakpointType);
563 // Update the appearance of a given breakpoint to show the given type.
564 public void UpdateBreakpoint(SourceLocation sourceLocation, BreakpointTypes newBreakpointType)
566 ModelItem modelItem = this.GetModelItemFromSourceLocation(sourceLocation);
567 if (modelItem != null)
569 SetBreakpointType(modelItem, newBreakpointType);
573 BreakpointTypes oldBreakpointType;
574 if (this.unmappedBreakpoints.TryGetValue(sourceLocation, out oldBreakpointType))
576 if (newBreakpointType == BreakpointTypes.None)
578 this.unmappedBreakpoints.Remove(sourceLocation);
582 this.unmappedBreakpoints[sourceLocation] = newBreakpointType;
585 else if (newBreakpointType != BreakpointTypes.None)
587 this.unmappedBreakpoints.Add(sourceLocation, newBreakpointType);
592 // Delete a breakpoint.
593 public void DeleteBreakpoint(SourceLocation sourceLocation)
595 UpdateBreakpoint(sourceLocation, BreakpointTypes.None);
598 // Reset breakpoints: delete and prepare for breakpoint refresh.
599 public void ResetBreakpoints()
601 ModelItem[] oldModelItems = new ModelItem[this.breakpoints.Keys.Count];
602 this.breakpoints.Keys.CopyTo(oldModelItems, 0);
603 this.breakpoints.Clear();
604 this.unmappedBreakpoints.Clear();
606 // Now notifying update to corresponding properties.
607 foreach (ModelItem modelItem in oldModelItems)
609 this.isBreakpointBoundedProperty.NotifyPropertyChanged(modelItem);
610 this.isBreakpointEnabledProperty.NotifyPropertyChanged(modelItem);
611 this.isBreakpointConditionalProperty.NotifyPropertyChanged(modelItem);
615 public void UpdateSourceLocations(Dictionary<object, SourceLocation> newSourceLocationMapping)
617 if (newSourceLocationMapping == null)
619 throw FxTrace.Exception.ArgumentNull("newSourceLocationMapping");
622 // Update unmappedBreakpoints before refreshing the instanceToSourceLocationMapping.
623 if (this.unmappedBreakpoints.Count > 0)
625 Dictionary<SourceLocation, BreakpointTypes> newUnmappedBreakpoints = new Dictionary<SourceLocation, BreakpointTypes>(this.unmappedBreakpoints.Count);
626 foreach (KeyValuePair<object, SourceLocation> kvpEntry in this.instanceToSourceLocationMapping)
628 if (this.unmappedBreakpoints.ContainsKey(kvpEntry.Value))
630 if (newSourceLocationMapping.ContainsKey(kvpEntry.Key))
632 newUnmappedBreakpoints.Add(newSourceLocationMapping[kvpEntry.Key], this.unmappedBreakpoints[kvpEntry.Value]);
636 this.unmappedBreakpoints = newUnmappedBreakpoints;
639 // It is possible that after InvalidateSourceLocationMapping, before UpdateSourceLocations, we introduced new unresolvedEntries.
640 // These entries should not be dropped, or we will not be able to add breakpoint before UpdateSourceLocation.
641 List<KeyValuePair<object, SourceLocation>> unresolvedEntries = this.instanceToSourceLocationMapping.Where(entry => IsUnresolved(entry.Value)).ToList();
643 this.instanceToSourceLocationMapping = newSourceLocationMapping;
644 this.sourceLocationToModelItem.Clear();
645 this.modelItemToSourceLocation.Clear();
646 this.transientBreakpoints.Clear();
648 if (this.modelTreeManager != null)
650 foreach (KeyValuePair<object, SourceLocation> kvp in newSourceLocationMapping)
652 ModelItem modelItem = this.modelTreeManager.GetModelItem(kvp.Key);
653 if (modelItem != null)
655 SourceLocation sourceLocation = kvp.Value;
656 this.modelItemToSourceLocation.Add(modelItem, sourceLocation);
657 this.sourceLocationToModelItem.Add(sourceLocation, modelItem);
661 foreach (KeyValuePair<object, SourceLocation> unresolvedEntry in unresolvedEntries)
663 object unresolvedObject = unresolvedEntry.Key;
664 SourceLocation sourceLocation = unresolvedEntry.Value;
665 if (!this.instanceToSourceLocationMapping.ContainsKey(unresolvedObject))
667 this.instanceToSourceLocationMapping.Add(unresolvedObject, sourceLocation);
668 ModelItem modelItem = this.modelTreeManager.GetModelItem(unresolvedObject);
669 if (modelItem != null)
671 this.modelItemToSourceLocation.Add(modelItem, sourceLocation);
672 this.sourceLocationToModelItem.Add(sourceLocation, modelItem);
678 TryActivateAllUnmappedBreakpoints();
681 // Called by View Service when a new view element is created
682 private void ViewCreated(object sender, ViewCreatedEventArgs e)
686 ModelItem modelItem = e.View.ModelItem;
687 object addedObject = modelItem.GetCurrentValue();
689 // Create a mapping between SourceLocation and this View Element
690 SourceLocation sourceLocation = this.GetSourceLocationFromModelItemInstance(addedObject);
691 if (sourceLocation == null)
693 // The current view element has not been saved yet to the Xaml file
694 sourceLocation = GenerateUnresolvedLocation();
695 this.instanceToSourceLocationMapping.Add(addedObject, sourceLocation);
698 this.modelItemToSourceLocation[modelItem] = sourceLocation;
699 this.sourceLocationToModelItem[sourceLocation] = modelItem;
701 BreakpointTypes breakpointType;
702 // check if it's in the transient breakpoint list.
703 if (this.transientBreakpoints.TryGetValue(modelItem, out breakpointType))
705 this.transientBreakpoints.Remove(modelItem);
706 SetBreakpointType(modelItem, breakpointType);
710 TryActivateUnmappedBreakpoint(sourceLocation, modelItem);
715 private SourceLocation GenerateUnresolvedLocation()
717 return new SourceLocation(unresolvedPrefix + this.context.Items.GetValue<WorkflowFileItem>().LoadedFile, this.lastSourceLineNo++);
720 private static bool IsUnresolved(SourceLocation sourceLocation)
722 return !string.IsNullOrEmpty(sourceLocation.FileName) && sourceLocation.FileName.StartsWith(unresolvedPrefix, StringComparison.OrdinalIgnoreCase);
725 // This method is called during Load/Save - the resolved mapping should be invalidated.
726 internal void InvalidateSourceLocationMapping(string fileName)
728 this.fileName = fileName;
729 this.requiresUpdateSourceLocation = true;
731 // Remove, from the SourceLocationMappings, the entries with resolved SourceLocation - they are no longer valid and should be refreshed.
732 List<KeyValuePair<ModelItem, SourceLocation>> resolvedEntries = this.modelItemToSourceLocation.Where(entry => !IsUnresolved(entry.Value)).ToList();
733 foreach (KeyValuePair<ModelItem, SourceLocation> resolvedEntry in resolvedEntries)
735 this.modelItemToSourceLocation.Remove(resolvedEntry.Key);
736 this.sourceLocationToModelItem.Remove(resolvedEntry.Value);
737 this.instanceToSourceLocationMapping.Remove(resolvedEntry.Key.GetCurrentValue());
740 // All breakpoint should simply stay - unmappedBreakpoint will get updated to newSourceLocation when we have the newSourceLocation.
743 private void EnsureSourceLocationUpdated()
745 Fx.Assert(this.modelSearchService != null, "ModelSearchService should be available and is ensured in WorkflowDesigner constructor");
746 if (this.requiresUpdateSourceLocation)
748 Dictionary<object, SourceLocation> updatedSourceLocations = new Dictionary<object, SourceLocation>();
749 foreach (ModelItem key in this.modelSearchService.GetObjectsWithSourceLocation())
751 // disallow expressions
752 if (AllowBreakpointAttribute.IsBreakpointAllowed(key.ItemType) && !typeof(IValueSerializableExpression).IsAssignableFrom(key.ItemType))
754 SourceLocation sourceLocationWithoutFileName = this.modelSearchService.FindSourceLocation(key);
756 // Appending the fileName
757 SourceLocation sourceLocationWithFileName = new SourceLocation(this.fileName,
758 sourceLocationWithoutFileName.StartLine,
759 sourceLocationWithoutFileName.StartColumn,
760 sourceLocationWithoutFileName.EndLine,
761 sourceLocationWithoutFileName.EndColumn);
762 updatedSourceLocations.Add(key.GetCurrentValue(), sourceLocationWithFileName);
766 this.UpdateSourceLocations(updatedSourceLocations);
767 this.requiresUpdateSourceLocation = false;
771 private void OnModelSearchServiceAvailable(ModelSearchService modelSearchService)
773 this.modelSearchService = (ModelSearchServiceImpl)modelSearchService;
776 private void OnViewServiceAvailable(ViewService viewService)
778 this.viewService = (WorkflowViewService)viewService;
779 this.viewService.ViewCreated += this.ViewCreated;
782 private SourceLocation GetSourceLocationFromModelItemInstance(object instance)
784 SourceLocation sourceLocation;
786 // instanceToSourceLocationMapping contains source locations for all instances
787 // immediately after a Load or save. For instances that have been just dropped into
788 // the Designer from the Toolbox, we want to return null from here and treat them
789 // as "Unresolved" in the caller.
790 if (this.instanceToSourceLocationMapping.TryGetValue(instance, out sourceLocation))
792 return sourceLocation;
800 private void SetPropertyValue(ModelItem oldModelItem, AttachedProperty property, ModelItem newModelItem)
802 // update the previous ModelItem (what was current before)
803 if (oldModelItem != null)
805 property.NotifyPropertyChanged(oldModelItem);
808 // update the current Modelitem
809 if (newModelItem != null)
811 property.NotifyPropertyChanged(newModelItem);
815 private SourceLocation GetSourceLocationFromModelItem(ModelItem modelItem)
817 this.EnsureSourceLocationUpdated();
818 SourceLocation sourceLocation = null;
819 if (modelItem != null)
821 this.modelItemToSourceLocation.TryGetValue(modelItem, out sourceLocation);
823 return sourceLocation;
826 private ModelItem GetModelItemFromSourceLocation(SourceLocation sourceLocation)
828 return GetModelItemFromSourceLocation(sourceLocation, /* forceCreate = */ false);
831 private ModelItem GetModelItemFromSourceLocation(SourceLocation sourceLocation, bool forceCreate)
833 ModelItem modelItem = null;
834 if (sourceLocation != null)
836 if (!this.sourceLocationToModelItem.TryGetValue(sourceLocation, out modelItem))
840 object foundElement = null;
841 foreach (KeyValuePair<object, SourceLocation> kvp in this.instanceToSourceLocationMapping)
843 if (kvp.Value.Equals(sourceLocation))
845 foundElement = kvp.Key;
850 if (foundElement != null)
852 modelItem = Validation.ValidationService.FindModelItem(this.modelTreeManager, foundElement);
854 if (modelItem != null)
856 this.modelItemToSourceLocation.Add(modelItem, sourceLocation);
857 this.sourceLocationToModelItem.Add(sourceLocation, modelItem);