Beispiel #1
0
        private void notifyPropertyChanged_PropertyChanging(object sender, PropertyChangingEventArgs e)
        {
            if (!TrackChanges)
            {
                return;
            }

            if (ExcludedTypes.Contains(sender.GetType()))
            {
                return;
            }

            var memento = new NotifyPropertyChangeMemento();

            memento.RememberOldValue(sender, e);

            var key = new PropertyChangeKey {
                Sender = sender, PropertyName = e.PropertyName
            };

            if (propertyChangeMementos.ContainsKey(key))
            {
                throw new InvalidOperationException(string.Format("Property {0} of {1} is already being changed",
                                                                  e.PropertyName, sender));
            }
            propertyChangeMementos[key] = memento;
        }
Beispiel #2
0
        private void notifyPropertyChanged_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (!TrackChanges)
            {
                return;
            }

            if (ExcludedTypes.Contains(sender.GetType()))
            {
                return;
            }

            NotifyPropertyChangeMemento memento;
            var key = new PropertyChangeKey {
                Sender = sender, PropertyName = e.PropertyName
            };

            propertyChangeMementos.TryGetValue(key, out memento);

            if (memento == null)
            {
                throw new NotSupportedException("PropertyChanged received without PropertyChanging");
            }

            memento.RememberNewValue(sender, e);
            propertyChangeMementos.Remove(key);

            // check if we need to add memento to current compound memento or to undoRedoManager
            if (e.PropertyName == "IsEditing")
            {
                var editable = (IEditableObject)memento.Instance;

                if (editable.IsEditing) // BeginEdit()
                {
                    if (currentEditableObjectMemento != null)
                    {
                        editableObjectMementos.Push(currentEditableObjectMemento);
                    }

                    currentEditableObjectMemento = new CompoundMemento {
                        Name = editable.CurrentEditAction.Name
                    };
                    AddMemento(memento);
                }
                else // EndEdit()
                {
                    if (currentEditableObjectMemento == null)
                    {
                        throw new InvalidOperationException("Unexpected end edit call before begin edit");
                    }

                    AddMemento(memento);

                    if (editableObjectMementos.Count == 0)
                    {
                        log.DebugFormat("saving undo for edit action {0}", currentEditableObjectMemento.Name);
                        AddNewMementoCallback(currentEditableObjectMemento);

                        currentEditableObjectMemento = null;
                    }
                    else
                    {
                        // pull previous editable object memento and continue with it as current compound memento
                        var previousEditableObjectMemento = editableObjectMementos.Pop();
                        previousEditableObjectMemento.ChildMementos.Add(currentEditableObjectMemento);
                        currentEditableObjectMemento = previousEditableObjectMemento;
                    }
                }
            }
            else
            {
                if (currentEditableObjectMemento != null)
                {
                    log.DebugFormat("adding property cange to edit action {0}.{1}: {2} -> {3}", sender.GetType().Name,
                                    e.PropertyName, memento.OldValue ?? "null", memento.NewValue ?? "null");
                }
                else
                {
                    log.DebugFormat("saving undo for property cange {0}.{1}: {2} -> {3}", sender.GetType().Name,
                                    e.PropertyName, memento.OldValue ?? "null", memento.NewValue ?? "null");
                }

                AddMemento(memento);
            }
        }
        private void ObservablePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (!TrackChanges)
            {
                return;
            }

            ThrowIfFromDifferentThread();

            if (ExcludedTypes.Contains(sender.GetType()))
            {
                return;
            }

            if (!handlingDisconnected)
            {
                //we got an event through the normal path, so we're sure this object is still connected
                UnsubscribeDisconnected(sender);
            }

            // if virtual property was added - try to handle it
            if(virtualPropertyCalls.Contains(e.PropertyName) && CheckVirtualPropertyNames(sender, e.PropertyName))
            {
                virtualPropertyCalls.Remove(e.PropertyName);
                return; // will be handled in second call (in derived class setter)
            }

            NotifyPropertyChangeMemento memento;
            var key = new PropertyChangeKey(sender, e.PropertyName);
            propertyChangeMementos.TryGetValue(key, out memento);

            if (memento == null)
            {
                // check if it is not something from disconnected objects
                if (propertyChangeMementosDisconnected.ContainsKey(key))
                {
                    propertyChangeMementosDisconnected.Remove(key);
                    return;
                }
                throw new NotSupportedException("PropertyChanged received without PropertyChanging");
            }

            memento.RememberNewValue(sender, e);
            propertyChangeMementos.Remove(key);
            if (!handlingDisconnected && propertyChangeMementosDisconnected.ContainsKey(key))
            {
                propertyChangeMementosDisconnected.Remove(key);
            }

            // exceptional situation, same object!
            lastPropertyChangeMemento = memento;

            if (!TypeUtils.IsAggregationProperty(sender, e.PropertyName))
            {
                if (memento.NewValue != null && ReferenceEquals(memento.OldValue, memento.NewValue))
                {
                    UnsubscribeDisconnected(memento.OldValue);
                }
                UnsubscribeDisconnected(memento.NewValue);
            }

            // check if we need to add memento to current compound memento or to undoRedoManager
            if (e.PropertyName == "IsEditing")
            {
                EditableObjectIsEditingChanged(memento);
            }
            else
            {
                LogPropertyChanged(sender, e, memento);
            }
        }
        private void ObservablePropertyChanging(object sender, PropertyChangingEventArgs e)
        {
            if (!TrackChanges)
            {
                return;
            }
            
            pendingIncrementEventCallCountSender = null;

            ThrowIfFromDifferentThread();

            if (ExcludedTypes.Contains(sender.GetType()))
            {
                return;
            }

            if (!handlingDisconnected)
            {
                //we got an event through the normal path, so we're sure this object is still connected
                UnsubscribeDisconnected(sender);
            }

            FixCancelledCollectionChangingEvents();

            var key = new PropertyChangeKey(sender, e.PropertyName);

            NotifyPropertyChangeMemento existingMemento;
            propertyChangeMementos.TryGetValue(key, out existingMemento);

            if (existingMemento != null)
            {
                // check if property is virtual, if so - show tip how to fix it
                if (CheckVirtualPropertyNames(sender, e.PropertyName))
                {
                    // ignore and add property to the virtual property list so that it can be handled in changed handler
                    virtualPropertyCalls.Add(e.PropertyName);
                    return;
                }
            }

            if (restoringMemento != null)
            {
                if (!IsPropertyChangeEventPartOfRestore(sender, e.PropertyName))
                {
                    if (e.PropertyName != "IsEditing")
                    {
                        throw new InvalidOperationException("Side-effect code detected (code which changes object tree in setters or in event handlers) which is not marked with [EditAction]");
                    }
                }
            }

            if (eventCascadeCallLevel > 1 && !handlingDisconnected)
            {
                if (eventCascadeCallLevel < expectedEventCascadeCallLevel)
                {
                    expectedEventCascadeCallLevel = eventCascadeCallLevel;
                }

                // we must be in a side-effect
                if (expectedEventCascadeCallLevel != eventCascadeCallLevel)
                {
                    LogCascadeLevels();
                    throw new InvalidOperationException("Side-effect code detected (code which changes object tree in setters or in event handlers) which is not marked with [EditAction]");
                }
            }
            
            if (existingMemento != null)
            {
                if(existingMemento.LastEventSenderIsDisconnected || handlingDisconnected)
                {
                    propertyChangeMementosDisconnected[key] = existingMemento;
                    return; // ignore
                }
                
                var oldMemento = propertyChangeMementos[key];

                LogMementoSenders(oldMemento);

                throw new InvalidOperationException(string.Format("Property {0} of {1} is already being changed", e.PropertyName, sender));
            }

            var memento = (NotifyPropertyChangeMemento)mementoStack.Peek();
            memento.RememberOldValue(sender, e);

            propertyChangeMementos[key] = memento;
            
            // debugging
            memento.LastEventSender = EventSettings.LastEventBubbler;
            memento.LastEventSenderIsDisconnected = handlingDisconnected;

            if (!handlingDisconnected && !TypeUtils.IsAggregationProperty(sender, e.PropertyName))
            {
                if (restoringMemento == null)
                {
                    HandleIfTransactional(memento.OldValue, true);
                }

                SubscribeDisconnected(memento.OldValue); // listen to changes in disconnected objects
            }
        }