StickyNoteAnnotations.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / MS / Internal / Controls / StickyNote / StickyNoteAnnotations.cs / 2 / StickyNoteAnnotations.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: This is the partial class of the StickyNoteControl. 
//              This file contains all CAF annotation related implementations.
// 
//              See spec at [....]/longhorn/Specs/StickyNoteControlSpec.mht
//
// History:
//  08/10/2004 - [....] - Created. 
//
//--------------------------------------------------------------------------- 
 
using MS.Internal;
using MS.Internal.Annotations; 
using MS.Internal.Annotations.Component;
using MS.Internal.Controls;
using MS.Internal.Controls.StickyNote;
using MS.Internal.KnownBoxes; 
using System;
using System.Collections; 
using System.Collections.Generic; 
using System.Diagnostics;                           // Assert
using System.Globalization; 
using System.IO;
using System.Windows;
using System.Windows.Annotations;
using System.Windows.Controls; 
using System.Windows.Data;
using System.Windows.Input; 
using System.Windows.Media; 
using System.Xml;
using System.Windows.Documents; 
using MS.Internal.Documents;
using MS.Internal.Annotations.Anchoring; //TextSelectionHelper
using System.Windows.Controls.Primitives;   // IScrollInfo
using MS.Utility; 

 
 
namespace MS.Internal.Controls.StickyNote
{ 
    // NOTICE-2004/08/18,
    // Whenever we add a new type data to this enum type, make sure to update SNCAnnotation.AllValues and SNCAnnotation.AllContents.
    // This is a collection which contains all the Xml elements being used by StickyNoteControl CAF schema.
    [System.Flags] 
    internal enum XmlToken
    { 
        MetaData = 0x00000001, 
        Left = 0x00000004,
        Top = 0x00000008, 
        XOffset = 0x00000010,
        YOffset = 0x00000020,
        Width = 0x00000080,
        Height = 0x00000100, 
        IsExpanded = 0x00000200,
        Author = 0x00000400, 
        Text = 0x00002000, 
        Ink = 0x00008000,
        ZOrder = 0x00020000 
    }

    // This a wrapper class which encapsulates the operations for dealing with CAF's cargo, resources and XmlElements.
    // The schema can be found in [....]/longhorn/Specs/WinFX%20StickyNoteControl%20M8.1.mht#_Toc79371211 
    internal class SNCAnnotation
    { 
        //------------------------------------------------------------------------------- 
        //
        // Constructors 
        //
        //-------------------------------------------------------------------------------

        #region Constructor 

        // This is a static constructor which initializes the internal xml name table and the name space manager. 
        static SNCAnnotation() 
        {
            // Create our xml name dictionary. 
            s_xmlTokeFullNames = new Dictionary();

            // Fill in the name dictionary.
            foreach (XmlToken val in Enum.GetValues(typeof(XmlToken))) 
            {
                AddXmlTokenNames(val); 
            } 
        }
 
        public SNCAnnotation(Annotation annotation)
        {
            Debug.Assert(annotation != null);
 
            _annotation = annotation;
            _isNewAnnotation = _annotation.Cargos.Count == 0; 
 
            // Initialize the data cache collection.
            _cachedXmlElements = new Dictionary(); 
        }

        private SNCAnnotation() { }
 
        #endregion Constructor
 
        //-------------------------------------------------------------------------------- 
        //
        // Public Methods 
        //
        //-------------------------------------------------------------------------------

        #region Public Methods 

        ///  
        /// This static method will update an Annotation object with the specified data in a StickyNoteControl 
        /// 
        /// A flag which indicates the data needs to be updated. The flag can be combinated with the any valid bits. 
        /// A StickyNoteControl instance
        /// An SNCAnnotation object which contains a CAF annotation object
        public static void UpdateAnnotation(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation)
        { 
            AnnotationService service = null;
            bool autoFlush = false; 
            try 
            {
                service = AnnotationService.GetService(((IAnnotationComponent)snc).AnnotatedElement); 
                if (service != null && service.Store != null)
                {
                    autoFlush = service.Store.AutoFlush;
                    // Temporarily turn off autoflush until we are done 
                    // updating all the necessary values
                    service.Store.AutoFlush = false; 
                } 

                Debug.Assert((token & AllValues) != 0); 

                // Update Ink
                if ((token & XmlToken.Ink) != 0 && snc.Content.Type == StickyNoteType.Ink)
                { 
                    sncAnnotation.UpdateContent(snc, true, XmlToken.Ink);
                } 
 
                // Update Text
                if ((token & XmlToken.Text) != 0 && snc.Content.Type == StickyNoteType.Text) 
                {
                    sncAnnotation.UpdateContent(snc, true, XmlToken.Text);
                }
 

                // Update MetaData 
                if ((token & NegativeAllContents) != 0) 
                {
                    UpdateMetaData(token, snc, sncAnnotation); 
                }
            }
            finally
            { 
                if (service != null && service.Store != null)
                { 
                    // If auto flush was true before, setting it to true again should cause a flush. 
                    service.Store.AutoFlush = autoFlush;
                } 
            }
        }

        ///  
        /// This static method will update a StickyNoteControl object with the specified data in an Annotation
        ///  
        /// A flag which indicates the data needs to be updated. The flag can be combinated with the any valid bits. 
        /// A StickyNoteControl instance
        /// An SNCAnnotation object which contains a CAF annotation object 
        public static void UpdateStickyNoteControl(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation)
        {
            Invariant.Assert((token & AllValues) != 0, "No token specified.");
            Invariant.Assert(snc != null, "Sticky Note Control is null."); 
            Invariant.Assert(sncAnnotation != null, "Annotation is null.");
 
            // 

 


            XmlAttribute node;
 
            // Update Ink
            if ((token & XmlToken.Ink) != 0 && sncAnnotation.HasInkData) 
            { 
                sncAnnotation.UpdateContent(snc, false, XmlToken.Ink);
            } 

            // Update Text
            if ((token & XmlToken.Text) != 0 && sncAnnotation.HasTextData)
            { 
                sncAnnotation.UpdateContent(snc, false, XmlToken.Text);
            } 
 
            // Update Author
            if ((token & XmlToken.Author) != 0) 
            {
                int nCount = sncAnnotation._annotation.Authors.Count;
                // Get the culture specific text separator.
                string listSeparator = snc.Language.GetSpecificCulture().TextInfo.ListSeparator; 
                string authors = string.Empty;
                for (int i = 0; i < nCount; i++) 
                { 
                    if (i != 0)
                    { 
                        authors += listSeparator + sncAnnotation._annotation.Authors[i];
                    }
                    else
                    { 
                        authors += sncAnnotation._annotation.Authors[i];
                    } 
                } 

                // Setting the author property will cause the UI to update 
                snc.SetValue(StickyNoteControl.AuthorPropertyKey, authors);
            }

            // Update Height 
            if ((token & XmlToken.Height) != 0)
            { 
                node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Height); 
                if (node != null)
                { 
                    double height = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture);
                    snc.SetValue(FrameworkElement.HeightProperty, height);
                }
                else 
                {
                    snc.ClearValue(FrameworkElement.HeightProperty); 
                } 
            }
 
