/// <summary> /// Callback from DescendentsWalker before the nodes children are visited. /// </summary> /// <param name="dependencyObject">node to visit</param> /// <param name="data">data used for the current tree walk</param> /// <returns>returns whether or not the children should be visited</returns> private bool PreVisit(DependencyObject dependencyObject, ProcessingTreeState data, bool visitedViaVisualTree) { Debug.Assert(data != null, "dataBlob is either null or not of ProcessingTreeState type"); bool calledProcessAnnotations = false; SubTreeProcessor processor = GetSubTreeProcessor(dependencyObject); Debug.Assert(processor != null, "SubtreeProcessor can not be null"); // There is always a default processor IList<IAttachedAnnotation> attachedAnnotations = processor.PreProcessNode(dependencyObject, out calledProcessAnnotations); if (attachedAnnotations != null) data.AttachedAnnotations.AddRange(attachedAnnotations); // Combine whether this processor called ProcessAnnotations with the info of its siblings data.CalledProcessAnnotations = data.CalledProcessAnnotations || calledProcessAnnotations; data.Push(); // Returning true here prevents children from being called return !calledProcessAnnotations; }
/// <summary> /// Callback from DescendentsWalker after the nodes children are visited. /// </summary> /// <param name="dependencyObject">node to visit</param> /// <param name="data">data used for the current tree walk</param> /// <returns>return value is ignored</returns> private bool PostVisit(DependencyObject dependencyObject, ProcessingTreeState data, bool visitedViaVisualTree) { Debug.Assert(data != null, "dataBlob is either null or not of ProcessingTreeState type"); bool childrenCalledProcessAnnotations = data.Pop(); SubTreeProcessor processor = GetSubTreeProcessor(dependencyObject); Debug.Assert(processor != null, "SubtreeProcessor can not be null"); bool calledProcessAnnotations = false; IList<IAttachedAnnotation> attachedAnnotations = processor.PostProcessNode(dependencyObject, childrenCalledProcessAnnotations, out calledProcessAnnotations); if (attachedAnnotations != null) data.AttachedAnnotations.AddRange(attachedAnnotations); // This flag is information available to PostVisit calls data.CalledProcessAnnotations = data.CalledProcessAnnotations || calledProcessAnnotations || childrenCalledProcessAnnotations; // This return value is not used by PrePostDescendentsWalker return true; }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// <summary> /// Traverse the element tree starting at subtree and load /// annotations for that subtree. /// </summary> /// <param name="subTree">root of the subtree for which to load annotations</param> /// <returns>list of IAttachedAnnotations that were loaded for 'node'; /// the list will never be null but may be empty</returns> /// <exception cref="ArgumentNullException">subtree is null</exception> internal IList<IAttachedAnnotation> ProcessSubTree(DependencyObject subTree) { if (subTree == null) throw new ArgumentNullException("subTree"); ProcessingTreeState data = new ProcessingTreeState(); PrePostDescendentsWalker<ProcessingTreeState> walker = new PrePostDescendentsWalker<ProcessingTreeState>(TreeWalkPriority.VisualTree, PreVisit, PostVisit, data); walker.StartWalk(subTree); return data.AttachedAnnotations; }