AdornerLayer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Documents / AdornerLayer.cs / 1 / AdornerLayer.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: 
//
//              See spec at: http://avalon/uis/Specs/AdornerLayer%20Spec.htm 
//
// History:
//  9/20/2002 susia:      Created (DecoratorContainer)
//  6/11/2003 psarrett:   Ported to WCP tree; merged DecoratorContainer and 
//                        AdornerContainerPresenter into AdornerLayer
//  10/22/2003 psarrett:  Updated as per current spec 
// 
//---------------------------------------------------------------------------
using System; 
using System.Windows.Media;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized; 
using System.Windows.Threading;
using System.Windows.Controls; 
 
using MS.Utility;
using MS.Internal; 
using MS.Internal.Controls;
using MS.Internal.Media;
using Microsoft.Internal.AlphaFlattener; // TransformGeometry()
 
namespace System.Windows.Documents
{ 
    ///  
    /// Visual decoration including but not limited to adornments, rubberband selection and
    /// non-live move feedback. 
    ///
    /// AdornerLayer expects to be parented by an AdornerDecorator.
    /// 
    public class AdornerLayer : FrameworkElement 
    {
        ///  
        /// Adorner information 
        /// 
        internal class AdornerInfo 
        {
            /// 
            /// Constructor
            ///  
            internal AdornerInfo(Adorner adorner)
            { 
                Invariant.Assert(adorner != null); 

                _adorner = adorner; 
            }

            /// 
            /// Adorner 
            /// 
            internal Adorner Adorner 
            { 
                get
                { 
                    return _adorner;
                }
            }
 
            /// 
            /// The RenderSize (bounding box) of the object we're adorning 
            ///  
            internal Size RenderSize
            { 
                get
                {
                    return _computedSize;
                } 
                set
                { 
                    _computedSize = value; 
                }
            } 

            /// 
            /// Transform on the Visual
            ///  
            internal GeneralTransform Transform
            { 
                get 
                {
                    return _transform; 
                }
                set
                {
                    _transform = value; 
                }
            } 
 
            internal int ZOrder
            { 
                get
                {
                    return _zOrder;
                } 
                set
                { 
                    _zOrder = value; 
                }
            } 

            internal Geometry Clip
            {
                get 
                {
                    return _clip; 
                } 
                set
                { 
                    _clip = value;
                }
            }
 
            private Adorner _adorner;
            private Size _computedSize; 
            private GeneralTransform _transform; 
            private int _zOrder;
            private Geometry _clip; 
        }

        //-----------------------------------------------------
        // 
        //  Constructors
        // 
        //----------------------------------------------------- 

        #region Constructors 

        /// 
        /// Constructor
        ///  
        /// 
        /// Note that because we're setting up an event handler here, we won't be GC'd until 
        /// our parent is GC'd.  So the implicit assumption is that the AdornerLayer, once 
        /// created, exists until its parent is deleted.
        ///  
        internal AdornerLayer() : this(Dispatcher.CurrentDispatcher)
        {
        }
 
        /// 
        /// Constructor 
        ///  
        /// Dispatcher
        ///  
        /// Note that because we're setting up an event handler here, we won't be GC'd until
        /// our parent is GC'd.  So the implicit assumption is that the AdornerLayer, once
        /// created, exists until its parent is deleted.
        ///  
        internal AdornerLayer(Dispatcher context)
        { 
            if (context == null) 
                throw new ArgumentNullException("context");
 
            LayoutUpdated += new EventHandler(OnLayoutUpdated);
            _children = new VisualCollection(this);
        }
 
        #endregion Constructors
 
        //------------------------------------------------------ 
        //
        //  Public Methods 
        //
        //-----------------------------------------------------

        #region Public Methods 

        ///  
        /// Add given Adorner to our children 
        /// 
        /// Adorner to add 
        public void Add(Adorner adorner)
        {
            Add(adorner, DefaultZOrder);
        } 

        ///  
        /// Remove given adorner.  This method will not complain if the given adorner is not 
        /// in the AdornerLayer.
        ///  
        /// adorner to remove
        public void Remove(Adorner adorner)
        {
            if (adorner == null) 
                throw new ArgumentNullException("adorner");
 
            ArrayList adornerInfos = ElementMap[adorner.AdornedElement] as ArrayList; 
            if (adornerInfos == null)
            { 
                // We currently allow adorners to be added on elements that can't be adorned, then
                // throw those away later without notifying anyone.  Consequently, Remove() shouldn't throw.
                return;
            } 
            AdornerInfo adornerInfo = GetAdornerInfo(adornerInfos, adorner);
            if (adornerInfo == null) 
            { 
                // We currently allow adorners to be added on elements that can't be adorned, then
                // throw those away later without notifying anyone.  Consequently, Remove() shouldn't throw. 
                return;
            }

            RemoveAdornerInfo(ElementMap, adorner, adorner.AdornedElement); 
            RemoveAdornerInfo(_zOrderMap, adorner, adornerInfo.ZOrder);
            _children.Remove(adorner); 
            RemoveLogicalChild(adorner); 
        }
 
        /// 
        /// Update (layout and render) all adorners.
        /// 
        public void Update() 
        {
            foreach (UIElement key in ElementMap.Keys) 
            { 
                ArrayList adornerInfos = (ArrayList)ElementMap[key];
                int i = 0; 

                if (adornerInfos != null)
                {
                    while (i < adornerInfos.Count) 
                    {
                        InvalidateAdorner((AdornerInfo)adornerInfos[i++]); 
                    } 
                }
            } 

            UpdateAdorner(null);
        }
 
        /// 
        /// Update (layout and render) all adorners for the given element. 
        ///  
        /// element key for redraw
        public void Update(UIElement element) 
        {
            if (element == null)
                throw new ArgumentNullException("element");
 
            ArrayList adornerInfos = ElementMap[element] as ArrayList;
 
            if (adornerInfos == null) 
                throw new InvalidOperationException(SR.Get(SRID.AdornedElementNotFound));
 
            int i = 0;

            while (i < adornerInfos.Count)
            { 
                InvalidateAdorner((AdornerInfo)adornerInfos[i++]);
            } 
 
            UpdateAdorner(element);
        } 

        /// 
        /// Return a collection of all adorners adorning the given element
        ///  
        /// Element for which adorners are to be retrieved
        /// array of adorners on given element, or null if 
        /// no adorners exist 
        public Adorner[] GetAdorners(UIElement element)
        { 
            if (element == null)
                throw new ArgumentNullException("element");

            ArrayList adornerInfos = ElementMap[element] as ArrayList; 

            if (adornerInfos == null || adornerInfos.Count == 0) 
                return null; 

            Adorner[] adorners = new Adorner[adornerInfos.Count]; 

            for (int i = 0; i < adornerInfos.Count; i++)
                adorners[i] = ((AdornerInfo)adornerInfos[i]).Adorner;
 
            return adorners;
        } 
 
        /// 
        /// Determine if the given point is on an adorner. 
        /// 
        /// point to test
        /// AdornerHitTestResult containing the hit visual and the adorner that visual
        /// is part of.  If the no adorner was hit, null is returned 
        public AdornerHitTestResult AdornerHitTest(Point point)
        { 
            PointHitTestResult result = VisualTreeUtils.AsNearestPointHitTestResult(VisualTreeHelper.HitTest(this, point, false)); 

            if (result != null && result.VisualHit != null) 
            {
                Visual visual = result.VisualHit;

                while (visual != this) 
                {
                    if (visual is Adorner) 
                        return new AdornerHitTestResult(result.VisualHit, result.PointHit, visual as Adorner); 

                    // we intentionally separate adorners from spanning 3D boundaries 
                    // and if the parent is ever 3D there was a mistake
                    visual = (Visual)VisualTreeHelper.GetParent(visual);
                }
 
                return null;
            } 
            else 
            {
                return null; 
            }
        }