            // Update Width
            if ((token & XmlToken.Width) != 0)
            {
                node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Width); 
                if (node != null)
                { 
                    double width = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); 
                    snc.SetValue(FrameworkElement.WidthProperty, width);
                } 
                else
                {
                    snc.ClearValue(FrameworkElement.WidthProperty);
                } 
            }
 
            // Update IsExpanded 
            if ((token & XmlToken.IsExpanded) != 0)
            { 
                node = (XmlAttribute)sncAnnotation.FindData(XmlToken.IsExpanded);
                if (node != null)
                {
                    bool expanded = Convert.ToBoolean(node.Value, CultureInfo.InvariantCulture); 
                    snc.IsExpanded = expanded;
                } 
                else 
                {
                    snc.ClearValue(StickyNoteControl.IsExpandedProperty); 
                }
            }

            // Update ZOrder 
            if ((token & XmlToken.ZOrder) != 0)
            { 
                node = (XmlAttribute)sncAnnotation.FindData(XmlToken.ZOrder); 
                if (node != null)
                { 
                    ((IAnnotationComponent)snc).ZOrder = Convert.ToInt32(node.Value, CultureInfo.InvariantCulture);
                }
            }
 
            // Update Position
            if ((token & PositionValues) != 0) 
            { 
                TranslateTransform transform = new TranslateTransform();
                if ((token & XmlToken.Left) != 0) 
                {
                    node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Left);
                    if (node != null)
                    { 
                        double left = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture);
                        // All 'left' values are persisted assuming two things: 
                        //  1) the top-left corner (visually) of the StickyNote is the origin of its coordinate space 
                        //  2) the positive x-axis of its parent is to the right
                        // This flag signals that we have a positive x-axis to the left and our 
                        // top-right corner (visually) is our origin.  So we need to flip the
                        // value before using it.
                        if (snc.FlipBothOrigins)
                        { 
                            left = -(left + snc.Width);
                        } 
                        transform.X = left; 
                    }
                } 

                if ((token & XmlToken.Top) != 0)
                {
                    node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Top); 
                    if (node != null)
                    { 
                        double top = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); 
                        transform.Y = top;
                    } 
                }

                // Now, we update the StickyNote offset
                if ((token & XmlToken.XOffset) != 0) 
                {
                    node = (XmlAttribute)sncAnnotation.FindData(XmlToken.XOffset); 
                    if (node != null) 
                    {
                        snc.XOffset = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); 
                    }
                }

                if ((token & XmlToken.YOffset) != 0) 
                {
                    node = (XmlAttribute)sncAnnotation.FindData(XmlToken.YOffset); 
                    if (node != null) 
                    {
                        snc.YOffset = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture); 
                    }
                }

                // Set the adorner layer transform. 
                snc.PositionTransform = transform;
            } 
        } 

 
        #endregion Public Methods

        //--------------------------------------------------------------------------------
        // 
        // Public Fields
        // 
        //-------------------------------------------------------------------------------- 

        #region Public Fields 

        // A const field which contains all the Xml Elements which are mapped to a StickyNoteControl's properties.
        public const XmlToken AllValues = XmlToken.Left | XmlToken.Top | XmlToken.XOffset | XmlToken.YOffset | XmlToken.Width | XmlToken.Height
                                                | XmlToken.IsExpanded | XmlToken.Author 
                                                | XmlToken.Text | XmlToken.Ink | XmlToken.ZOrder;
 
        // A const field which contains all the Xml Elements which are related to the StickyNotes persisted position. 
        public const XmlToken PositionValues = XmlToken.Left | XmlToken.Top | XmlToken.XOffset | XmlToken.YOffset;
        // A const field which contains all the Xml Elements for initial draw of the StickyNote (this includes the offsets but not the ZOrder). 
        public const XmlToken Sizes = XmlToken.Left | XmlToken.Top | XmlToken.XOffset | XmlToken.YOffset | XmlToken.Width | XmlToken.Height;
        // A const field which contains all the Xml Elements which are related to the properties of the its contents.
        public const XmlToken AllContents = XmlToken.Text | XmlToken.Ink;
        public const XmlToken NegativeAllContents = AllValues ^ XmlToken.Text ^ XmlToken.Ink; 

        #endregion Public Fields 
 
        //-------------------------------------------------------------------------------
        // 
        // Public Properties
        //
        //--------------------------------------------------------------------------------
 
        #region Public Properties
 
        ///  
        /// Returns whether this annotation is considered new by the StickyNoteControl.
        ///  
        public bool IsNewAnnotation
        {
            get
            { 
                return _isNewAnnotation;
            } 
        } 

        ///  
        /// Returns whether this annotation has ink data.
        /// 
        public bool HasInkData
        { 
            get
            { 
                return FindData(XmlToken.Ink) != null; 
            }
        } 

        /// 
        /// Returns wether this annotation has text data.
        ///  
        public bool HasTextData
        { 
            get 
            {
                return FindData(XmlToken.Text) != null; 
            }
        }

        #endregion Public Properties 

        //------------------------------------------------------------------------------- 
        // 
        // Private Methods
        // 
        //-------------------------------------------------------------------------------

        #region Private Methods
 
        /// 
        /// This method will find a specified cargo. 
        ///  
        /// A specified cargo name
        /// The existing cargo or null 
        private AnnotationResource FindCargo(string cargoName)
        {
            foreach (AnnotationResource cargo in _annotation.Cargos)
            { 
                if (cargoName.Equals(cargo.Name))
                    return cargo; 
            } 

            return null; 
        }

        /// 
        /// Find the specified Annotation data 
        /// 
        /// A flag which is corresponding to the annotation data 
        /// The annotation data or null 
        private object FindData(XmlToken token)
        { 
            // Assume that we can't find any thing.
            object ret = null;

            // First, check if we have the data cached. 
            if (_cachedXmlElements.ContainsKey(token))
            { 
                ret = _cachedXmlElements[token]; 
            }
            else 
            {
                // Then, we try to search the data in the current annotation.
                AnnotationResource cargo = FindCargo(GetCargoName(token));
                if (cargo != null) 
                {
                    ret = SNCAnnotation.FindContent(token, cargo); 
 
                    // If we found the data in annotation, we go ahead cache it.
                    if (ret != null) 
                    {
                        _cachedXmlElements.Add(token, ret);
                    }
                } 
            }
 
            return ret; 
        }
 
        /// 
        /// Returns the AnnotationResource and the XML root for the given token from the passed in annotation.
        /// If the cargo or root do not exist they are created but not added to the annotation.  The newCargo
        /// and newRoot flags specify whether they were created.  The caller must use these to add the items 
        /// to the annotation after they are done with their modifications.
        ///  
        /// the current annotation 
        /// the token to be processed
        /// the cargo for the token 
        /// the root XML element
        /// means a new root and new cargo was created.  the root was already added to the cargo but the cargo was not added to the annotation
        /// means a new root was created.  it has not been added to the cargo.
        private static void GetCargoAndRoot( 
            SNCAnnotation annotation, XmlToken token, out AnnotationResource cargo, out XmlElement root, out bool newCargo, out bool newRoot)
        { 
            Invariant.Assert(annotation != null, "Annotation is null."); 
            Invariant.Assert((token & (AllValues | XmlToken.MetaData)) != 0, "No token specified.");
 
            string cargoName = GetCargoName(token);

            newRoot = false;
            newCargo = false; 
            cargo = annotation.FindCargo(cargoName);
 
            // Cargo exists 
            if (cargo != null)
            { 
                root = FindRootXmlElement(token, cargo);
                // Uncommon situation - cargo created without root XmlElement
                if (root == null)
                { 
                    newRoot = true;
                    XmlDocument xmlDoc = new XmlDocument(); 
                    root = xmlDoc.CreateElement(GetXmlName(token), AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); 
                    // Don't add it to the cargo yet - wait until all the
                    // values are set on it 
                }
            }
            else
            { 
                newCargo = true;
                cargo = new AnnotationResource(cargoName); 
                XmlDocument xmlDoc = new XmlDocument(); 
                root = xmlDoc.CreateElement(GetXmlName(token), AnnotationXmlConstants.Namespaces.BaseSchemaNamespace);
 
                // Since the cargo is new, its safe to add the root to it
                // No events will make it to the annotation yet
                cargo.Contents.Add(root);
            } 
        }
 
        ///  
        /// Updates the value of the specified token on the specified XmlElement.
        /// If the value is the same, no update is made.  If the new value is null 
        /// the attribute is removed.
        /// 
        private void UpdateAttribute(XmlElement root, XmlToken token, string value)
        { 
            string name = GetXmlName(token);
 
            XmlNode oldValue = root.GetAttributeNode(name, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); 
            if (oldValue == null)
            { 
                if (value == null)
                    return;
                else
                    root.SetAttribute(name, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace, value); 
            }
            else 
            { 
                if (value == null)
                    root.RemoveAttribute(name, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); 
                else if (oldValue.Value != value)
                    root.SetAttribute(name, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace, value);
            }
        } 

        ///  
        /// This static method returns the Xml name for the specified token. 
        /// 
        /// A specified token 
        /// The name for the Xml node
        private static string GetXmlName(XmlToken token)
        {
            return s_xmlTokeFullNames[token]; 
        }
 
        ///  
        /// This method is called by the static constructor to set up the Xml name dictionary.
        ///  
        /// A specified token
        private static void AddXmlTokenNames(XmlToken token)
        {
            // Conver the enum value to the string first. 
            string xmlName = token.ToString();
 
            // Depending on the data, we add the proper prefix to the full name. 
            switch (token)
            { 
                // The element names should be qualified
                case XmlToken.MetaData:
                case XmlToken.Text:
                case XmlToken.Ink: 
                    {
                        s_xmlTokeFullNames.Add(token, AnnotationXmlConstants.Prefixes.BaseSchemaPrefix + ":" + xmlName); 
                    } 
                    break;
 
                    //the attribute names should be local
                case XmlToken.Left:
                case XmlToken.Top:
                case XmlToken.XOffset: 
                case XmlToken.YOffset:
                case XmlToken.Width: 
                case XmlToken.Height: 
                case XmlToken.IsExpanded:
                case XmlToken.ZOrder: 
                default:
                    {
                        s_xmlTokeFullNames.Add(token, xmlName);
                    } 
                    break;
            } 
        } 

        ///  
        /// Return the cargo name which hosts the specified data.
        /// 
        /// The specified data
        /// The host cargo name 
        private static string GetCargoName(XmlToken token)
        { 
            string cargoName; 
            switch (token)
            { 
                // Those tokens use *snc* prefix.
                case XmlToken.MetaData:
                case XmlToken.Left:
                case XmlToken.Top: 
                case XmlToken.XOffset:
                case XmlToken.YOffset: 
                case XmlToken.Width: 
                case XmlToken.Height:
                case XmlToken.IsExpanded: 
                case XmlToken.ZOrder:
                    {
                        cargoName = SNBConstants.MetaResourceName;
                    } 
                    break;
                // Those tokens use *media* prefix. 
                case XmlToken.Text: 
                    {
                        cargoName = SNBConstants.TextResourceName; 
                    }
                    break;
                case XmlToken.Ink:
                    { 
                        cargoName = SNBConstants.InkResourceName;
                    } 
                    break; 
                default:
                    { 
                        cargoName = string.Empty;
                        Debug.Assert(false);
                    }
                    break; 
            }
            return cargoName; 
        } 

        ///  
        /// The method returns the root node which contains the specified data in a cargo.
        /// 
        /// The specified data
        /// The specified cargo 
        /// The root node or null
        private static XmlElement FindRootXmlElement(XmlToken token, AnnotationResource cargo) 
        { 
            Debug.Assert(cargo != null);
 
            XmlElement element = null;
            string xmlName = string.Empty;

            // Get the xml name of the root node 
            switch (token)
            { 
                case XmlToken.Text: 
                case XmlToken.Ink:
                    xmlName = GetXmlName(token); 
                    break;
                case XmlToken.MetaData:
                case XmlToken.IsExpanded:
                case XmlToken.Width: 
                case XmlToken.Height:
                case XmlToken.Top: 
                case XmlToken.Left: 
                case XmlToken.XOffset:
                case XmlToken.YOffset: 
                case XmlToken.ZOrder:
                    xmlName = GetXmlName(XmlToken.MetaData);
                    break;
                default: 
                    Debug.Assert(false);
                    break; 
            } 

            // Search the root in the cargo's contents. 
            foreach (XmlElement node in cargo.Contents)
            {
                if (node.Name.Equals(xmlName))
                { 
                    element = node;
                    break; 
                } 
            }
 
            return element;
        }

        ///  
        /// Find the specified data in a cargo.
        ///  
        /// The specified data 
        /// The cargo which we are searhing in
        /// The data object or null 
        private static object FindContent(XmlToken token, AnnotationResource cargo)
        {
            object content = null;
            XmlElement root = SNCAnnotation.FindRootXmlElement(token, cargo); 

            // If we found the root node, we should use XPath to query the node which contains the corresponding data. 
            // The StickyNoteControl's xml schema can be found 
            // in [....]/longhorn/Specs/WinFX%20StickyNoteControl%20M8.1.mht#_Toc79371211
            if (root != null) 
            {
                switch (token)
                {
                    case XmlToken.Text: 
                    case XmlToken.Ink:
                        return root; 
                    case XmlToken.IsExpanded: 
                    case XmlToken.ZOrder:
                    case XmlToken.Top: 
                    case XmlToken.Left:
                    case XmlToken.XOffset:
                    case XmlToken.YOffset:
                    case XmlToken.Width: 
                    case XmlToken.Height:
                        return root.GetAttributeNode(GetXmlName(token), AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); 
                    default: 
                        Debug.Assert(false);
                        break; 
                }

            }
 
            return content;
        } 
 
        // Update ink data from/to SNC.
        private void UpdateContent(StickyNoteControl snc, bool updateAnnotation, XmlToken token) 
        {
            Invariant.Assert(snc != null, "Sticky Note Control is null.");
            Invariant.Assert((token & AllContents) != 0, "No token specified.");
 
            StickyNoteContentControl contentControl = snc.Content;
 
            // Template hasn't been applied yet.  Once it has the content control will then be setup. 
            if (contentControl == null)
            { 
                return;
            }

            // Check whether the annotation data matches the content control. 
            if ((token == XmlToken.Ink && contentControl.Type != StickyNoteType.Ink)
                || (token == XmlToken.Text && contentControl.Type != StickyNoteType.Text)) 
            { 
                Debug.Assert(false, "The annotation data does match with the current content control in StickyNote");
                return; 
            }

            XmlElement root = null;
 
            if (updateAnnotation)
            { 
                // Update annotation from SNC 

                AnnotationResource cargo = null; 
                bool newRoot = false;
                bool newCargo = false;

                // Check if the text is empty. 
                if (!contentControl.IsEmpty)
                { 
                    GetCargoAndRoot(this, token, out cargo, out root, out newCargo, out newRoot); 
                    contentControl.Save(root);
                } 
                else
                {
                    string cargoName = GetCargoName(token);
                    cargo = FindCargo(cargoName); 
                    if (cargo != null)
                    { 
                        _annotation.Cargos.Remove(cargo); 
                        _cachedXmlElements.Remove(token);
                    } 
                }
                if (newRoot)
                {
                    Invariant.Assert(root != null, "XmlElement should have been created."); 
                    Invariant.Assert(cargo != null, "Cargo should have been retrieved.");
                    cargo.Contents.Add(root); 
                } 
                if (newCargo)
                { 
                    Invariant.Assert(cargo != null, "Cargo should have been created.");
                    _annotation.Cargos.Add(cargo);
                }
            } 
            else
            { 
                // Update SNC from annotation 

                // Check if we have the text data in the xml store. 
                XmlElement node = (XmlElement)FindData(token);
                if (node != null)
                {
                    contentControl.Load(node); 
                }
                else 
                { 
                    if (!contentControl.IsEmpty)
                    { 
                        contentControl.Clear();
                    }
                }
            } 
        }
 
        ///  
        /// Update the metadata tokens specified in token.
        ///  
        private static void UpdateMetaData(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation)
        {
            bool newCargo, newRoot;
            AnnotationResource cargo; 
            XmlElement root;
 
            GetCargoAndRoot(sncAnnotation, XmlToken.MetaData, out cargo, out root, out newCargo, out newRoot); 

            // Update Expanded 
            if ((token & XmlToken.IsExpanded) != 0)
            {
                bool expanded = snc.IsExpanded;
                sncAnnotation.UpdateAttribute(root, XmlToken.IsExpanded, expanded.ToString(CultureInfo.InvariantCulture)); 
            }
 
            // Update Height 
            if ((token & XmlToken.Height) != 0)
            { 
                Debug.Assert(snc.IsExpanded);
                double height = (double)snc.GetValue(FrameworkElement.HeightProperty);
                sncAnnotation.UpdateAttribute(root, XmlToken.Height, height.ToString(CultureInfo.InvariantCulture));
            } 

            // Update Width 
            if ((token & XmlToken.Width) != 0) 
            {
                Debug.Assert(snc.IsExpanded); 
                double width = (double)snc.GetValue(FrameworkElement.WidthProperty);
                sncAnnotation.UpdateAttribute(root, XmlToken.Width, width.ToString(CultureInfo.InvariantCulture));
            }
 
            // Update Left
            if ((token & XmlToken.Left) != 0) 
            { 
                double left = snc.PositionTransform.X;
                // All 'left' values are persisted assuming two things: 
                //  1) the top-left corner (visually) of the StickyNote is the origin of its coordinate space
                //  2) the positive x-axis of its parent is to the right
                // This flag signals that we have a positive x-axis to the left and our
                // top-right corner (visually) is our origin.  So we need to flip the 
                // value before persisting it.
                if (snc.FlipBothOrigins) 
                { 
                    left = -(left + snc.Width);
                } 
                sncAnnotation.UpdateAttribute(root, XmlToken.Left, left.ToString(CultureInfo.InvariantCulture));
            }

            // Update Top 
            if ((token & XmlToken.Top) != 0)
            { 
                sncAnnotation.UpdateAttribute(root, XmlToken.Top, snc.PositionTransform.Y.ToString(CultureInfo.InvariantCulture)); 
            }
 
            // Update XOffset
            if ((token & XmlToken.XOffset) != 0)
            {
                sncAnnotation.UpdateAttribute(root, XmlToken.XOffset, snc.XOffset.ToString(CultureInfo.InvariantCulture)); 
            }
 
            // Update YOffset 
            if ((token & XmlToken.YOffset) != 0)
            { 
                sncAnnotation.UpdateAttribute(root, XmlToken.YOffset, snc.YOffset.ToString(CultureInfo.InvariantCulture));
            }

            // Update ZOrder 
            if ((token & XmlToken.ZOrder) != 0)
            { 
                sncAnnotation.UpdateAttribute(root, XmlToken.ZOrder, ((IAnnotationComponent)snc).ZOrder.ToString(CultureInfo.InvariantCulture)); 
            }
 
            if (newRoot)
            {
                cargo.Contents.Add(root);
            } 
            if (newCargo)
            { 
                sncAnnotation._annotation.Cargos.Add(cargo); 
            }
        } 

        #endregion Private Methods

        //------------------------------------------------------------------------------- 
        //
        // Private Fields 
        // 
        //--------------------------------------------------------------------------------
 
        #region Private Fields

        private static Dictionary s_xmlTokeFullNames;     // A dictionary for the names of the xml elements
 
        private Dictionary _cachedXmlElements;   // A dictionary for caching the data object
        private Annotation _annotation; 
        private readonly bool _isNewAnnotation; 

        #endregion Private Fields 
    }

}
 
