File: MS\Internal\Annotations\Anchoring\AttachedAnnotation.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
//
//
// Description:
//     AttachedAnnotation represents an annotation which has been loaded for a
//     specific logical tree and has a runtime anchor in that tree.  The same 
//     annotation may be loaded in a different logical tree and get a different 
//     anchor - thereby creating a different AttachedAnnotation.
//    
//     Spec: Annotation Service Spec.doc
//
 
using System.Windows;
using System.Windows.Annotations;
using System.Windows.Annotations.Storage;
 
namespace MS.Internal.Annotations.Anchoring
{
    /// <summary>
    ///     AttachedAnnotation represents an annotation which has been loaded for a
    ///     specific logical tree and has an anchor in that tree.  The same annotation
    ///     may be loaded in a different logical tree and get a different anchor - 
    ///     thereby creating a different AttachedAnnotation.
    /// </summary>
    internal class AttachedAnnotation : IAttachedAnnotation
    {
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
 
        #region Constructors
 
        /// <summary>
        ///     Create an instance of AttachedAnnotation.
        /// </summary>
        /// <param name="manager">the LocatorManager providing processors for this anchored annotation</param>
        /// <param name="annotation">the annotation itself</param>
        /// <param name="anchor">the annotation's anchor represented by the attached anchor</param>
        /// <param name="attachedAnchor">the attached anchor itself</param>
        /// <param name="attachmentLevel">the level of the attached anchor</param>
        internal AttachedAnnotation(LocatorManager manager, Annotation annotation, AnnotationResource anchor, Object attachedAnchor, AttachmentLevel attachmentLevel)
            : this(manager, annotation, anchor, attachedAnchor, attachmentLevel, null)
        {
        }
 
        /// <summary>
        ///     Create an instance of AttachedAnnotation with a specified parent.  Takes an optional 
        ///     parent for the attached annotation.  This is useful when the parent is known before
        ///     hand and not available through the normal means (such as in printing).
        /// </summary>
        /// <param name="manager">the LocatorManager providing processors for this anchored annotation</param>
        /// <param name="annotation">the annotation itself</param>
        /// <param name="anchor">the annotation's anchor represented by the attached anchor</param>
        /// <param name="attachedAnchor">the attached anchor itself</param>
        /// <param name="attachmentLevel">the level of the attached anchor</param>
        /// <param name="parent">parent of the selection</param>
        internal AttachedAnnotation(LocatorManager manager, Annotation annotation, AnnotationResource anchor, Object attachedAnchor, AttachmentLevel attachmentLevel, DependencyObject parent)
        {
            Debug.Assert(manager != null, "LocatorManager can not be null");
            Debug.Assert(annotation != null, "Annotation can not be null");
            Debug.Assert(anchor != null, "Anchor can not be null");
            Debug.Assert(attachedAnchor != null, "AttachedAnchor can not be null");
 
            _annotation = annotation;
            _anchor = anchor;
            _locatorManager = manager;
            Update(attachedAnchor, attachmentLevel, parent);
        }
 
 
        #endregion Constructors
 
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------        
 
        #region Public Methods
 
        /// <summary>
        /// Returns true if the attachedanchor of this IAttachedAnnotation is 
        /// equal to the attached anchor passed to the function
        /// </summary>
        /// <param name="o"></param>
        /// <returns>true if the anchors are equal</returns>
        public bool IsAnchorEqual(Object o)
        {
            //return _selectionProcessor.AnchorEquals(_attachedAnchor, o);
            return false;
        }
 
        #endregion Public Methods
 
        //------------------------------------------------------
        //
        //  Public Operators
        //
        //------------------------------------------------------
 
        //------------------------------------------------------
        //
        //  Public Events
        //
        //------------------------------------------------------
 
        //------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------
 
        #region Public Properties
 
        /// <summary>
        /// The Annotation that is being attached to the element tree
        /// </summary>
        /// <value></value>
        public Annotation Annotation { get { return _annotation; } }
 
        /// <summary>
        /// The specific anchor that has been resolved into the element tree
        /// </summary>
        /// <value></value>
        public AnnotationResource Anchor { get { return _anchor; } }
 
        /// <summary>
        /// The part of the Avalon element tree that this attached annotation is anchored to
        /// </summary>
        /// <value></value>
        public Object AttachedAnchor { get { return _attachedAnchor; } }
 
        /// <summary>
        /// This is simply a public accessor for FullyAttachedAnchor.  We didn't want to use the
        /// FullyAttachedAnchor name in the public API but couldn't get rid of this internal
        /// property because there are a few known users of it (through reflection).
        /// </summary>
        public Object ResolvedAnchor { get { return FullyAttachedAnchor; } }
 