        ///  
        /// Walk up the visual tree to find the nearest AdornerLayer.
        ///  
        /// Visual from which the treewalk begins 
        /// First AdornerLayer above given element, or null
        static public AdornerLayer GetAdornerLayer(Visual visual) 
        {
            if (visual == null)
                throw new ArgumentNullException("visual");
 
            Visual parent = VisualTreeHelper.GetParent(visual) as Visual;
 
            while (parent != null) 
            {
                if (parent is AdornerDecorator) 
                    return ((AdornerDecorator)parent).AdornerLayer;
                if (parent is ScrollContentPresenter)
                    return ((ScrollContentPresenter)parent).AdornerLayer;
 
                parent = VisualTreeHelper.GetParent(parent) as Visual;
            } 
 
            return null;
        } 

        #endregion Public Methods

        //------------------------------------------------------ 
        //
        //  Public Properties 
        // 
        //------------------------------------------------------
 
        #region Public Properties

        #endregion Public Properties
 
        //-----------------------------------------------------
        // 
        //  Public Events 
        //
        //------------------------------------------------------ 
        //-----------------------------------------------------
        //
        //  Protected Methods
        // 
        //-----------------------------------------------------
 
        #region Protected Methods 

 
        /// 
        ///  Derived classes override this property to enable the Visual code to enumerate
        ///  the Visual children. Derived classes need to return the number of children
        ///  from this method. 
        ///
        ///    By default a Visual does not have any children. 
        /// 
        ///  Remark:
        ///      During this virtual method the Visual tree must not be modified. 
        /// 
        protected override int VisualChildrenCount
        {
            get 
            {
                //_children cannot be null as its initialized in the constructor 
                return _children.Count; 
            }
        } 

        /// 
        ///   Derived class must implement to support Visual children. The method must return
        ///    the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. 
        ///
        ///    By default a Visual does not have any children. 
        /// 
        ///  Remark:
        ///       During this virtual call it is not valid to modify the Visual tree. 
        /// 
        protected override Visual GetVisualChild(int index)
        {
            //_children cannot be null as its initialized in the constructor 
            // index range check done by VisualCollection
            return _children[index]; 
        } 

        ///  
        /// Returns enumerator to logical children.
        /// 
        protected internal override IEnumerator LogicalChildren
        { 
            get
            { 
                if ((this.VisualChildrenCount == 0)) 
                {
                    return EmptyEnumerator.Instance; 
                }

                return _children.GetEnumerator();
            } 
        }
        ///  
        /// AdornerLayer always returns a size of (0,0). 
        /// The AdornerLayer's size should be the same as its parent, but not take up layout space.  This means
        /// parents containing an AdornerLayer should stretch it to their own size. 
        /// 
        /// 
        /// Sizing constraint.
        ///  
        protected override Size MeasureOverride(Size constraint)
        { 
            // Not using an enumerator because the list can be modified during the loop when we call out. 
            DictionaryEntry[] zOrderMapEntries = new DictionaryEntry[_zOrderMap.Count];
            _zOrderMap.CopyTo(zOrderMapEntries, 0); 

            for (int i = 0; i < zOrderMapEntries.Length; i++)
            {
                ArrayList adornerInfos = (ArrayList)zOrderMapEntries[i].Value; 
                Debug.Assert(adornerInfos != null, "No adorners found for element in AdornerLayer._zOrderMap");
 
                int j = 0; 
                while (j < adornerInfos.Count)
                { 
                    AdornerInfo adornerInfo = (AdornerInfo)adornerInfos[j++];
                    adornerInfo.Adorner.Measure(constraint);
                }
            } 

            // Returning 0,0 prevents an invalidation of Measure for AdornerLayer from unnecessarily dirtying the parent. 
            return new Size(); 
        }
 
        /// 
        /// Override for 
        /// 
        ///  
        /// We need information from AdornerInfo.  Since we keep one AdornerInfo per
        /// Adorner, and we expect a 1:1 mapping between Adorners and our visual children, 
        /// it makes more sense for us to iterate across AdornerInfos instead of 
        /// our visual children here.  This means that if someone somehow adds a non-Adorner
        /// child to AdornerLayer, it will never render. 
        /// 
        /// The location reserved for this element by the parent
        protected override Size ArrangeOverride(Size finalSize)
        { 
            // Not using an enumerator because the list can be modified during the loop when we call out.
            DictionaryEntry[] zOrderMapEntries = new DictionaryEntry[_zOrderMap.Count]; 
            _zOrderMap.CopyTo(zOrderMapEntries, 0); 

            for (int i = 0; i < zOrderMapEntries.Length; i++) 
            {
                ArrayList adornerInfos = (ArrayList)zOrderMapEntries[i].Value;

                Debug.Assert(adornerInfos != null, "No adorners found for element in AdornerLayer._zOrderMap"); 

                int j = 0; 
                while (j < adornerInfos.Count) 
                {
                    AdornerInfo adornerInfo = (AdornerInfo)adornerInfos[j++]; 

                    if (!adornerInfo.Adorner.IsArrangeValid)    // optimization
                    {
                        // We're dependent on Arrange to get the rendersize of the adorner, so Arrange before 
                        // doing our transform magic.
                        adornerInfo.Adorner.Arrange(new Rect(new Point(), adornerInfo.Adorner.DesiredSize)); 
                        GeneralTransform proposedTransform = adornerInfo.Adorner.GetDesiredTransform(adornerInfo.Transform); 
                        GeneralTransform adornerTransform = GetProposedTransform(adornerInfo.Adorner, proposedTransform);
 
                        int index = _children.IndexOf(adornerInfo.Adorner);

                        if (index >= 0)
                        { 
                            // Get the matrix transform out, skip all non affine transforms
                            Transform transform = (adornerTransform != null) ? adornerTransform.AffineTransform : null; 
 
                            ((Adorner)(_children[index])).AdornerTransform = transform;
                        } 
                    }
                    if (adornerInfo.Adorner.IsClipEnabled)
                    {
                        adornerInfo.Adorner.AdornerClip = adornerInfo.Clip; 
                    }
                    else if (adornerInfo.Adorner.AdornerClip != null) 
                    { 
                        adornerInfo.Adorner.AdornerClip = null;
                    } 
                }
            }

            return finalSize; 
        }
 
        #endregion Protected Methods 

        //----------------------------------------------------- 
        //
        //  Internal Methods
        //
        //------------------------------------------------------ 

        #region Internal Methods 
 
        /// 
        /// Add given Adorner to our children 
        /// 
        /// Adorner to add
        /// z-order
        internal void Add(Adorner adorner, int zOrder) 
        {
            if (adorner == null) 
                throw new ArgumentNullException("adorner"); 

            AdornerInfo adornerInfo = new AdornerInfo(adorner); 
            adornerInfo.ZOrder = zOrder;

            AddAdornerInfo(ElementMap, adornerInfo, adorner.AdornedElement);
 
            AddAdornerToVisualTree(adornerInfo, zOrder);
 
            AddLogicalChild(adorner); 

            UpdateAdorner(adorner.AdornedElement); 
        }

