/// <summary> /// Event handler that is called when the document node has disposed or name changed. Because the path to the node can have changed too, /// the path is renewed in this case. The <see cref="OnChanged" /> method is called then for the proxy itself. /// </summary> /// <param name="sender"></param> /// <param name="source"></param> /// <param name="e"></param> private void EhDocNode_TunneledEvent(object sender, object source, Main.TunnelingEventArgs e) { if (IsDisposeInProgress) { return; } #if DEBUG_DOCNODEPROXYLOGGING Current.Console.WriteLine("RelDocNodeProxy.EhDocNode_TunneledEvent: sender={0}, source={1} e={2}", sender, source, e); #endif bool shouldFireChangedEvent = false; var senderAsNode = source as IDocumentLeafNode; if (!(senderAsNode != null)) { throw new InvalidProgramException(); } if (e is DisposeEventArgs) { // when our DocNode was disposed, it is probable that the parent of this node (and further parents) are disposed too // thus we need to watch the first node that is not disposed var docNode = InternalDocNode; ClearDocNode(); if (!(sender is AltaxoDocument)) // if the whole document is disposed, there is no point in trying to watch something { // note Dispose is designed to let the hierarchy from child to parent (root) valid, but not from root to child! // thus trying to get an actual document path here is in must cases unsuccessfull. We have to rely on our stored path, and that it was always updated! // the only case were it is successfull if a new node immediately replaces an old document node var node = RelativeDocumentPath.GetNodeOrLeastResolveableNode(_docNodePath, senderAsNode, out var wasResolvedCompletely); if (wasResolvedCompletely) { InternalSetDocNode(node, _parent); } else { SetWatchOnNode(node); } shouldFireChangedEvent = true; } } else if (e is DocumentPathChangedEventArgs) { if (null != InternalDocNode) { InternalDocumentPath = RelativeDocumentPath.GetRelativePathFromTo(_parent, InternalDocNode); } shouldFireChangedEvent = true; } if (shouldFireChangedEvent) { EhSelfChanged(EventArgs.Empty); } }
/// <summary> /// Sets the document node that is held by this proxy. /// </summary> /// <param name="value">The document node. If <c>docNode</c> implements <see cref="Main.IDocumentLeafNode" />, /// the document path is stored for this object in addition to the object itself.</param> /// <param name="parentNode">The start point of the document path. Should be equal to the member _parent, but this might be not set now.</param> protected void InternalSetDocNode(Main.IDocumentLeafNode value, IDocumentLeafNode parentNode) { if (!IsValidDocument(value)) { throw new ArgumentException("This type of document is not allowed for the proxy of type " + GetType().ToString()); } if (null == parentNode) { throw new InvalidOperationException("Parent of this node must be set in order to set the docnode."); } var oldValue = InternalDocNode; if (object.ReferenceEquals(oldValue, value)) { return; // Nothing to do } if (null != _weakDocNodeChangedHandler) { _weakDocNodeChangedHandler.Remove(); _weakDocNodeChangedHandler = null; } if (null != _weakDocNodeTunneledEventHandler) { _weakDocNodeTunneledEventHandler.Remove(); _weakDocNodeTunneledEventHandler = null; } if (null != oldValue) { ClearDocNode(); } var newPath = RelativeDocumentPath.GetRelativePathFromTo(parentNode, value); if (null != newPath) { InternalDocumentPath = newPath; // especially in dispose situations, the new path can be null. In this case we leave the path as it was } _docNodeRef = new WeakReference(value); #if DEBUG_DOCNODEPROXYLOGGING Current.Console.WriteLine("RelDocNodeProxy.SetDocNode, path is <<{0}>>", _docNodePath); #endif value.TunneledEvent += (_weakDocNodeTunneledEventHandler = new WeakActionHandler <object, object, TunnelingEventArgs>(EhDocNode_TunneledEvent, handler => value.TunneledEvent -= handler)); if (null != _docNodePath && !_docNodePath.IsIdentity) // it does not make sense to watch the changed event of our target node is our parent because the parent can handle the Changed event itself { value.Changed += (_weakDocNodeChangedHandler = new WeakEventHandler(EhDocNode_Changed, handler => value.Changed -= handler)); } OnAfterSetDocNode(); EhSelfChanged(new Main.InstanceChangedEventArgs(oldValue, value)); }
public override void EhParentTunnelingEventHappened(IDocumentNode sender, IDocumentNode originalSource, TunnelingEventArgs e) { // since we deal with relative path, we have to watch changes to our path too if (e is Main.DocumentPathChangedEventArgs) { var node = InternalDocNode; if (null != node) { _docNodePath = RelativeDocumentPath.GetRelativePathFromTo(_parent, node); } } base.EhParentTunnelingEventHappened(sender, originalSource, e); }
/// <summary> /// Event handler that is called when the document node has changed. Because the path to the node can have changed too, /// the path is renewed in this case. The <see cref="OnChanged" /> method is called then for the proxy itself. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void EhDocNode_Changed(object sender, EventArgs e) { if (IsDisposeInProgress) { return; } #if DEBUG_DOCNODEPROXYLOGGING Current.Console.WriteLine("DocNodeProxy.EhDocNode_Changed: sender={0}, e={1}", sender, e); #endif if (null != InternalDocNode) { _docNodePath = RelativeDocumentPath.GetRelativePathFromTo(_parent, InternalDocNode); } EhSelfChanged(EventArgs.Empty); }