        /// <summary>
        /// For virtualized content, this property returns the full anchor for the annotation.
        /// It may not be all visible or loaded into the tree, but the full anchor is useful
        /// for some operations that operate on content that may be virtualized.  This property
        /// could be:
        ///  - equal to AttachedAnchor, if the attachment level is Full
        ///  - different from AttachedAnchor, if the attachment level was not full but the
        ///    anchor could be resolved using virtual data
        ///  - null, if the attachment level was not ful but the anchor could not be resolved
        ///    using virtual data
        /// </summary>
        public Object FullyAttachedAnchor
        {
            get
            {
                if (_attachmentLevel == AttachmentLevel.Full)
                    return _attachedAnchor;
                else
                    return _fullyAttachedAnchor;
            }
        }
 
        /// <summary>
        /// The level of attachment of the annotation to its attached anchor
        /// </summary>
        /// <value></value>
        public AttachmentLevel AttachmentLevel { get { return _attachmentLevel; } }
 
        /// <summary>
        /// The Avalon logical Parent node of the attached anchor
        /// </summary>
        /// <returns></returns>
        public DependencyObject Parent
        {
            get
            {
                return _parent;
            }
        }
 
        /// <summary>
        /// The Avalon coordinate of the attached anchor measured relative 
        /// from its parent coordinate
        /// </summary>
        /// <returns></returns>
        public Point AnchorPoint
        {
            get
            {
                Point pt = _selectionProcessor.GetAnchorPoint(_attachedAnchor);
 
                if (!Double.IsInfinity(pt.X) && !Double.IsInfinity(pt.Y))
                {
                    _cachedPoint = pt;
                }
 
                return _cachedPoint;
            }
        }
 
        /// <summary>
        /// The AnnotationStore 
        /// </summary>
        /// <returns></returns>
        public AnnotationStore Store
        {
            get { return GetStore(); }
        }
 
        #endregion Public Properties        
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        /// <summary>
        /// Update the attached anchor and level for this attached annotation.  Internal method called by
        /// the annotation service when a change to an anchor is processed.  Optional parent will be used
        /// if present.  Otherwise we get the parent from the selection processor.
        /// </summary>
        /// <param name="attachedAnchor">the new attached anchor</param>
        /// <param name="attachmentLevel">the new attachment level</param>
        /// <param name="parent">optional, the parent of the attached annotation</param>
        internal void Update(object attachedAnchor, AttachmentLevel attachmentLevel, DependencyObject parent)
        {
            Debug.Assert(attachedAnchor != null, "AttachedAnchor can not be null");
            Debug.Assert(attachmentLevel > AttachmentLevel.Unresolved && attachmentLevel <= AttachmentLevel.Incomplete,
                         "Undefined attachment level");
 
            _attachedAnchor = attachedAnchor;
            _attachmentLevel = attachmentLevel;
            _selectionProcessor = _locatorManager.GetSelectionProcessor(attachedAnchor.GetType());
            // Use optional parent if available
            if (parent != null)
            {
                _parent = parent;
            }
            else
            {
                _parent = _selectionProcessor.GetParent(_attachedAnchor);
            }
            Debug.Assert(_selectionProcessor != null, SR.Format(SR.NoProcessorForSelectionType, attachedAnchor.GetType()));
        }
 
 
        /// <summary>
        /// Sets the fully attached anchor for this attached annotation.  Should be used if
        /// the attachment level is not Full and the anchor could be fully resolved using virual content.
        /// </summary>
        internal void SetFullyAttachedAnchor(object fullyAttachedAnchor)
        {
            Debug.Assert(_attachmentLevel != AttachmentLevel.Full, "Should only set fully resolved anchor if attachment level is not full.");
 
            _fullyAttachedAnchor = fullyAttachedAnchor;
        }
 
        #endregion Internal Methods
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Functions
 
        private AnnotationStore GetStore()
        {
            // indirect via the parent element & DP
            if (this.Parent != null)
            {
                AnnotationService service = AnnotationService.GetService(this.Parent);
                if (service != null)
                    return service.Store;
            }
 
            return null;
        }
 
        #endregion Private Methods
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        // The Annotation that is being attached to the element tree
        private Annotation _annotation;
 
        // The specific anchor that has been resolved into the element tree
        private AnnotationResource _anchor;
 
        // The part of the Avalon element tree that this attached annotation is anchored to
        private Object _attachedAnchor;
 
        // The fully resolved anchor, if different from _attachedAnchor
        private Object _fullyAttachedAnchor;
 
        // The level of attachment of the annotation to its attached anchor
        private AttachmentLevel _attachmentLevel;
 
        // Parent object of the attached anchor.  This shouldn't change without
        // the anchor actually changing.
        private DependencyObject _parent;
 
        // // The selectionprocessor capable of handling this _attachedanchor
        private SelectionProcessor _selectionProcessor;
 
        // the locatormanager that created this attached annotation
        private LocatorManager _locatorManager;
 
        // cached anchor point - used if the selection processor returns Infinity
        private Point _cachedPoint;
        #endregion Private Fields
    }
}