namespace System.Windows.Controls
{ 
    public partial class StickyNoteControl 
    {
 
        //-------------------------------------------------------------------------------
        //
        // IAnnotationComponent Interface
        // 
        //--------------------------------------------------------------------------------
 
        #region IAnnotationComponent Members 
        /// 
        /// Adds an attached annotations to this StickyNoteControl 
        /// 
        /// An IAttachedAnnotation instance
        void IAnnotationComponent.AddAttachedAnnotation(IAttachedAnnotation attachedAnnotation)
        { 
            if (attachedAnnotation == null)
            { 
                throw new ArgumentNullException("attachedAnnotation"); 
            }
 
            if (_attachedAnnotation == null)
            {
                //fire trace event
                EventTrace.NormalTraceEvent(EventTraceGuidId.ADDATTACHEDSNGUID, EventType.StartEvent); 

                SetAnnotation(attachedAnnotation); 
 
                //fire trace event
                EventTrace.NormalTraceEvent(EventTraceGuidId.ADDATTACHEDSNGUID, EventType.EndEvent); 

            }
            else
            { 
                throw new InvalidOperationException(SR.Get(SRID.AddAnnotationsNotImplemented));
            } 
        } 

        ///  
        /// Removes an attached annotations from this StickyNoteControl.
        /// 
        /// An IAttachedAnnotation instance
        void IAnnotationComponent.RemoveAttachedAnnotation(IAttachedAnnotation attachedAnnotation) 
        {
            if (attachedAnnotation == null) 
            { 
                throw new ArgumentNullException("attachedAnnotation");
            } 

            if (attachedAnnotation == _attachedAnnotation)
            {
                //fire trace event 
                EventTrace.NormalTraceEvent(EventTraceGuidId.REMOVEATTACHEDSNGUID, EventType.StartEvent);
 
                GiveUpFocus(); 

                ClearAnnotation(); 

                //fire trace event
                EventTrace.NormalTraceEvent(EventTraceGuidId.REMOVEATTACHEDSNGUID, EventType.StartEvent);
 
            }
            else 
            { 
                throw new ArgumentException(SR.Get(SRID.InvalidValueSpecified), "attachedAnnotation");
            } 
        }