        /// 
        /// Clean all the dynamically-updated data from the Adorner 
        /// 
        /// AdornerInfo to scrub 
        internal void InvalidateAdorner(AdornerInfo adornerInfo) 
        {
            Debug.Assert(adornerInfo != null, "Adorner should not be null"); 
            adornerInfo.Adorner.InvalidateMeasure();
            adornerInfo.Adorner.InvalidateVisual();
            adornerInfo.RenderSize = new Size(Double.NaN, Double.NaN);
            adornerInfo.Transform = null; 
        }
 
        ///  
        /// OnLayoutUpdated event handler
        ///  
        /// 
        /// 
        internal void OnLayoutUpdated(object sender, EventArgs args)
        { 
            if (ElementMap.Count == 0)
                return; 
 
            UpdateAdorner(null);
        } 

        /// 
        /// Set the zOrder on the given adorner.
        ///  
        /// 
        ///  
        internal void SetAdornerZOrder(Adorner adorner, int zOrder) 
        {
            ArrayList adornerInfos = ElementMap[adorner.AdornedElement] as ArrayList; 
            if (adornerInfos == null)
            {
                throw new InvalidOperationException(SR.Get(SRID.AdornedElementNotFound));
            } 
            AdornerInfo adornerInfo = GetAdornerInfo(adornerInfos, adorner);
            if (adornerInfo == null) 
            { 
                throw new InvalidOperationException(SR.Get(SRID.AdornerNotFound));
            } 

            RemoveAdornerInfo(_zOrderMap, adorner, adornerInfo.ZOrder);
            _children.Remove(adorner);
            adornerInfo.ZOrder = zOrder; 
            AddAdornerToVisualTree(adornerInfo, zOrder);
            InvalidateAdorner(adornerInfo); 
            UpdateAdorner(adorner.AdornedElement); 
        }
 
        /// 
        /// Query the zOrder on the given adorner.
        /// 
        ///  
        /// zOrder of given adorner
        internal int GetAdornerZOrder(Adorner adorner) 
        { 
            ArrayList adornerInfos = ElementMap[adorner.AdornedElement] as ArrayList;
            if (adornerInfos == null) 
            {
                throw new InvalidOperationException(SR.Get(SRID.AdornedElementNotFound));
            }
            AdornerInfo adornerInfo = GetAdornerInfo(adornerInfos, adorner); 
            if (adornerInfo == null)
            { 
                throw new InvalidOperationException(SR.Get(SRID.AdornerNotFound)); 
            }
 
            return adornerInfo.ZOrder;
        }

        #endregion Internal methods 

        //----------------------------------------------------- 
        // 
        //  Internal Properties
        // 
        //------------------------------------------------------

        #region Internal Properties
 
        internal HybridDictionary ElementMap
        { 
            get { return this._elementMap; } 
        }
 
        #endregion Internal Properties

        //------------------------------------------------------
        // 
        //  Internal Events
        // 
        //----------------------------------------------------- 
        //------------------------------------------------------
        // 
        //  Private Methods
        //
        //-----------------------------------------------------
 
        #region Private Methods
 
        ///  
        /// Adds the given adorner to the visual tree in the proper zOrder order.
        ///  
        /// 
        /// 
        private void AddAdornerToVisualTree(AdornerInfo adornerInfo, int zOrder)
        { 
            Adorner adorner = adornerInfo.Adorner;
            Debug.Assert(adorner != null); 
 
            AddAdornerInfo(_zOrderMap, adornerInfo, zOrder);
 
            // We've already added the adorner to the zOrderMap, so we can't get null back
            ArrayList adornerInfos = (ArrayList)_zOrderMap[zOrder];
            if (adornerInfos.Count > 1)
            { 
                // The easy case.  Find the index of the adorner immediately in front of the
                // new one and insert the new one after it. 
                int index = adornerInfos.IndexOf(adornerInfo); 
                int insertionIndex = _children.IndexOf(((AdornerInfo)adornerInfos[index - 1]).Adorner) + 1;
                _children.Insert(insertionIndex, adorner); 
            }
            else
            {
                // The hard case.  Find the set of adorners with the closest, but lower, zOrder. 
                IList keys = _zOrderMap.GetKeyList();
                int index = keys.IndexOf(zOrder) - 1; 
                if (index < 0) 
                {
                    // nothing's lower than the new adorner.  Make it the first child. 
                    _children.Insert(0, adorner);
                }
                else
                { 
                    // find the last adorner at this zOrder and add the new one after it.
                    adornerInfos = (ArrayList)_zOrderMap[keys[index]]; 
                    int insertionIndex = _children.IndexOf(((AdornerInfo)adornerInfos[adornerInfos.Count - 1]).Adorner) + 1; 
                    _children.Insert(insertionIndex, adorner);
                } 
            }
        }

        ///  
        /// Remove all adorners for the given element
        ///  
        /// element key for removal 
        private void Clear(UIElement element)
        { 
            if (element == null)
                throw new ArgumentNullException("element");

            ArrayList adornerInfos = ElementMap[element] as ArrayList; 

            if (adornerInfos == null) 
                throw new InvalidOperationException(SR.Get(SRID.AdornedElementNotFound)); 

            while (adornerInfos.Count > 0) 
            {
                AdornerInfo info = adornerInfos[0] as AdornerInfo;

                Remove(info.Adorner); 
            }
 
            ElementMap.Remove(element); 
        }
 
        /// 
        /// Update the Adorners for the given element
        /// 
        /// UIElement for which we're updating AdornerSet 
        private void UpdateElementAdorners(UIElement element)
        { 
            Size size; 

            // we intentionally do not ascend in to a 3D scene 
            Visual adornerLayerParent = VisualTreeHelper.GetParent(this) as Visual;
            if (adornerLayerParent == null)
            {
                return; 
            }
 
            Debug.Assert(element != null); 
            ArrayList adornerInfos = ElementMap[element] as ArrayList;
            if (adornerInfos == null) 
            {
                return;
            }
 
            bool dirty = false;
 
            // 
            // See if the adorners need to be rerendered due to object resizing
            // 
            GeneralTransform transform = element.TransformToAncestor(adornerLayerParent);

            for (int i = 0; i < adornerInfos.Count; i++)
            { 
                AdornerInfo adornerInfo = (AdornerInfo)adornerInfos[i];
                size = element.RenderSize; 
                Geometry clip = null; 
                bool clipChanged = false;
                if (adornerInfo.Adorner.IsClipEnabled) 
                {
                    clip = GetClipGeometry(adornerInfo.Adorner.AdornedElement, adornerInfo.Adorner);
                    if (adornerInfo.Clip == null && clip != null || adornerInfo.Clip != null && clip == null ||
                     (adornerInfo.Clip != null && clip != null && adornerInfo.Clip.Bounds != clip.Bounds)) 
                    {
                        clipChanged = true; 
                    } 
                }
 
                if (adornerInfo.Adorner.NeedsUpdate(adornerInfo.RenderSize) || adornerInfo.Transform == null ||
                    transform.AffineTransform == null || adornerInfo.Transform.AffineTransform == null ||
                    transform.AffineTransform.Value != adornerInfo.Transform.AffineTransform.Value ||
                    clipChanged) 
                {
                    InvalidateAdorner(adornerInfo); 
                    adornerInfo.RenderSize = size; 
                    adornerInfo.Transform = transform;
                    if (adornerInfo.Adorner.IsClipEnabled) 
                    {
                        adornerInfo.Clip = clip;
                    }
                    dirty = true; 
                }
            } 
 
            if (dirty)
                InvalidateMeasure(); 
        }

