// NOTE: The code here is highly similar to AddChildCore in ModelVisual3D, // but slightly different because the parent is 2D here. void IVisual3DContainer.AddChild(Visual3D child) { // It is invalid to modify the children collection that we // might be iterating during a property invalidation tree walk. if (IsVisualChildrenIterationInProgress) { throw new InvalidOperationException(SR.Get(SRID.CannotModifyVisualChildrenDuringTreeWalk)); } // invalid during a VisualTreeChanged event VisualDiagnostics.VerifyVisualTreeChange(this); Debug.Assert(child != null); Debug.Assert(child.InternalVisualParent == null); child.SetParent(this); // set the inheritance context so databinding, etc... work if (_inheritanceContextForChildren != null) { _inheritanceContextForChildren.ProvideSelfAsInheritanceContext(child, null); } SetFlagsOnAllChannels(true, VisualProxyFlags.IsContentDirty); // The child already might be dirty. Hence we need to propagate dirty information // from the parent and from the child. Visual.PropagateFlags( this, VisualFlags.IsSubtreeDirtyForPrecompute, VisualProxyFlags.IsSubtreeDirtyForRender); Visual3D.PropagateFlags( child, VisualFlags.IsSubtreeDirtyForPrecompute, VisualProxyFlags.IsSubtreeDirtyForRender); // // Fire notifications OnVisualChildrenChanged(child, /* visualRemoved = */ null); child.FireOnVisualParentChanged(null); VisualDiagnostics.OnVisualChildChanged(this, child, true); }
/// <summary> /// Invoked when logical parent is changed. This just /// sets the parent pointer. /// </summary> /// <remarks> /// A parent change is considered catastrohpic and results in a large /// amount of invalidations and tree traversals. <cref see="DependencyFastBuild"/> /// is recommended to reduce the work necessary to build a tree /// </remarks> /// <param name="newParent"> /// New parent that was set /// </param> internal void ChangeLogicalParent(DependencyObject newParent) { /////////////////// // OnNewParent: /////////////////// // // -- Approved By The Core Team -- // // Do not allow foreign threads to change the tree. // (This is a noop if this object is not assigned to a Dispatcher.) // // We also need to ensure that the tree is homogenous with respect // to the dispatchers that the elements belong to. // this.VerifyAccess(); if (newParent != null) { newParent.VerifyAccess(); } // Logical Parent must first be dropped before you are attached to a newParent // This mitigates illegal tree state caused by logical child stealing as illustrated in bug 970706 if (_parent != null && newParent != null && _parent != newParent) { throw new System.InvalidOperationException(SR.Get(SRID.HasLogicalParent)); } // Trivial check to avoid loops if (newParent == this) { throw new System.InvalidOperationException(SR.Get(SRID.CannotBeSelfParent)); } // invalid during a VisualTreeChanged event VisualDiagnostics.VerifyVisualTreeChange(this); // Logical Parent implies no InheritanceContext if (newParent != null) { ClearInheritanceContext(); } IsParentAnFE = newParent is FrameworkElement; DependencyObject oldParent = _parent; OnNewParent(newParent); // Update Has[Loaded/Unloaded]Handler Flags BroadcastEventHelper.AddOrRemoveHasLoadedChangeHandlerFlag(this, oldParent, newParent); /////////////////// // OnParentChanged: /////////////////// // Invalidate relevant properties for this subtree DependencyObject parent = (newParent != null) ? newParent : oldParent; TreeWalkHelper.InvalidateOnTreeChange(/* fe = */ this, /* fce = */ null, parent, (newParent != null)); // If no one has called BeginInit then mark the element initialized and fire Initialized event // (non-parser programmatic tree building scenario) TryFireInitialized(); }
// NOTE: The code here is highly similar to RemoveChildCore in ModelVisual3D, // but slightly different because the parent is 2D here. void IVisual3DContainer.RemoveChild(Visual3D child) { int index = child.ParentIndex; // It is invalid to modify the children collection that we // might be iterating during a property invalidation tree walk. if (IsVisualChildrenIterationInProgress) { throw new InvalidOperationException(SR.Get(SRID.CannotModifyVisualChildrenDuringTreeWalk)); } // invalid during a VisualTreeChanged event VisualDiagnostics.VerifyVisualTreeChange(this); Debug.Assert(child != null); Debug.Assert(child.InternalVisualParent == this); VisualDiagnostics.OnVisualChildChanged(this, child, false); child.SetParent(/* newParent = */ (Visual)null); // CS0121: Call is ambigious without casting null to Visual. // remove the inheritance context if (_inheritanceContextForChildren != null) { _inheritanceContextForChildren.RemoveSelfAsInheritanceContext(child, null); } // // Remove the child on all channels this visual is marshalled to. // for (int i = 0, limit = _proxy3D.Count; i < limit; i++) { DUCE.Channel channel = _proxy3D.GetChannel(i); if (child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent)) { child.SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent); DUCE.IResource childResource = (DUCE.IResource)child; childResource.RemoveChildFromParent(this, channel); childResource.ReleaseOnChannel(channel); } } SetFlagsOnAllChannels(true, VisualProxyFlags.IsContentDirty); // // Force a full precompute and render pass for this visual. // Visual.PropagateFlags( this, VisualFlags.IsSubtreeDirtyForPrecompute, VisualProxyFlags.IsSubtreeDirtyForRender); // child.FireOnVisualParentChanged(this); OnVisualChildrenChanged(/* visualAdded = */ null, child); }