        /// 
        /// Called when an AttachedAnnotation's attached anchor changes. 
        /// 
        /// The attached annotation after modification 
        /// The attached anchor previously associated with the attached annotation. 
        /// The previous attachment level of the attached annotation.
        void IAnnotationComponent.ModifyAttachedAnnotation(IAttachedAnnotation attachedAnnotation, object previousAttachedAnchor, AttachmentLevel previousAttachmentLevel) 
        {
            throw new NotSupportedException(SR.Get(SRID.NotSupported));
        }
 
        /// 
        /// Gets the attached annotations this component is representing. 
        ///  
        /// list of IAttachedAnnotation instances this component is representing
        IList IAnnotationComponent.AttachedAnnotations 
        {
            get
            {
                ArrayList annotations = new ArrayList(1); 

                if (_attachedAnnotation != null) 
                { 
                    annotations.Add(_attachedAnnotation);
                } 

                return annotations;
            }
        } 

        ///  
        /// Compute the transform for the icon. 
        /// also hide or show the expanded component.
        ///  
        /// 
        /// 
        GeneralTransform IAnnotationComponent.GetDesiredTransform(GeneralTransform transform)
        { 
            if (_attachedAnnotation != null)
            { 
                // If we are expanded and set to flow from RightToLeft and we are in a viewer using a DocumentPageHost 
                // we need to mirror ourselves.  This is work around an issue with DocumentViewerBase which mirrors its
                // contents (because its generated always as LeftToRight).  We are anchored to that content so the mirror 
                // gets applied to as as well.  This is our attempt to cancel out that mirror.
                if (this.IsExpanded
                    && this.FlowDirection == FlowDirection.RightToLeft
                    && _attachedAnnotation.Parent is DocumentPageHost) 
                {
                    _selfMirroring = true; 
                } 
                else
                { 
                    _selfMirroring = false;
                }

                Point anchor = _attachedAnnotation.AnchorPoint; 

                if (double.IsInfinity(anchor.X) || double.IsInfinity(anchor.Y)) 
                { 
                    throw new InvalidOperationException(SR.Get(SRID.InvalidAnchorPosition));
                } 

                if ((double.IsNaN(anchor.X)) || (double.IsNaN(anchor.Y)))
                    return null;
 
                GeneralTransformGroup transformations = new GeneralTransformGroup();
 
                // We should be in normal Right-To-Left mode, but because of special cases 
                // in DocumentPageView, we've been mirrored.  We detect this and re-mirror
                // ourselves.  We also need to do special handling of move/resize operations. 
                if (_selfMirroring)
                {
                    // This is the mirroring transform that will get the StickyNote to lay out
                    // as if it were in Right-To-Left mode 
                    transformations.Children.Add(new MatrixTransform(-1.0, 0.0, 0.0, 1.0, this.Width, 0.0));
                } 
 
                transformations.Children.Add(new TranslateTransform(anchor.X, anchor.Y));
 
                TranslateTransform offsetTransform = new TranslateTransform(0, 0);
                if (IsExpanded == true)
                {
                    offsetTransform = PositionTransform.Clone(); 

                    // Reset delta values 
                    _deltaX = _deltaY = 0; 

                    //if we are in any kind of page viewer we might need to bring SN on the page 
                    Rect rectPage = PageBounds;
                    Rect rectStickyNote = StickyNoteBounds;

                    // Get the current offsets 
                    double offsetX, offsetY;
                    GetOffsets(rectPage, rectStickyNote, out offsetX, out offsetY); 
 
                    // If the current offsets are greater than the cached the values,
                    // we will make sure that stickynote sticks on the cached values. 
                    if (DoubleUtil.GreaterThan(Math.Abs(offsetX), Math.Abs(_offsetX)))
                    {
                        // Whatever the offset - don't move to the right more than
                        double offset = _offsetX - offsetX; 
                        if (DoubleUtil.LessThan(offset, 0)) // if we are moving to the left, don't go beyond the edge
                        { 
                            offset = Math.Max(offset, -(rectStickyNote.Left - rectPage.Left)); 
                        }
                        offsetTransform.X += offset; 
                        _deltaX = offset;
                    }

                    if (DoubleUtil.GreaterThan(Math.Abs(offsetY), Math.Abs(_offsetY))) 
                    {
                        double offset = _offsetY - offsetY; 
                        if (DoubleUtil.LessThan(offset, 0)) // if we are moving to the top, don't go beyond the edge 
                        {
                            offset = Math.Max(offset, -(rectStickyNote.Top - rectPage.Top)); 
                        }
                        offsetTransform.Y += offset;
                        _deltaY = offset;
                    } 
                }
 
                if (offsetTransform != null) 
                    transformations.Children.Add(offsetTransform);
                transformations.Children.Add(transform); 
                return transformations;
            }

            return null; 
        }
 