        /// 
        /// Update the Adorner for the given element 
        /// 
        /// UIElement for which we're updating AdornerSet 
        private void UpdateAdorner(UIElement element) 
        {
            Visual adornerLayerParent = VisualTreeHelper.GetParent(this) as Visual; 
            if (adornerLayerParent == null)
            {
                // Never update when the adorner layer is not part of a visual tree.
                return; 
            }
 
            // We only expect one to have been removed on any one call. 
            ArrayList removeList = new ArrayList(1);
 
            if (element != null)
            {
                // Make sure element is still beneath the adorner decorator
                if (!element.IsDescendantOf(adornerLayerParent)) 
                {
                    removeList.Add(element); 
                } 
                else
                { 
                    UpdateElementAdorners(element);
                }
            }
            else 
            {
                ICollection keyCollection = ElementMap.Keys; 
                UIElement[] keys = new UIElement[keyCollection.Count]; 
                keyCollection.CopyTo(keys, 0);  // make a static copy of the keys to prevent any possible enumerator exceptions
 
                for (int i = 0; i < keys.Length; i++)
                {
                    UIElement elTemp = (UIElement)keys[i];
 
                    // Make sure element is still beneath the adorner decorator
                    if (!elTemp.IsDescendantOf(adornerLayerParent)) 
                    { 
                        removeList.Add(elTemp);
                    } 
                    else
                    {
                        UpdateElementAdorners(elTemp);
                    } 
                }
            } 
 
            for (int i = 0; i < removeList.Count; i++)
            { 
                Clear((UIElement)removeList[i]);
            }
        }
 
        /// 
        /// Walk up the tree from the adorned element to the AdornerLayer's parent, accumulating 
        /// clip geometries as we go.  Called when IsClipEnabled == true to allow an adorner 
        /// to be clipped (which normally, it isn't).
        ///  
        private CombinedGeometry GetClipGeometry(Visual element, Adorner adorner)
        {
            Visual oldElement = null;
 
            // we intentionally do not ascend in to a 3D scene
            Visual adornerLayerParent = VisualTreeHelper.GetParent(this) as Visual; 
            if (adornerLayerParent == null) 
            {
                return null; 
            }

            CombinedGeometry combinedGeometry = null;
 
            // If the element has been removed from the tree and we've not yet had a chance
            // to remove the adorner, there's obviously no clipping 
            if (!adornerLayerParent.IsAncestorOf(element)) 
            {
                return null; 
            }

            while (element != adornerLayerParent && element != null)
            { 
                Geometry geometry = VisualTreeHelper.GetClip(element);
                if (geometry != null) 
                { 
                    if (combinedGeometry == null)
                    { 
                        combinedGeometry = new CombinedGeometry(geometry, null);
                    }
                    else
                    { 
                        GeneralTransform transform = oldElement.TransformToAncestor(element);
                        combinedGeometry.Transform = transform.AffineTransform; 
                        combinedGeometry = new CombinedGeometry(combinedGeometry, geometry); 
                        combinedGeometry.GeometryCombineMode = GeometryCombineMode.Intersect;
                    } 
                    oldElement = element;
                }

                // we intentionally separate adorners from spanning 3D boundaries 
                // and if the parent is ever 3D there was a mistake
                element = (Visual)VisualTreeHelper.GetParent(element); 
            } 
            if (combinedGeometry != null)
            { 
                // transform the last combined geometry up to the top
                GeneralTransform transform = oldElement.TransformToAncestor(adornerLayerParent);
                if (transform == null)
                { 
                    combinedGeometry = null;
                } 
                else 
                {
                    TransformGroup transformGroup = new TransformGroup(); 
                    transformGroup.Children.Add(transform.AffineTransform);

                    // Now transform back down to the adorner
                    transform = adornerLayerParent.TransformToDescendant(adorner); 
                    if (transform == null)
                    { 
                        combinedGeometry = null; 
                    }
                    else 
                    {
                        transformGroup.Children.Add(transform.AffineTransform);
                        combinedGeometry.Transform = transformGroup;
                    } 
                }
            } 
 
            return combinedGeometry;
        } 

        /// 
        /// Remove the given adorner's AdornerInfo from the given AdornerInfo list.
        ///  
        /// dictionary of adornerInfo
        /// adorner 
        /// key 
        /// true if info was found and removed
        private bool RemoveAdornerInfo(IDictionary infoMap, Adorner adorner, object key) 
        {
            ArrayList adornerInfos = infoMap[key] as ArrayList;

            if (adornerInfos != null) 
            {
                AdornerInfo adornerInfo = GetAdornerInfo(adornerInfos, adorner); 
                if (adornerInfo != null) 
                {
                    adornerInfos.Remove(adornerInfo); 
                    if (adornerInfos.Count == 0)
                    {
                        infoMap.Remove(key);
                    } 
                    return true;
                } 
            } 
            return false;
        } 

        private AdornerInfo GetAdornerInfo(ArrayList adornerInfos, Adorner adorner)
        {
            if (adornerInfos != null) 
            {
                int i = 0; 
 
                while (i < adornerInfos.Count)
                { 
                    if (((AdornerInfo)adornerInfos[i]).Adorner == adorner)
                    {
                        return (AdornerInfo)adornerInfos[i];
                    } 
                    i++;
                } 
            } 
            return null;
        } 

        private void AddAdornerInfo(IDictionary infoMap, AdornerInfo adornerInfo, object key)
        {
            ArrayList adornerInfos; 

            if (infoMap[key] == null) 
            { 
                adornerInfos = new ArrayList(1);
                infoMap[key] = adornerInfos; 
            }
            else
            {
                adornerInfos = (ArrayList)infoMap[key]; 
            }
            adornerInfos.Add(adornerInfo); 
        } 

        // 
        //  This property
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
        //  2. This is a performance optimization
        // 
        internal override int EffectiveValuesInitialSize
        { 
            get { return 4; } 
        }
 
        GeneralTransform GetProposedTransform(Adorner adorner, GeneralTransform sourceTransform)
        {
            // Flip horizontally if Right to Left.
            if (adorner.FlowDirection != this.FlowDirection) 
            {
                GeneralTransformGroup group; 
                MatrixTransform matrixTransform; 
                Matrix matrix;
 
                group = new GeneralTransformGroup();

                matrix = new Matrix(-1.0, 0.0, 0.0, 1.0, adorner.RenderSize.Width, 0.0);
                matrixTransform = new MatrixTransform(matrix); 
                group.Children.Add(matrixTransform);
 
                if (sourceTransform != null && sourceTransform != Transform.Identity) 
                {
                    group.Children.Add(sourceTransform); 
                }

                return group;
            } 

            return sourceTransform; 
        } 

        #endregion Private methods 

        //-----------------------------------------------------
        //
        //  Private Properties 
        //
        //----------------------------------------------------- 
        //------------------------------------------------------ 
        //
        //  Private Fields 
        //
        //-----------------------------------------------------

        #region Private Fields 

        private HybridDictionary _elementMap = new HybridDictionary(10); 
        private SortedList _zOrderMap = new SortedList(10); 
        private const int DefaultZOrder = System.Int32.MaxValue;
        private VisualCollection _children; 

