1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.Activities.Presentation.Model
8 using System.Activities.Presentation.Validation;
9 using System.Collections.Generic;
10 using System.Collections.ObjectModel;
15 [Fx.Tag.XamlVisible(false)]
16 public class EditingScope : ModelEditingScope
18 ModelTreeManager modelTreeManager;
19 EditingScope outerScope;
21 List<Change> appliedChanges;
23 private HashSet<ModelItem> itemsAdded;
24 private HashSet<ModelItem> itemsRemoved;
26 // this is intended for ImmediateEditingScope only
27 private bool? hasEffectiveChanges;
29 internal EditingScope(ModelTreeManager modelTreeManager, EditingScope outerScope)
31 this.modelTreeManager = modelTreeManager;
32 this.changes = new List<Change>();
33 this.outerScope = outerScope;
34 this.HasModelChanges = false;
35 this.itemsAdded = new HashSet<ModelItem>();
36 this.itemsRemoved = new HashSet<ModelItem>();
39 private EditingScope()
43 public bool HasEffectiveChanges
47 if (this.hasEffectiveChanges.HasValue)
49 Fx.Assert(this.GetType() == typeof(ImmediateEditingScope), "we should only set this property on an ImmediateEditingScope");
51 return this.hasEffectiveChanges.Value;
54 return this.appliedChanges != null && this.appliedChanges.Count > 0;
59 Fx.Assert(this.GetType() == typeof(ImmediateEditingScope), "we should only set this property on an ImmediateEditingScope");
61 this.hasEffectiveChanges = value;
65 internal bool HasModelChanges
69 // setter is only expected to be called by EditingScope and ImmediateEditingScope
73 internal bool SuppressUndo
77 return this.suppressUndo;
81 Fx.Assert(!value || this.outerScope == null, "If we are suppressing undo, then we are not nested within another editingScope, otherwise suppress undo won't work.");
82 this.suppressUndo = value;
86 internal ReadOnlyCollection<ModelItem> ItemsAdded
90 return new ReadOnlyCollection<ModelItem>(this.itemsAdded.ToList());
94 internal ReadOnlyCollection<ModelItem> ItemsRemoved
98 return new ReadOnlyCollection<ModelItem>(this.itemsRemoved.ToList());
103 /// Gets or sets whether validation should be suppressed when this EditingScope completes.
105 internal bool SuppressValidationOnComplete
111 public List<Change> Changes
119 internal void EditingScope_ModelItemsAdded(object sender, ModelItemsAddedEventArgs e)
121 this.HandleModelItemsAdded(e.ModelItemsAdded);
124 internal void EditingScope_ModelItemsRemoved(object sender, ModelItemsRemovedEventArgs e)
126 this.HandleModelItemsRemoved(e.ModelItemsRemoved);
129 internal void HandleModelItemsAdded(IEnumerable<ModelItem> modelItems)
131 foreach (ModelItem addedItem in modelItems)
133 if (this.itemsRemoved.Contains(addedItem))
135 this.itemsRemoved.Remove(addedItem);
139 Fx.Assert(!this.itemsAdded.Contains(addedItem), "One ModelItem should not be added more than once.");
140 this.itemsAdded.Add(addedItem);
145 internal void HandleModelItemsRemoved(IEnumerable<ModelItem> modelItems)
147 foreach (ModelItem removedItem in modelItems)
149 if (this.itemsAdded.Contains(removedItem))
151 this.itemsAdded.Remove(removedItem);
155 Fx.Assert(!itemsRemoved.Contains(removedItem), "One ModelItem should not be removed more than once.");
156 this.itemsRemoved.Add(removedItem);
161 protected override void OnComplete()
163 Fx.Assert(this.itemsAdded.Count == 0 && this.itemsRemoved.Count == 0, "There should not be items changed before completed.");
164 this.modelTreeManager.RegisterModelTreeChangeEvents(this);
166 bool modelChangeBegin = false;
169 if (this.outerScope == null)
171 appliedChanges = new List<Change>();
173 // pump all changes, applying changes can add more changes to the end of the change list.
174 while (startIndex < this.Changes.Count)
176 // pickup the new changes
177 List<Change> changesToApply = this.Changes.GetRange(startIndex, this.Changes.Count - startIndex);
178 startIndex = this.Changes.Count;
180 foreach (Change change in changesToApply)
184 if (change is ModelChange && !modelChangeBegin)
186 this.BeginModelChange();
187 modelChangeBegin = true;
192 appliedChanges.Add(change);
196 if (change is ModelChange)
198 this.HasModelChanges = true;
205 outerScope.Changes.AddRange(this.Changes);
210 if (modelChangeBegin)
212 this.EndModelChange();
215 this.modelTreeManager.UnregisterModelTreeChangeEvents(this);
218 this.modelTreeManager.OnEditingScopeCompleted(this);
221 private void BeginModelChange()
223 ValidationService validationService = this.modelTreeManager.Context.Services.GetService<ValidationService>();
224 if (validationService != null)
226 validationService.DeactivateValidation();
230 private void EndModelChange()
232 ValidationService validationService = this.modelTreeManager.Context.Services.GetService<ValidationService>();
233 if (validationService != null)
235 validationService.ActivateValidation();
239 protected override bool CanComplete()
241 return this.modelTreeManager.CanEditingScopeComplete(this);
244 protected override void OnRevert(bool finalizing)
246 bool modelChangeBegin = false;
249 if (this.appliedChanges != null)
251 List<Change> revertChanges = new List<Change>();
252 foreach (Change change in this.appliedChanges)
254 revertChanges.Add(change.GetInverse());
256 revertChanges.Reverse();
257 foreach (Change change in revertChanges)
259 if (change is ModelChange && !modelChangeBegin)
261 this.BeginModelChange();
262 modelChangeBegin = true;
266 this.appliedChanges.RemoveAt(this.appliedChanges.Count - 1);
272 if (modelChangeBegin)
274 this.EndModelChange();
278 this.modelTreeManager.UnregisterModelTreeChangeEvents(this);
279 this.modelTreeManager.OnEditingScopeReverted(this);
282 protected override bool OnException(Exception e)