        ///  
        /// Return the attached annotation parent as the annotated element
        ///  
        /// 
        UIElement IAnnotationComponent.AnnotatedElement
        {
            get 
            {
                return _attachedAnnotation != null ? _attachedAnnotation.Parent as UIElement : null; 
            } 
        }
 
        /// 
        /// Get/Set the PresentationContext
        /// 
        ///  
        PresentationContext IAnnotationComponent.PresentationContext
        { 
            get 
            {
                return _presentationContext; 
            }
            set
            {
                _presentationContext = value; 
            }
        } 
 
        /// 
        /// Sets and gets the Z-order of this component. NOP - 
        /// Highlight does not have Z-order
        /// 
        /// Context this annotation component is hosted in
        int IAnnotationComponent.ZOrder 
        {
            get 
            { 
                return _zOrder;
            } 

            set
            {
                _zOrder = value; 
                UpdateAnnotationWithSNC(XmlToken.ZOrder);
            } 
        } 

        ///  
        /// Notifies the component that the AnnotatedElement content has changed
        /// 
        bool IAnnotationComponent.IsDirty
        { 
            get
            { 
                if (_anchor != null) 
                    return _anchor.IsDirty;
                return false; 
            }
            set
            {
                if (_anchor != null) 
                    _anchor.IsDirty = value;
                if (value) 
                    InvalidateVisual(); 
            }
        } 