        #endregion Private Fields
    }
} 

 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: 
//
//              See spec at: http://avalon/uis/Specs/AdornerLayer%20Spec.htm 
//
// History:
//  9/20/2002 susia:      Created (DecoratorContainer)
//  6/11/2003 psarrett:   Ported to WCP tree; merged DecoratorContainer and 
//                        AdornerContainerPresenter into AdornerLayer
//  10/22/2003 psarrett:  Updated as per current spec 
// 
//---------------------------------------------------------------------------
using System; 
using System.Windows.Media;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized; 
using System.Windows.Threading;
using System.Windows.Controls; 
 
using MS.Utility;
using MS.Internal; 
using MS.Internal.Controls;
using MS.Internal.Media;
using Microsoft.Internal.AlphaFlattener; // TransformGeometry()
 
namespace System.Windows.Documents
{ 
    ///  
    /// Visual decoration including but not limited to adornments, rubberband selection and
    /// non-live move feedback. 
    ///
    /// AdornerLayer expects to be parented by an AdornerDecorator.
    /// 
    public class AdornerLayer : FrameworkElement 
    {
        ///  
        /// Adorner information 
        /// 
        internal class AdornerInfo 
        {
            /// 
            /// Constructor
            ///  
            internal AdornerInfo(Adorner adorner)
            { 
                Invariant.Assert(adorner != null); 

                _adorner = adorner; 
            }

            /// 
            /// Adorner 
            /// 
            internal Adorner Adorner 
            { 
                get
                { 
                    return _adorner;
                }
            }
 
            /// 
            /// The RenderSize (bounding box) of the object we're adorning 
            ///  
            internal Size RenderSize
            { 
                get
                {
                    return _computedSize;
                } 
                set
                { 
                    _computedSize = value; 
                }
            } 

            /// 
            /// Transform on the Visual
            ///  
            internal GeneralTransform Transform
            { 
                get 
                {
                    return _transform; 
                }
                set
                {
                    _transform = value; 
                }
            } 
 
            internal int ZOrder
            { 
                get
                {
                    return _zOrder;
                } 
                set
                { 
                    _zOrder = value; 
                }
            } 

            internal Geometry Clip
            {
                get 
                {
                    return _clip; 
                } 
                set
                { 
                    _clip = value;
                }
            }
 
            private Adorner _adorner;
            private Size _computedSize; 
            private GeneralTransform _transform; 
            private int _zOrder;
            private Geometry _clip; 
        }

        //-----------------------------------------------------
        // 
        //  Constructors
        // 
        //----------------------------------------------------- 

        #region Constructors 

        /// 
        /// Constructor
        ///  
        /// 
        /// Note that because we're setting up an event handler here, we won't be GC'd until 
        /// our parent is GC'd.  So the implicit assumption is that the AdornerLayer, once 
        /// created, exists until its parent is deleted.
        ///  
        internal AdornerLayer() : this(Dispatcher.CurrentDispatcher)
        {
        }
 
        /// 
        /// Constructor 
        ///  
        /// Dispatcher
        ///  
        /// Note that because we're setting up an event handler here, we won't be GC'd until
        /// our parent is GC'd.  So the implicit assumption is that the AdornerLayer, once
        /// created, exists until its parent is deleted.
        ///  
        internal AdornerLayer(Dispatcher context)
        { 
            if (context == null) 
                throw new ArgumentNullException("context");
 
            LayoutUpdated += new EventHandler(OnLayoutUpdated);
            _children = new VisualCollection(this);
        }
 
        #endregion Constructors
 
        //------------------------------------------------------ 
        //
        //  Public Methods 
        //
        //-----------------------------------------------------

        #region Public Methods 

        ///  
        /// Add given Adorner to our children 
        /// 
        /// Adorner to add 
        public void Add(Adorner adorner)
        {
            Add(adorner, DefaultZOrder);
        } 

        ///  
        /// Remove given adorner.  This method will not complain if the given adorner is not 
        /// in the AdornerLayer.
        ///  
        /// adorner to remove
        public void Remove(Adorner adorner)
        {
            if (adorner == null) 
                throw new ArgumentNullException("adorner");
 
            ArrayList adornerInfos = ElementMap[adorner.AdornedElement] as ArrayList; 
            if (adornerInfos == null)
            { 
                // We currently allow adorners to be added on elements that can't be adorned, then
                // throw those away later without notifying anyone.  Consequently, Remove() shouldn't throw.
                return;
            } 
            AdornerInfo adornerInfo = GetAdornerInfo(adornerInfos, adorner);
            if (adornerInfo == null) 
            { 
                // We currently allow adorners to be added on elements that can't be adorned, then
                // throw those away later without notifying anyone.  Consequently, Remove() shouldn't throw. 
                return;
            }

            RemoveAdornerInfo(ElementMap, adorner, adorner.AdornedElement); 
            RemoveAdornerInfo(_zOrderMap, adorner, adornerInfo.ZOrder);
            _children.Remove(adorner); 
            RemoveLogicalChild(adorner); 
        }
 
        /// 
        /// Update (layout and render) all adorners.
        /// 
        public void Update() 
        {
            foreach (UIElement key in ElementMap.Keys) 
            { 
                ArrayList adornerInfos = (ArrayList)ElementMap[key];
                int i = 0; 

                if (adornerInfos != null)
                {
                    while (i < adornerInfos.Count) 
                    {
                        InvalidateAdorner((AdornerInfo)adornerInfos[i++]); 
                    } 
                }
            } 

            UpdateAdorner(null);
        }
 
        /// 
        /// Update (layout and render) all adorners for the given element. 
        ///  
        /// element key for redraw
        public void Update(UIElement element) 
        {
            if (element == null)
                throw new ArgumentNullException("element");
 
            ArrayList adornerInfos = ElementMap[element] as ArrayList;
 
            if (adornerInfos == null) 
                throw new InvalidOperationException(SR.Get(SRID.AdornedElementNotFound));
 
            int i = 0;

            while (i < adornerInfos.Count)
            { 
                InvalidateAdorner((AdornerInfo)adornerInfos[i++]);
            } 
 
            UpdateAdorner(element);
        } 

        /// 
        /// Return a collection of all adorners adorning the given element
        ///  
        /// Element for which adorners are to be retrieved
        /// array of adorners on given element, or null if 
        /// no adorners exist 
        public Adorner[] GetAdorners(UIElement element)
        { 
            if (element == null)
                throw new ArgumentNullException("element");

            ArrayList adornerInfos = ElementMap[element] as ArrayList; 

            if (adornerInfos == null || adornerInfos.Count == 0) 
                return null; 

            Adorner[] adorners = new Adorner[adornerInfos.Count]; 

            for (int i = 0; i < adornerInfos.Count; i++)
                adorners[i] = ((AdornerInfo)adornerInfos[i]).Adorner;
 
            return adorners;
        } 
 
        /// 
        /// Determine if the given point is on an adorner. 
        /// 
        /// point to test
        /// AdornerHitTestResult containing the hit visual and the adorner that visual
        /// is part of.  If the no adorner was hit, null is returned 
        public AdornerHitTestResult AdornerHitTest(Point point)
        { 
            PointHitTestResult result = VisualTreeUtils.AsNearestPointHitTestResult(VisualTreeHelper.HitTest(this, point, false)); 

            if (result != null && result.VisualHit != null) 
            {
                Visual visual = result.VisualHit;

                while (visual != this) 
                {
                    if (visual is Adorner) 
                        return new AdornerHitTestResult(result.VisualHit, result.PointHit, visual as Adorner); 

                    // we intentionally separate adorners from spanning 3D boundaries 
                    // and if the parent is ever 3D there was a mistake
                    visual = (Visual)VisualTreeHelper.GetParent(visual);
                }
 
                return null;
            } 
            else 
            {
                return null; 
            }
        }

