private void EditableObjectIsEditingChanged(NotifyPropertyChangeMemento memento) { var editable = (IEditableObject)memento.Instance; EditableObjectMemento editableObjectMemento = null; var orphanedMementos = RemoveIsEditingMemento(); if (editable.IsEditing) // BeginEdit() { editableObjectMemento = new EditableObjectMemento(editable, editable.CurrentEditAction); mementoStack.Push(editableObjectMemento); //inject EditableObject memento } else // EndEdit() { if (editable.CurrentEditAction == null) { throw new ArgumentException( "CurrentEditAction is null while IsEditing is set to false, two potential causes:\n" + "1. Check the order in EndEdit (first IsEditing false, then CurrentEditAction null)\n" + "2. Check edit actions are not being called recursive (a new edit action starts while another is busy)\n"+ " If the latter is the case, consider using a stack to store nested actions, see for example DataItem\n"); } editableObjectMemento = (EditableObjectMemento)mementoStack.Peek(); if (!ReferenceEquals(editableObjectMemento.Editable, memento.Instance)) { throw new ArgumentException("IsEditing events out of sync: did anyone call BeginEdit in response to another BeginEdit (instead of EndEdit)"); } editableObjectMemento.Done = true; //mark done editableObjectMemento.Cancelled = editable.EditWasCancelled; } // add orphaned mementos to edit action orphanedMementos.ForEach(editableObjectMemento.ChildMementos.Add); LogIsEditingChanged(editable); }
/// <summary> /// Hack in place to filter out useless (but corrupting) property changes caused by data binding refreshes /// TOOLS-7093 /// </summary> /// <param name="memento"></param> /// <returns></returns> private static bool IsDataBindingBogusMemento(NotifyPropertyChangeMemento memento) { var isSameValue = false; if (memento.OldValue is bool) { isSameValue = (bool)memento.OldValue == (bool)memento.NewValue; } if (memento.OldValue is Enum) { isSameValue = (int)memento.OldValue == (int)memento.NewValue; } return isSameValue && (new StackTrace(false).ToString().Contains("Binding.PullData")); }
private void LogPropertyChanged(object sender, PropertyChangedEventArgs e, NotifyPropertyChangeMemento memento) { if (!EventSettings.EnableLogging) return; log.DebugFormat( "{0} {1}.{2}: {3} -> {4} ({5})", InEditableObjectAction() ? "adding property change to edit action" : "saving undo for property change", sender.GetType().Name, e.PropertyName, memento.OldValue ?? "null", memento.NewValue ?? "null", memento.LastEventSender); }
private static void LogMementoSenders(NotifyPropertyChangeMemento oldMemento) { if (!EventSettings.EnableLogging) return; log.DebugFormat("Old event sender: {0} ({1}), current event sender: {2} ({3})", oldMemento.LastEventSender, oldMemento.LastEventSender.GetType(), EventSettings.LastEventBubbler, EventSettings.LastEventBubbler.GetType()); }
private void DisconnectedPropertyChanged(object sender, PropertyChangedEventArgs e) { if (restoringMemento != null) { if (IsPropertyChangeEventPartOfRestore(sender, e.PropertyName)) { handlingDisconnected = true; //track actual changes in disconnected objects ObservablePropertyChanged(sender, e); handlingDisconnected = false; return; } } else { if (InEditAction()) { if (!AlreadySeenEvent(sender, e)) { handlingDisconnected = true; ObservablePropertyChanged(sender, e); // track actual changes in disconnected objects handlingDisconnected = false; } else { // skip already handled event lastPropertyChangeMemento = null; } } } }