        #endregion // IAnnotationComponent Members

        #region Public Fields 

        ///  
        /// The Xml type name which is used by the Annotation to instantiate a Text StickyNoteControl 
        /// 
        public static readonly XmlQualifiedName TextSchemaName = new XmlQualifiedName("TextStickyNote", AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); 

        /// 
        /// The Xml type name which is used by the Annotation to instantiate an Ink StickyNoteControl
        ///  
        public static readonly XmlQualifiedName InkSchemaName = new XmlQualifiedName("InkStickyNote", AnnotationXmlConstants.Namespaces.BaseSchemaNamespace);
 
        #endregion Public Fields 

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

        #region Internal Properties 
 
        // The property is the accessor of the variable of _positionTransform which is used by
        // IAnnotationComponent.GetDesiredTransform method. The annotation adorner layer will use the transform to 
        // position the StickyNoteControl
        internal TranslateTransform PositionTransform
        {
            get 
            {
                return _positionTransform; 
            } 
            set
            { 
                Invariant.Assert(value != null, "PositionTransform cannot be null.");
                _positionTransform = value;

                InvalidateTransform(); 
            }
        } 
 
        /// 
        /// Gets/Sets the cached X offset when StikcyNote is cross the page boundary 
        /// 
        internal double XOffset
        {
            get 
            {
                return _offsetX; 
            } 
            set
            { 
                _offsetX = value;
            }
        }
 
        /// 
        /// Gets/Sets the cached Y offset when StikcyNote is cross the page boundary 
        ///  
        internal double YOffset
        { 
            get
            {
                return _offsetY;
            } 
            set
            { 
                _offsetY = value; 
            }
        } 

        /// 
        /// This flag signals that we are truly in Right-To-Left mode.  This means the positive
        /// x-axis points to the left and our top-right corner (visually) is our origin.  We use 
        /// this flag to determine whether we should flip the value for 'left' before storing it.
        /// Flipping it allows it to be persisted in a way that can be used by the StickyNote in 
        /// non Right-To-Left mode or in the self-mirroring case. 
        /// 
        internal bool FlipBothOrigins 
        {
            get
            {
                return (this.IsExpanded && this.FlowDirection == FlowDirection.RightToLeft && 
                    _attachedAnnotation != null && _attachedAnnotation.Parent is DocumentPageHost);
            } 
        } 

        #endregion Internal Properties 

        //--------------------------------------------------------------------------------
        //
        // Private Methods 
        //
        //------------------------------------------------------------------------------- 
 
        #region Private Methods
 
        // A registered handler for a bubble listening to the annotation author update event.
        //     obj  -   The sender of the event
        //     args -   event arguement
        private void OnAuthorUpdated(object obj, AnnotationAuthorChangedEventArgs args) 
        {
            Debug.Assert(_attachedAnnotation != null && _attachedAnnotation.Annotation == args.Annotation); 
 
            if (!InternalLocker.IsLocked(LockHelper.LockFlag.AnnotationChanged))
            { 
                UpdateSNCWithAnnotation(XmlToken.Author);
                IsDirty = true;
            }
        } 

        // A registered handler for a bubble listening to the annotation store update event. 
        //     obj  -   The sender of the event 
        //     args -   event arguement
        private void OnAnnotationUpdated(object obj, AnnotationResourceChangedEventArgs args) 
        {
            Debug.Assert(_attachedAnnotation != null && _attachedAnnotation.Annotation == args.Annotation);

            if (!InternalLocker.IsLocked(LockHelper.LockFlag.AnnotationChanged)) 
            {
                SNCAnnotation sncAnnotation = new SNCAnnotation(args.Annotation); 
                _sncAnnotation = sncAnnotation; 
                UpdateSNCWithAnnotation(SNCAnnotation.AllValues);
                IsDirty = true; 
            }
        }