        ///  
        /// Walk up the visual tree to find the nearest AdornerLayer.
        ///  
        /// Visual from which the treewalk begins 
        /// First AdornerLayer above given element, or null
        static public AdornerLayer GetAdornerLayer(Visual visual) 
        {
            if (visual == null)
                throw new ArgumentNullException("visual");
 
            Visual parent = VisualTreeHelper.GetParent(visual) as Visual;
 
            while (parent != null) 
            {
                if (parent is AdornerDecorator) 
                    return ((AdornerDecorator)parent).AdornerLayer;
                if (parent is ScrollContentPresenter)
                    return ((ScrollContentPresenter)parent).AdornerLayer;
 
                parent = VisualTreeHelper.GetParent(parent) as Visual;
            } 
 
            return null;
        } 

        #endregion Public Methods

        //------------------------------------------------------ 
        //
        //  Public Properties 
        // 
        //------------------------------------------------------
 
        #region Public Properties

        #endregion Public Properties
 
        //-----------------------------------------------------
        // 
        //  Public Events 
        //
        //------------------------------------------------------ 
        //-----------------------------------------------------
        //
        //  Protected Methods
        // 
        //-----------------------------------------------------
 
        #region Protected Methods 

 
        /// 
        ///  Derived classes override this property to enable the Visual code to enumerate
        ///  the Visual children. Derived classes need to return the number of children
        ///  from this method. 
        ///
        ///    By default a Visual does not have any children. 
        /// 
        ///  Remark:
        ///      During this virtual method the Visual tree must not be modified. 
        /// 
        protected override int VisualChildrenCount
        {
            get 
            {
                //_children cannot be null as its initialized in the constructor 
                return _children.Count; 
            }
        } 

        /// 
        ///   Derived class must implement to support Visual children. The method must return
        ///    the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. 
        ///
        ///    By default a Visual does not have any children. 
        /// 
        ///  Remark:
        ///       During this virtual call it is not valid to modify the Visual tree. 
        /// 
        protected override Visual GetVisualChild(int index)
        {
            //_children cannot be null as its initialized in the constructor 
            // index range check done by VisualCollection
            return _children[index]; 
        } 

        ///  
        /// Returns enumerator to logical children.
        /// 
        protected internal override IEnumerator LogicalChildren
        { 
            get
            { 
                if ((this.VisualChildrenCount == 0)) 
                {
                    return EmptyEnumerator.Instance; 
                }

                return _children.GetEnumerator();
            } 
        }
        ///  
        /// AdornerLayer always returns a size of (0,0). 
        /// The AdornerLayer's size should be the same as its parent, but not take up layout space.  This means
        /// parents containing an AdornerLayer should stretch it to their own size. 
        /// 
        /// 
        /// Sizing constraint.
        ///  
        protected override Size MeasureOverride(Size constraint)
        { 
            // Not using an enumerator because the list can be modified during the loop when we call out. 
            DictionaryEntry[] zOrderMapEntries = new DictionaryEntry[_zOrderMap.Count];
            _zOrderMap.CopyTo(zOrderMapEntries, 0); 

            for (int i = 0; i < zOrderMapEntries.Length; i++)
            {
                ArrayList adornerInfos = (ArrayList)zOrderMapEntries[i].Value; 
                Debug.Assert(adornerInfos != null, "No adorners found for element in AdornerLayer._zOrderMap");
 
                int j = 0; 
                while (j < adornerInfos.Count)
                { 
                    AdornerInfo adornerInfo = (AdornerInfo)adornerInfos[j++];
                    adornerInfo.Adorner.Measure(constraint);
                }
            } 

            // Returning 0,0 prevents an invalidation of Measure for AdornerLayer from unnecessarily dirtying the parent. 
            return new Size(); 
        }
 
        /// 
        /// Override for 
        /// 
        ///  
        /// We need information from AdornerInfo.  Since we keep one AdornerInfo per
        /// Adorner, and we expect a 1:1 mapping between Adorners and our visual children, 
        /// it makes more sense for us to iterate across AdornerInfos instead of 
        /// our visual children here.  This means that if someone somehow adds a non-Adorner
        /// child to AdornerLayer, it will never render. 
        /// 
        /// The location reserved for this element by the parent
        protected override Size ArrangeOverride(Size finalSize)
        { 
            // Not using an enumerator because the list can be modified during the loop when we call out.
            DictionaryEntry[] zOrderMapEntries = new DictionaryEntry[_zOrderMap.Count]; 
            _zOrderMap.CopyTo(zOrderMapEntries, 0); 

            for (int i = 0; i < zOrderMapEntries.Length; i++) 
            {
                ArrayList adornerInfos = (ArrayList)zOrderMapEntries[i].Value;

                Debug.Assert(adornerInfos != null, "No adorners found for element in AdornerLayer._zOrderMap"); 

                int j = 0; 
                while (j < adornerInfos.Count) 
                {
                    AdornerInfo adornerInfo = (AdornerInfo)adornerInfos[j++]; 

                    if (!adornerInfo.Adorner.IsArrangeValid)    // optimization
                    {
                        // We're dependent on Arrange to get the rendersize of the adorner, so Arrange before 
                        // doing our transform magic.
                        adornerInfo.Adorner.Arrange(new Rect(new Point(), adornerInfo.Adorner.DesiredSize)); 
                        GeneralTransform proposedTransform = adornerInfo.Adorner.GetDesiredTransform(adornerInfo.Transform); 
                        GeneralTransform adornerTransform = GetProposedTransform(adornerInfo.Adorner, proposedTransform);
 
                        int index = _children.IndexOf(adornerInfo.Adorner);

                        if (index >= 0)
                        { 
                            // Get the matrix transform out, skip all non affine transforms
                            Transform transform = (adornerTransform != null) ? adornerTransform.AffineTransform : null; 
 
                            ((Adorner)(_children[index])).AdornerTransform = transform;
                        } 
                    }
                    if (adornerInfo.Adorner.IsClipEnabled)
                    {
                        adornerInfo.Adorner.AdornerClip = adornerInfo.Clip; 
                    }
                    else if (adornerInfo.Adorner.AdornerClip != null) 
                    { 
                        adornerInfo.Adorner.AdornerClip = null;
                    } 
                }
            }

            return finalSize; 
        }
 
        #endregion Protected Methods 

        //----------------------------------------------------- 
        //
        //  Internal Methods
        //
        //------------------------------------------------------ 

        #region Internal Methods 
 
        /// 
        /// Add given Adorner to our children 
        /// 
        /// Adorner to add
        /// z-order
        internal void Add(Adorner adorner, int zOrder) 
        {
            if (adorner == null) 
                throw new ArgumentNullException("adorner"); 

            AdornerInfo adornerInfo = new AdornerInfo(adorner); 
            adornerInfo.ZOrder = zOrder;

            AddAdornerInfo(ElementMap, adornerInfo, adorner.AdornedElement);
 
            AddAdornerToVisualTree(adornerInfo, zOrder);
 
            AddLogicalChild(adorner); 

            UpdateAdorner(adorner.AdornedElement); 
        }