        ///  
        /// The method sets an instance of the IAttachedAnnotation to the StickyNoteControl.
        /// It will be called by IAnnotationComponent.AddAttachedAnnotation. 
        ///  
        /// The instance of the IAttachedAnnotation
        private void SetAnnotation(IAttachedAnnotation attachedAnnotation) 
        {
            SNCAnnotation sncAnnotation = new SNCAnnotation(attachedAnnotation.Annotation);

            // Retrieve the data type. Then set the StickyNote to correct type. 
            // If we have empty data, we won't change the current StickyNote type.
            bool hasInkData = sncAnnotation.HasInkData; 
            bool hasTextData = sncAnnotation.HasTextData; 
            if (hasInkData && hasTextData)
            { 
                throw new ArgumentException(SR.Get(SRID.InvalidStickyNoteAnnotation), "attachedAnnotation");
            }
            else if (hasInkData)
            { 
                _stickyNoteType = StickyNoteType.Ink;
            } 
            else if (hasTextData) 
            {
                _stickyNoteType = StickyNoteType.Text; 
            }

            // If we already created a Content control, make sure it matches our new type or
            // gets recreated to match. 
            if (Content != null)
            { 
                EnsureStickyNoteType(); 
            }
 
            //create cargo if it is a new Annotation so it is not considered as new next time
            if (sncAnnotation.IsNewAnnotation)
            {
                AnnotationResource cargo = new AnnotationResource(SNBConstants.MetaResourceName); 
                attachedAnnotation.Annotation.Cargos.Add(cargo);
            } 
 
            // Set the internal variables
            _attachedAnnotation = attachedAnnotation; 
            _attachedAnnotation.Annotation.CargoChanged += new AnnotationResourceChangedEventHandler(OnAnnotationUpdated);
            _attachedAnnotation.Annotation.AuthorChanged += new AnnotationAuthorChangedEventHandler(OnAuthorUpdated);
            _sncAnnotation = sncAnnotation;
            _anchor.AddAttachedAnnotation(attachedAnnotation); 

            // Update all value 
            UpdateSNCWithAnnotation(SNCAnnotation.AllValues); 

            // The internal data is just sync'ed to the store. So, reset the dirty to false. 
            IsDirty = false;

            //now check if the SN must be seen
            if ((_attachedAnnotation.AttachmentLevel & AttachmentLevel.StartPortion) == 0) 
            {
                //we do not need to show the StickyNote 
                SetValue(UIElement.VisibilityProperty, Visibility.Collapsed); 
            }
            else 
            {
                //if it is seen we need to take care about bringing into view when needed
                RequestBringIntoView += new RequestBringIntoViewEventHandler(OnRequestBringIntoView);
            } 
        }
 
        ///  
        /// Clear the internal variables and events which are related to the annotation.
        /// The method will be called by IAnnotationComponent.RemoveAttachedAnnotation 
        /// 
        private void ClearAnnotation()
        {
            _attachedAnnotation.Annotation.CargoChanged -= new AnnotationResourceChangedEventHandler(OnAnnotationUpdated); 
            _attachedAnnotation.Annotation.AuthorChanged -= new AnnotationAuthorChangedEventHandler(OnAuthorUpdated);
            _anchor.RemoveAttachedAnnotation(_attachedAnnotation); 
            _sncAnnotation = null; 

           _attachedAnnotation = null; 
            RequestBringIntoView -= new RequestBringIntoViewEventHandler(OnRequestBringIntoView);
        }

        ///  
        /// Brings the SN into view. When navigate through the keyboard navigation the focus
        /// can get to a SN that is not currently  into view. 
        ///  
        /// sender
        /// arguments 
        ///  Since the AdornerLayer does not have scrolling abilities we need to scroll
        /// AnnotatedElement. In order to get out SN into view we must calculate the corresponding area of
        /// the AnnotatedElement.
        private void OnRequestBringIntoView(Object sender, RequestBringIntoViewEventArgs e) 
        {
            Debug.Assert(((IAnnotationComponent)this).AnnotatedElement != null, "undefined annotated element"); 
            FrameworkElement target = ((IAnnotationComponent)this).AnnotatedElement as FrameworkElement; 

            DocumentPageHost host = target as DocumentPageHost; 
            if (host != null)
            {
                target = host.PageVisual as FrameworkElement;
            } 

            if (target == null) 
            { 
                //we have nothing to do here
                return; 
            }

            //if target is IScrollInfo - check if we are within the viewport
            IScrollInfo scrollInfo = target as IScrollInfo; 
            if (scrollInfo != null)
            { 
                Rect bounds = StickyNoteBounds; 
                Rect viewport = new Rect(0, 0, scrollInfo.ViewportWidth, scrollInfo.ViewportHeight);
                if (bounds.IntersectsWith(viewport)) 
                    return;
            }

            //get adorned element 
            Transform adornerTransform = (Transform)TransformToVisual(target);
            Debug.Assert(adornerTransform != null, "transform to AnnotatedElement is null"); 
 
            //get SN sizes
            Rect size = new Rect(0, 0, Width, Height); 
            size.Transform(adornerTransform.Value);
            target.BringIntoView(size);
        }
 
        /// 
        /// This method will update this StickyNoteControl data based on the internal annotation variable. 
        ///  
        /// The data need to be updated
        private void UpdateSNCWithAnnotation(XmlToken tokens) 
        {
            if (_sncAnnotation != null)
            {
                //fire trace event 
                EventTrace.NormalTraceEvent(EventTraceGuidId.UPDATESNCWITHANNOTATIONGUID, EventType.StartEvent);
 
                // Now, we are going to update this StickyNoteControl. We will get notified for the data being changed. 
                // we don't want to update our internal annotation because for the data changes which are coming
                // from the annotation itself. So, we lock our internal locker. 
                using (LockHelper.AutoLocker locker = new LockHelper.AutoLocker(InternalLocker, LockHelper.LockFlag.DataChanged))
                {
                    SNCAnnotation.UpdateStickyNoteControl(tokens, this, _sncAnnotation);
                } 

                //fire trace event 
                EventTrace.NormalTraceEvent(EventTraceGuidId.UPDATESNCWITHANNOTATIONGUID, EventType.EndEvent); 
            }
        } 

        /// 
        /// This method will update this internal annotation based on this StickyNoteControl.
        ///  
        /// 
        private void UpdateAnnotationWithSNC(XmlToken tokens) 
        { 
            // Check if we have an annotation attached.
            // Also we don't want to update the annotation when the data changes are actually caused by UpdateSNCWithAnnotation. 
            if (_sncAnnotation != null &&
                !InternalLocker.IsLocked(LockHelper.LockFlag.DataChanged))
            {
                //fire trace event 
                EventTrace.NormalTraceEvent(EventTraceGuidId.UPDATEANNOTATIONWITHSNCGUID, EventType.StartEvent);
 
                // Now, we are going to update the annotation. Since we will get notified from the annotation store, 
                // we don't want to update our internal annotation if the change has been made by this instance.
                // Here we lock the internal locker. 
                using (LockHelper.AutoLocker locker = new LockHelper.AutoLocker(InternalLocker, LockHelper.LockFlag.AnnotationChanged))
                {
                    // Now, update the attached annotation.
                    SNCAnnotation.UpdateAnnotation(tokens, this, _sncAnnotation); 
                }
                //fire trace event 
                EventTrace.NormalTraceEvent(EventTraceGuidId.UPDATEANNOTATIONWITHSNCGUID, EventType.EndEvent); 
            }
        } 

        /// 
        /// The method will update the X and Y offsets when StickyNote is cross the host page boundary.
        /// This method should only be called from OnDragDelta. 
        /// 
        private void UpdateOffsets() 
        { 
            // If we don't have annotation, don't even borther.
            if (_attachedAnnotation != null) 
            {
                Rect rectPage = PageBounds;
                Rect rectStickyNote = StickyNoteBounds;
 
                // Make sure that we have the valid bounds.
                if (!rectPage.IsEmpty && !rectStickyNote.IsEmpty) 
                { 
                    // StickyNote should never disappear from the host page.
                    Invariant.Assert(DoubleUtil.GreaterThan(rectStickyNote.Right, rectPage.Left), "Note's right is off left of page."); 
                    Invariant.Assert(DoubleUtil.LessThan(rectStickyNote.Left, rectPage.Right), "Note's left is off right of page.");
                    Invariant.Assert(DoubleUtil.GreaterThan(rectStickyNote.Bottom, rectPage.Top), "Note's bottom is off top of page.");
                    Invariant.Assert(DoubleUtil.LessThan(rectStickyNote.Top, rectPage.Bottom), "Note's top is off bottom of page.");
 
                    double offsetX, offsetY;
                    // Get the current offsets. 
                    GetOffsets(rectPage, rectStickyNote, out offsetX, out offsetY); 

                    // If the offsets have been changed, we should update the cached values. 
                    if (!DoubleUtil.AreClose(XOffset, offsetX))
                    {
                        XOffset = offsetX;
                    } 

                    if (!DoubleUtil.AreClose(YOffset, offsetY)) 
                    { 
                        YOffset = offsetY;
                    } 
                }
            }
        }
 
        /// 
        /// A method which calculates the X and Y offsets between StickyNote and Page bounds. 
        ///  
        /// The page bounds
        /// The StickyNote bounds 
        /// 
        /// X Offset.
        /// 0 means that StickyNote is completely inside page on X dimension.
        /// A negative value means that StickyNote is partially beyond page left. 
        /// A positive value means that StickyNote is partially beyond page right.
        ///  
        ///  
        /// Y Offset.
        /// 0 means that StickyNote is completely inside page on Y dimension. 
        /// A negative value means that StickyNote is partially beyond page top.
        /// A positive value means that StickyNote is partially beyond page bottom.
        /// 
        private static void GetOffsets(Rect rectPage, Rect rectStickyNote, out double offsetX, out double offsetY) 
        {
            offsetX = 0; 
            if (DoubleUtil.LessThan(rectStickyNote.Left, rectPage.Left)) 
            {
                // StickyNote is beyond the left boundary 
                offsetX = rectStickyNote.Left - rectPage.Left;
            }
            else if (DoubleUtil.GreaterThan(rectStickyNote.Right, rectPage.Right))
            { 
                // StickyNote is beyond the right boundary
                offsetX = rectStickyNote.Right - rectPage.Right; 
            } 

 
            offsetY = 0;
            if (DoubleUtil.LessThan(rectStickyNote.Top, rectPage.Top))
            {
                // StickyNote is beyond the top boundary 
                offsetY = rectStickyNote.Top - rectPage.Top;
            } 
            else if (DoubleUtil.GreaterThan(rectStickyNote.Bottom, rectPage.Bottom)) 
            {
                // StickyNote is beyond the bottom boundary 
                offsetY = rectStickyNote.Bottom - rectPage.Bottom;
            }
        }
 
        private Rect StickyNoteBounds
        { 
            get 
            {
                Debug.Assert(_attachedAnnotation != null, "This property should never be acccessed from outside of CAF"); 

                Rect ret = Rect.Empty;
                Point anchor = _attachedAnnotation.AnchorPoint;
 
                if (!(double.IsNaN(anchor.X)) && !(double.IsNaN(anchor.Y)) && PositionTransform != null)
                { 
                    ret = new Rect(anchor.X + PositionTransform.X + _deltaX, anchor.Y + PositionTransform.Y + _deltaY, Width, Height); 
                }
 
                return ret;
            }
        }
 
        private Rect PageBounds
        { 
            get 
            {
                Rect pageBounds = Rect.Empty; 

                IAnnotationComponent component = (IAnnotationComponent)this;

                // If the annotated element is a scroll info, we should use the 
                // full size of the scrollable content - ExtendWidth/ExtentHeight.
                IScrollInfo scrollInfo = component.AnnotatedElement as IScrollInfo; 
                if (scrollInfo != null) 
                {
                    pageBounds = new Rect(-scrollInfo.HorizontalOffset, -scrollInfo.VerticalOffset, scrollInfo.ExtentWidth, scrollInfo.ExtentHeight); 
                }
                else
                {
                    UIElement parent = component.AnnotatedElement; 

                    if (parent != null) 
                    { 
                        Size pageSize = parent.RenderSize;
                        pageBounds = new Rect(0, 0, pageSize.Width, pageSize.Height); 
                    }
                }

                return pageBounds; 
            }
 
        } 

        #endregion // Private Methods 

        //-------------------------------------------------------------------------------
        //
        // Private Fields 
        //
        //------------------------------------------------------------------------------- 
 
        #region Private Fields
 
        /// 
        /// the presentation context this sticky note is in
        /// 
        PresentationContext _presentationContext; 

        ///  
        /// Offset from anchor point to sticky note icon 
        /// 
        TranslateTransform _positionTransform = new TranslateTransform(0, 0); 

        // A reference of the current attached annotation instance.
        private IAttachedAnnotation _attachedAnnotation;
        private SNCAnnotation _sncAnnotation; 

        // The cached horizontal and vertical portions of the StickyNote the user 
        // put off the page boundary.  This is used to attempt to reproduce the same 
        // portions when the page has been reflowed.
        // 0 means that StickyNote is completely inside page on X or Y dimension. 
        // A negative value means that StickyNote is partially beyond page top/left.
        // A positive value means that StickyNote is partially beyond page bottom/right.
        // These are updated everytime the user moves the StickyNote and are persisted.
        private double _offsetX; 
        private double _offsetY;
 
        // The distances the StickyNote has been moved at layout time in order to 
        // reproduce the same portion off the page as the user previously created.
        // 0 means we had to do no adjusting, the note is where the use put it. 
        // A negative value means we had to move the StickyNote towards the origin.
        // A positive value menas we had to move the StickyNote away from the origin.
        // These are updated on every layout pass and are not persisted.
        private double _deltaX; 
        private double _deltaY;
 
        //Component Z-order 
        private int _zOrder;
 
        // This flag signals that we should be in normal Right-To-Left mode, but because
        // of special cases in DocumentPageView, we've been mirrored (back to Left-To-Right mode).
        // Therefore we need to re-mirror ourselves and special handling of move/resize operations.
        private bool _selfMirroring = false; 

        #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