        /// 
        /// Clean all the dynamically-updated data from the Adorner 
        /// 
        /// AdornerInfo to scrub 
        internal void InvalidateAdorner(AdornerInfo adornerInfo) 
        {
            Debug.Assert(adornerInfo != null, "Adorner should not be null"); 
            adornerInfo.Adorner.InvalidateMeasure();
            adornerInfo.Adorner.InvalidateVisual();
            adornerInfo.RenderSize = new Size(Double.NaN, Double.NaN);
            adornerInfo.Transform = null; 
        }
 
        ///  
        /// OnLayoutUpdated event handler
        ///  
        /// 
        /// 
        internal void OnLayoutUpdated(object sender, EventArgs args)
        { 
            if (ElementMap.Count == 0)
                return; 
 
            UpdateAdorner(null);
        } 

        /// 
        /// Set the zOrder on the given adorner.
        ///  
        /// 
        ///  
        internal void SetAdornerZOrder(Adorner adorner, int zOrder) 
        {
            ArrayList adornerInfos = ElementMap[adorner.AdornedElement] as ArrayList; 
            if (adornerInfos == null)
            {
                throw new InvalidOperationException(SR.Get(SRID.AdornedElementNotFound));
            } 
            AdornerInfo adornerInfo = GetAdornerInfo(adornerInfos, adorner);
            if (adornerInfo == null) 
            { 
                throw new InvalidOperationException(SR.Get(SRID.AdornerNotFound));
            } 

            RemoveAdornerInfo(_zOrderMap, adorner, adornerInfo.ZOrder);
            _children.Remove(adorner);
            adornerInfo.ZOrder = zOrder; 
            AddAdornerToVisualTree(adornerInfo, zOrder);
            InvalidateAdorner(adornerInfo); 
            UpdateAdorner(adorner.AdornedElement); 
        }
 
        /// 
        /// Query the zOrder on the given adorner.
        /// 
        ///  
        /// zOrder of given adorner
        internal int GetAdornerZOrder(Adorner adorner) 
        { 
            ArrayList adornerInfos = ElementMap[adorner.AdornedElement] as ArrayList;
            if (adornerInfos == null) 
            {
                throw new InvalidOperationException(SR.Get(SRID.AdornedElementNotFound));
            }
            AdornerInfo adornerInfo = GetAdornerInfo(adornerInfos, adorner); 
            if (adornerInfo == null)
            { 
                throw new InvalidOperationException(SR.Get(SRID.AdornerNotFound)); 
            }
 
            return adornerInfo.ZOrder;
        }

        #endregion Internal methods 

        //----------------------------------------------------- 
        // 
        //  Internal Properties
        // 
        //------------------------------------------------------

        #region Internal Properties
 
        internal HybridDictionary ElementMap
        { 
            get { return this._elementMap; } 
        }
 
        #endregion Internal Properties

        //------------------------------------------------------
        // 
        //  Internal Events
        // 
        //----------------------------------------------------- 
        //------------------------------------------------------
        // 
        //  Private Methods
        //
        //-----------------------------------------------------
 
        #region Private Methods
 
        ///  
        /// Adds the given adorner to the visual tree in the proper zOrder order.
        ///  
        /// 
        /// 
        private void AddAdornerToVisualTree(AdornerInfo adornerInfo, int zOrder)
        { 
            Adorner adorner = adornerInfo.Adorner;
            Debug.Assert(adorner != null); 
 
            AddAdornerInfo(_zOrderMap, adornerInfo, zOrder);
 
            // We've already added the adorner to the zOrderMap, so we can't get null back
            ArrayList adornerInfos = (ArrayList)_zOrderMap[zOrder];
            if (adornerInfos.Count > 1)
            { 
                // The easy case.  Find the index of the adorner immediately in front of the
                // new one and insert the new one after it. 
                int index = adornerInfos.IndexOf(adornerInfo); 
                int insertionIndex = _children.IndexOf(((AdornerInfo)adornerInfos[index - 1]).Adorner) + 1;
                _children.Insert(insertionIndex, adorner); 
            }
            else
            {
                // The hard case.  Find the set of adorners with the closest, but lower, zOrder. 
                IList keys = _zOrderMap.GetKeyList();
                int index = keys.IndexOf(zOrder) - 1; 
                if (index < 0) 
                {
                    // nothing's lower than the new adorner.  Make it the first child. 
                    _children.Insert(0, adorner);
                }
                else
                { 
                    // find the last adorner at this zOrder and add the new one after it.
                    adornerInfos = (ArrayList)_zOrderMap[keys[index]]; 
                    int insertionIndex = _children.IndexOf(((AdornerInfo)adornerInfos[adornerInfos.Count - 1]).Adorner) + 1; 
                    _children.Insert(insertionIndex, adorner);
                } 
            }
        }

        ///  
        /// Remove all adorners for the given element
        ///  
        /// element key for removal 
        private void Clear(UIElement element)
        { 
            if (element == null)
                throw new ArgumentNullException("element");

            ArrayList adornerInfos = ElementMap[element] as ArrayList; 

            if (adornerInfos == null) 
                throw new InvalidOperationException(SR.Get(SRID.AdornedElementNotFound)); 

            while (adornerInfos.Count > 0) 
            {
                AdornerInfo info = adornerInfos[0] as AdornerInfo;

                Remove(info.Adorner); 
            }
 
            ElementMap.Remove(element); 
        }
 
        /// 
        /// Update the Adorners for the given element
        /// 
        /// UIElement for which we're updating AdornerSet 
        private void UpdateElementAdorners(UIElement element)
        { 
            Size size; 

            // we intentionally do not ascend in to a 3D scene 
            Visual adornerLayerParent = VisualTreeHelper.GetParent(this) as Visual;
            if (adornerLayerParent == null)
            {
                return; 
            }
 
            Debug.Assert(element != null); 
            ArrayList adornerInfos = ElementMap[element] as ArrayList;
            if (adornerInfos == null) 
            {
                return;
            }
 
            bool dirty = false;
 
            // 
            // See if the adorners need to be rerendered due to object resizing
            // 
            GeneralTransform transform = element.TransformToAncestor(adornerLayerParent);

            for (int i = 0; i < adornerInfos.Count; i++)
            { 
                AdornerInfo adornerInfo = (AdornerInfo)adornerInfos[i];
                size = element.RenderSize; 
                Geometry clip = null; 
                bool clipChanged = false;
                if (adornerInfo.Adorner.IsClipEnabled) 
                {
                    clip = GetClipGeometry(adornerInfo.Adorner.AdornedElement, adornerInfo.Adorner);
                    if (adornerInfo.Clip == null && clip != null || adornerInfo.Clip != null && clip == null ||
                     (adornerInfo.Clip != null && clip != null && adornerInfo.Clip.Bounds != clip.Bounds)) 
                    {
                        clipChanged = true; 
                    } 
                }
 
                if (adornerInfo.Adorner.NeedsUpdate(adornerInfo.RenderSize) || adornerInfo.Transform == null ||
                    transform.AffineTransform == null || adornerInfo.Transform.AffineTransform == null ||
                    transform.AffineTransform.Value != adornerInfo.Transform.AffineTransform.Value ||
                    clipChanged) 
                {
                    InvalidateAdorner(adornerInfo); 
                    adornerInfo.RenderSize = size; 
                    adornerInfo.Transform = transform;
                    if (adornerInfo.Adorner.IsClipEnabled) 
                    {
                        adornerInfo.Clip = clip;
                    }
                    dirty = true; 
                }
            } 
 
            if (dirty)
                InvalidateMeasure(); 
        }

        /// 
        /// Update the Adorner for the given element 
        /// 
        /// UIElement for which we're updating AdornerSet 
        private void UpdateAdorner(UIElement element) 
        {
            Visual adornerLayerParent = VisualTreeHelper.GetParent(this) as Visual; 
            if (adornerLayerParent == null)
            {
                // Never update when the adorner layer is not part of a visual tree.
                return; 
            }
 
            // We only expect one to have been removed on any one call. 
            ArrayList removeList = new ArrayList(1);
 
            if (element != null)
            {
                // Make sure element is still beneath the adorner decorator
                if (!element.IsDescendantOf(adornerLayerParent)) 
                {
                    removeList.Add(element); 
                } 
                else
                { 
                    UpdateElementAdorners(element);
                }
            }
            else 
            {
                ICollection keyCollection = ElementMap.Keys; 
                UIElement[] keys = new UIElement[keyCollection.Count]; 
                keyCollection.CopyTo(keys, 0);  // make a static copy of the keys to prevent any possible enumerator exceptions
 
                for (int i = 0; i < keys.Length; i++)
                {
                    UIElement elTemp = (UIElement)keys[i];
 
                    // Make sure element is still beneath the adorner decorator
                    if (!elTemp.IsDescendantOf(adornerLayerParent)) 
                    { 
                        removeList.Add(elTemp);
                    } 
                    else
                    {
                        UpdateElementAdorners(elTemp);
                    } 
                }
            } 
 
            for (int i = 0; i < removeList.Count; i++)
            { 
                Clear((UIElement)removeList[i]);
            }
        }
 
        /// 
        /// Walk up the tree from the adorned element to the AdornerLayer's parent, accumulating 
        /// clip geometries as we go.  Called when IsClipEnabled == true to allow an adorner 
        /// to be clipped (which normally, it isn't).
        ///  
        private CombinedGeometry GetClipGeometry(Visual element, Adorner adorner)
        {
            Visual oldElement = null;
 
            // we intentionally do not ascend in to a 3D scene
            Visual adornerLayerParent = VisualTreeHelper.GetParent(this) as Visual; 
            if (adornerLayerParent == null) 
            {
                return null; 
            }

            CombinedGeometry combinedGeometry = null;
 
            // If the element has been removed from the tree and we've not yet had a chance
            // to remove the adorner, there's obviously no clipping 
            if (!adornerLayerParent.IsAncestorOf(element)) 
            {
                return null; 
            }

            while (element != adornerLayerParent && element != null)
            { 
                Geometry geometry = VisualTreeHelper.GetClip(element);
                if (geometry != null) 
                { 
                    if (combinedGeometry == null)
                    { 
                        combinedGeometry = new CombinedGeometry(geometry, null);
                    }
                    else
                    { 
                        GeneralTransform transform = oldElement.TransformToAncestor(element);
                        combinedGeometry.Transform = transform.AffineTransform; 
                        combinedGeometry = new CombinedGeometry(combinedGeometry, geometry); 
                        combinedGeometry.GeometryCombineMode = GeometryCombineMode.Intersect;
                    } 
                    oldElement = element;
                }

                // we intentionally separate adorners from spanning 3D boundaries 
                // and if the parent is ever 3D there was a mistake
                element = (Visual)VisualTreeHelper.GetParent(element); 
            } 
            if (combinedGeometry != null)
            { 
                // transform the last combined geometry up to the top
                GeneralTransform transform = oldElement.TransformToAncestor(adornerLayerParent);
                if (transform == null)
                { 
                    combinedGeometry = null;
                } 
                else 
                {
                    TransformGroup transformGroup = new TransformGroup(); 
                    transformGroup.Children.Add(transform.AffineTransform);

                    // Now transform back down to the adorner
                    transform = adornerLayerParent.TransformToDescendant(adorner); 
                    if (transform == null)
                    { 
                        combinedGeometry = null; 
                    }
                    else 
                    {
                        transformGroup.Children.Add(transform.AffineTransform);
                        combinedGeometry.Transform = transformGroup;
                    } 
                }
            } 
 
            return combinedGeometry;
        } 

        /// 
        /// Remove the given adorner's AdornerInfo from the given AdornerInfo list.
        ///  
        /// dictionary of adornerInfo
        /// adorner 
        /// key 
        /// true if info was found and removed
        private bool RemoveAdornerInfo(IDictionary infoMap, Adorner adorner, object key) 
        {
            ArrayList adornerInfos = infoMap[key] as ArrayList;

            if (adornerInfos != null) 
            {
                AdornerInfo adornerInfo = GetAdornerInfo(adornerInfos, adorner); 
                if (adornerInfo != null) 
                {
                    adornerInfos.Remove(adornerInfo); 
                    if (adornerInfos.Count == 0)
                    {
                        infoMap.Remove(key);
                    } 
                    return true;
                } 
            } 
            return false;
        } 

        private AdornerInfo GetAdornerInfo(ArrayList adornerInfos, Adorner adorner)
        {
            if (adornerInfos != null) 
            {
                int i = 0; 
 
                while (i < adornerInfos.Count)
                { 
                    if (((AdornerInfo)adornerInfos[i]).Adorner == adorner)
                    {
                        return (AdornerInfo)adornerInfos[i];
                    } 
                    i++;
                } 
            } 
            return null;
        } 

        private void AddAdornerInfo(IDictionary infoMap, AdornerInfo adornerInfo, object key)
        {
            ArrayList adornerInfos; 

            if (infoMap[key] == null) 
            { 
                adornerInfos = new ArrayList(1);
                infoMap[key] = adornerInfos; 
            }
            else
            {
                adornerInfos = (ArrayList)infoMap[key]; 
            }
            adornerInfos.Add(adornerInfo); 
        } 

        // 
        //  This property
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
        //  2. This is a performance optimization
        // 
        internal override int EffectiveValuesInitialSize
        { 
            get { return 4; } 
        }
 
        GeneralTransform GetProposedTransform(Adorner adorner, GeneralTransform sourceTransform)
        {
            // Flip horizontally if Right to Left.
            if (adorner.FlowDirection != this.FlowDirection) 
            {
                GeneralTransformGroup group; 
                MatrixTransform matrixTransform; 
                Matrix matrix;
 
                group = new GeneralTransformGroup();

                matrix = new Matrix(-1.0, 0.0, 0.0, 1.0, adorner.RenderSize.Width, 0.0);
                matrixTransform = new MatrixTransform(matrix); 
                group.Children.Add(matrixTransform);
 
                if (sourceTransform != null && sourceTransform != Transform.Identity) 
                {
                    group.Children.Add(sourceTransform); 
                }

                return group;
            } 

            return sourceTransform; 
        } 

        #endregion Private methods 

        //-----------------------------------------------------
        //
        //  Private Properties 
        //
        //----------------------------------------------------- 
        //------------------------------------------------------ 
        //
        //  Private Fields 
        //
        //-----------------------------------------------------

        #region Private Fields 

        private HybridDictionary _elementMap = new HybridDictionary(10); 
        private SortedList _zOrderMap = new SortedList(10); 
        private const int DefaultZOrder = System.Int32.MaxValue;
        private VisualCollection _children; 

        #endregion Private Fields
    }
} 

 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK