StickyNote.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 / Controls / StickyNote.cs / 1 / StickyNote.cs

                            // In order to disable Presharp warning 6507 - Prefer 'string.IsNullOrEmpty(value)' over checks for null and/or emptiness, 
// we have to disable warnings 1634 and 1691 to make the compiler happy first.
#pragma warning disable 1634, 1691

//---------------------------------------------------------------------------- 
//
//  
//    Copyright (C) Microsoft Corporation.  All rights reserved. 
// 
// 
//
// Description: Implementation of StickyNoteControl control.
//
//              See spec at http://tabletpc/longhorn/Specs/StickyNoteControlSpec.mht 
//
// History: 
//  04/19/2004 - waynezen - Expose more properties and methods 
//  02/17/2004 - waynezen - Moved to TabletFramework
//  10/06/2003 - waynezen - Added Ink and Snippet Image supports 
//  09/23/2003 - waynezen - Ported to WCP.
//  12/16/2002 - waynezen - Created.
//
//--------------------------------------------------------------------------- 

using System; 
using System.ComponentModel; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.Collections.Specialized;
using System.Diagnostics;                           // Assert
using System.Globalization;
using System.IO; 
using System.Reflection;
using System.Xml; 
using System.Xml.Serialization; 
using Microsoft.Win32;              // SystemEvents
using MS.Internal; 
using MS.Internal.Annotations.Component;
using MS.Internal.Controls.StickyNote;
using MS.Internal.Commands;
using MS.Internal.KnownBoxes; 
using MS.Internal.PresentationFramework;
using System.Windows.Threading; 
using System.Windows; 
using System.Windows.Data;
using System.Windows.Annotations; 
using System.Windows.Automation;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Ink; 
using System.Windows.Input;
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes;
using System.Text; 
using System.Text.RegularExpressions;
using MS.Utility;

 
namespace System.Windows.Controls
{ 
    ///  
    /// The type of data handled by a StickyNoteControl.
    ///  
    public enum StickyNoteType
    {
        /// 
        /// Text StickyNote 
        /// 
        Text, 
        ///  
        /// Ink StickyNote
        ///  
        Ink,
    }

 
    /// 
    /// StickyNoteControl control intends to be an UI control for user to make annotation. 
    ///  
    [TemplatePart(Name = SNBConstants.c_CloseButtonId, Type = typeof(Button))]
    [TemplatePart(Name = SNBConstants.c_TitleThumbId, Type = typeof(Thumb))] 
    [TemplatePart(Name = SNBConstants.c_BottomRightResizeThumbId, Type = typeof(Thumb))]
    [TemplatePart(Name = SNBConstants.c_ContentControlId, Type = typeof(ContentControl))]
    [TemplatePart(Name = SNBConstants.c_IconButtonId, Type = typeof(Button))]
    [TemplatePart(Name = SNBConstants.c_CopyMenuId, Type = typeof(MenuItem))] 
    [TemplatePart(Name = SNBConstants.c_PasteMenuId, Type = typeof(MenuItem))]
    [TemplatePart(Name = SNBConstants.c_InkMenuId, Type = typeof(MenuItem))] 
    [TemplatePart(Name = SNBConstants.c_SelectMenuId, Type = typeof(MenuItem))] 
    [TemplatePart(Name = SNBConstants.c_EraseMenuId, Type = typeof(MenuItem))]
    public sealed partial class StickyNoteControl : Control, 
        IAnnotationComponent
    {
        //-------------------------------------------------------------------------------
        // 
        // Constructors
        // 
        //------------------------------------------------------------------------------- 

        #region Constructors 

        /// 
        /// The static constructor
        ///  
        static StickyNoteControl()
        { 
            Type owner = typeof(StickyNoteControl); 

            // Register event handlers 
            // NTRAID-WINDOWS#1136774-WAYNEZEN,
            // We want to bring a note to front when the input device is pressed down on it at the first time.
            // StickyNote invokes PresentationContext.BringToFront method to achieve it.
            // Eventually the Annotation AdornerLayer will re-arrange index of its children to change their "Z-Order". 
            // So, the BringToFront could temporarily remove StickyNote from the visual tree.
            // But the hosted InkCanvas might capture Stylus for collecting packets. If the host note is removed from the tree, the capture 
            // will be released automatically which will mess up the InkCanvas' states. 
            // So we have to do BringToFront before InkCanvas does capture. Adding a handler of PreviewStylusDownEvent fixes the problem.
            // Unfortunately we still need the existing handler of PreviewMouseDownEvent since there is no stylus event for text StickyNote. 

            //

 
            EventManager.RegisterClassHandler(owner, Stylus.PreviewStylusDownEvent, new StylusDownEventHandler(_OnPreviewDeviceDown));
            EventManager.RegisterClassHandler(owner, Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(_OnPreviewDeviceDown)); 
            EventManager.RegisterClassHandler(owner, Mouse.MouseDownEvent, new MouseButtonEventHandler(_OnDeviceDown)); 
            EventManager.RegisterClassHandler(owner, ContextMenuService.ContextMenuOpeningEvent, new ContextMenuEventHandler(_OnContextMenuOpening));
 
            CommandHelpers.RegisterCommandHandler(typeof(StickyNoteControl), StickyNoteControl.DeleteNoteCommand,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled));
            CommandHelpers.RegisterCommandHandler(typeof(StickyNoteControl), StickyNoteControl.InkCommand,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled)); 

            // 
            // set the main style CRK to the default theme style key 
            //
            DefaultStyleKeyProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata( 
                new ComponentResourceKey(typeof(PresentationUIStyleResources), "StickyNoteControlStyleKey")));

            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
            Control.IsTabStopProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(false)); 

            // Override the changed callback of the Foreground Property. 
            ForegroundProperty.OverrideMetadata( 
                    owner,
                    new FrameworkPropertyMetadata(new PropertyChangedCallback(_UpdateInkDrawingAttributes))); 

            FontFamilyProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged)));
            FontSizeProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged)));
            FontStretchProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged))); 
            FontStyleProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged)));
            FontWeightProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged))); 
        } 

        ///  
        /// This is an instance constructor for StickyNoteControl class.  Should not be used
        /// 
        private StickyNoteControl() : this(StickyNoteType.Text)
        { 
        }
 
        ///  
        /// Creates an instance of StickyNoteControl that handles the specified type.
        ///  
        /// the type of data to be handled by the StickyNoteControl
        internal StickyNoteControl(StickyNoteType type) : base()
        {
            _stickyNoteType = type; 
            SetValue(StickyNoteTypePropertyKey, type);
            InitStickyNoteControl(); 
        } 

        #endregion // Constructors 

        //--------------------------------------------------------------------------------
        //
        // Public Methods 
        //
        //------------------------------------------------------------------------------- 
 
        #region Public Methods
 

        /// 
        /// Override OnApplyTemplate method. This method will ensure whether the created visual is one which
        /// StickyNoteControl expects. If so, the internal controls will be cached and Annotation will be applied 
        /// to the UI status.
        ///  
        /// Whether Visuals were added to the tree 
        public override void OnApplyTemplate()
        { 
            // No need for calling VerifyAccess since we call the method on the base here.
            base.OnApplyTemplate();

            // Ensure the type 
            if (this.IsExpanded)
            { 
                EnsureStickyNoteType(); 
            }
 
            // Setup the inner controls with the Annotation's data
            UpdateSNCWithAnnotation(SNCAnnotation.AllValues);

            // If the visual tree just gets populated from the new style, we have to add our event handles to the individual 
            // elements.
            if (!this.IsExpanded) 
            { 
                Button button = GetIconButton();
                if (button != null) 
                {
                    button.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonClick));
                }
            } 
            else
            { 
                Button closeButton = GetCloseButton(); 
                if (closeButton != null)
                { 
                    closeButton.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonClick));
                }

                Thumb titleThumb = GetTitleThumb(); 
                if (titleThumb != null)
                { 
                    titleThumb.AddHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta)); 
                    titleThumb.AddHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted));
                } 

                Thumb resizeThumb = GetResizeThumb();
                if (resizeThumb != null)
                { 
                    resizeThumb.AddHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta));
                    resizeThumb.AddHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted)); 
                } 

                // Set up the bindings to the menuitems. 
                SetupMenu();
            }
        }
 
        #endregion // Public Methods
 
        //-------------------------------------------------------------------------------- 
        //
        // Public Properties 
        //
        //--------------------------------------------------------------------------------

        #region Public Properties 

        ///  
        /// The property key of Author 
        /// 
        internal static readonly DependencyPropertyKey AuthorPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "Author",
                        typeof(string),
                        typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(String.Empty));
 
        ///  
        /// Author Dependency Property
        ///  
        public static readonly DependencyProperty AuthorProperty = AuthorPropertyKey.DependencyProperty;

        /// 
        /// Returns the author of the annotation the StickyNoteControl is editing. 
        /// 
        public String Author 
        { 
            get
            { 
                return (String)GetValue(StickyNoteControl.AuthorProperty);
            }
        }
 
        /// 
        /// Gets/Sets the expanded or minimized state of the StickyNoteControl. 
        /// If Expanded=false, the bubble is in a minimized state. 
        /// 
        public static readonly DependencyProperty IsExpandedProperty = 
                DependencyProperty.Register(
                        "IsExpanded",
                        typeof(bool),
                        typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(
                                BooleanBoxes.TrueBox, 
                                new PropertyChangedCallback(_OnIsExpandedChanged))); 

        ///  
        /// Gets/Sets the expanded or minimized state of the StickyNoteControl.
        /// 
        public bool IsExpanded
        { 
            get { return (bool) GetValue(IsExpandedProperty); }
            set { SetValue(IsExpandedProperty, value); } 
        } 

        ///  
        /// true - StickyNoteControl is active (i.e. has the focus or selection includes part of its anchor)
        ///The value of this property is set by the MarkedHighlightComponent which controls the SN state
        /// 
        public static readonly DependencyProperty IsActiveProperty = 
            DependencyProperty.RegisterAttached("IsActive",
                typeof(bool), 
                typeof(StickyNoteControl), 
                new FrameworkPropertyMetadata(BooleanBoxes.FalseBox,
                    FrameworkPropertyMetadataOptions.Inherits)); 

        /// 
        /// The state of StickyNoteControl - true : active, false:inactive
        ///  
        public bool IsActive
        { 
            get 
            {
                return (bool)GetValue(StickyNoteControl.IsActiveProperty); 
            }
        }

        ///  
        /// If true, mouse is over the SticyNoteControl's anchor (which could be used to change its appearance
        /// in its style). 
        ///  
        internal static readonly DependencyPropertyKey IsMouseOverAnchorPropertyKey =
            DependencyProperty.RegisterReadOnly("IsMouseOverAnchor", 
                typeof(bool),
                typeof(StickyNoteControl),
                    new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        /// 
        /// If true, mouse is over the SticyNoteControl's anchor (which could be used to change its appearance 
        /// in its style). 
        /// 
        public static readonly DependencyProperty IsMouseOverAnchorProperty = IsMouseOverAnchorPropertyKey.DependencyProperty; 

        /// 
        /// True if the mouse is over the StickyNote anchor, false otherwise
        ///  
        public bool IsMouseOverAnchor
        { 
            get 
            {
               return  (bool) GetValue(StickyNoteControl.IsMouseOverAnchorProperty); 
            }
        }

        ///  
        ///     The DependencyProperty for the CaptionFontFamily property.
        ///     Flags:              Can be used in style rules 
        ///     Default Value:      System Dialog Font 
        /// 
        public static readonly DependencyProperty CaptionFontFamilyProperty = 
                DependencyProperty.Register(
                        "CaptionFontFamily",
                        typeof(FontFamily),
                        typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(
                                SystemFonts.MessageFontFamily, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure)); 

        ///  
        ///     The caption font family
        /// 
        public FontFamily CaptionFontFamily
        { 
            get { return (FontFamily) GetValue(CaptionFontFamilyProperty); }
            set { SetValue(CaptionFontFamilyProperty, value); } 
        } 

        ///  
        ///     The DependencyProperty for the CaptionFontSize property.
        ///     Flags:              Can be used in style rules
        ///     Default Value:      System Dialog Font Size
        ///  
        public static readonly DependencyProperty CaptionFontSizeProperty =
                DependencyProperty.Register( 
                        "CaptionFontSize", 
                        typeof(double),
                        typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(
                                SystemFonts.MessageFontSize,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///     The size of the caption font. 
        ///  
        public double CaptionFontSize
        { 
            get { return (double) GetValue(CaptionFontSizeProperty); }
            set { SetValue(CaptionFontSizeProperty, value); }
        }
 
        /// 
        ///     The DependencyProperty for the CaptionFontStretch property. 
        ///     Flags:              Can be used in style rules 
        ///     Default Value:      FontStretches.Normal
        ///  
        public static readonly DependencyProperty CaptionFontStretchProperty =
                DependencyProperty.Register(
                        "CaptionFontStretch",
                        typeof(FontStretch), 
                        typeof(StickyNoteControl),
                        new FrameworkPropertyMetadata( 
                                FontStretches.Normal, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///     The stretch of the caption font.
        /// 
        public FontStretch CaptionFontStretch 
        {
            get { return (FontStretch) GetValue(CaptionFontStretchProperty); } 
            set { SetValue(CaptionFontStretchProperty, value); } 
        }
 
        /// 
        ///     The DependencyProperty for the CaptionFontStyle property.
        ///     Flags:              Can be used in style rules
        ///     Default Value:      System Dialog Font Style 
        /// 
        public static readonly DependencyProperty CaptionFontStyleProperty = 
                DependencyProperty.Register( 
                        "CaptionFontStyle",
                        typeof(FontStyle), typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(
                                SystemFonts.MessageFontStyle,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///     The style of the caption font. 
        ///  
        public FontStyle CaptionFontStyle
        { 
            get { return (FontStyle) GetValue(CaptionFontStyleProperty); }
            set { SetValue(CaptionFontStyleProperty, value); }
        }
 
        /// 
        ///     The DependencyProperty for the CaptionFontWeight property. 
        ///     Flags:              Can be used in style rules 
        ///     Default Value:      System Dialog Font Weight
        ///  
        public static readonly DependencyProperty CaptionFontWeightProperty =
                DependencyProperty.Register(
                        "CaptionFontWeight",
                        typeof(FontWeight), 
                        typeof(StickyNoteControl),
                        new FrameworkPropertyMetadata( 
                                SystemFonts.MessageFontWeight, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///     The weight or thickness of the caption font.
        /// 
        public FontWeight CaptionFontWeight 
        {
            get { return (FontWeight) GetValue(CaptionFontWeightProperty); } 
            set { SetValue(CaptionFontWeightProperty, value); } 
        }
 
        /// 
        ///     The DependencyProperty for the PenWidth property.
        ///     Flags:              Can be used in style rules
        ///     Default Value:      The default width of System.Windows.Ink.DrawingAttributes. 
        /// 
        public static readonly DependencyProperty PenWidthProperty = 
                DependencyProperty.Register( 
                        "PenWidth",
                        typeof(double), 
                        typeof(StickyNoteControl),
                        new FrameworkPropertyMetadata(
                                (new DrawingAttributes()).Width,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, 
                                new PropertyChangedCallback(_UpdateInkDrawingAttributes)));
 
        ///  
        ///     The width of the pen for the ink StickyNoteControl.
        ///  
        public double PenWidth
        {
            get { return (double) GetValue(PenWidthProperty); }
            set { SetValue(PenWidthProperty, value); } 
        }
 
        ///  
        /// StickyNoteType Property Key
        ///  
        private static readonly DependencyPropertyKey StickyNoteTypePropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "StickyNoteType",
                        typeof(StickyNoteType), 
                        typeof(StickyNoteControl),
                        new FrameworkPropertyMetadata(StickyNoteType.Text)); 
 
        /// 
        /// StickyNoteType Dependency Property 
        /// 
        public static readonly DependencyProperty StickyNoteTypeProperty = StickyNoteTypePropertyKey.DependencyProperty;

        ///  
        /// Gets StickyNoteType Property
        ///  
        public StickyNoteType StickyNoteType 
        {
            get{ return (StickyNoteType) GetValue(StickyNoteTypeProperty); } 
        }

        /// 
        /// Returns the Annotation this StickyNote is representing. 
        /// 
        public IAnchorInfo AnchorInfo 
        { 
            get
            { 
                if (_attachedAnnotation != null)
                    return _attachedAnnotation;
                return null;
            } 
        }
 
        #endregion  Public Properties 

        //------------------------------------------------------------------------------- 
        //
        // Public Commands
        //
        //-------------------------------------------------------------------------------- 

        #region Public Commands 
 
        /// 
        /// Delete a note 
        /// 
        public static readonly RoutedCommand DeleteNoteCommand = new RoutedCommand("DeleteNote", typeof(StickyNoteControl));

        ///  
        /// Ink Mode
        ///  
        public static readonly RoutedCommand InkCommand = new RoutedCommand("Ink", typeof(StickyNoteControl)); 

        #endregion Public Commands 


        //-------------------------------------------------------------------------------
        // 
        // Protected Methods
        // 
        //------------------------------------------------------------------------------- 

        #region Protected Methods 

        /// 
        /// Called whenever the template changes.
        ///  
        /// Old template
        /// New template 
        protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate) 
        {
            // No need for calling VerifyAccess since we call the method on the base here. 
            base.OnTemplateChanged(oldTemplate, newTemplate);

            // If StickyNote's control template has been changed, we should invalidate current cached controls.
            ClearCachedControls(); 
        }
 
        ///  
        /// Called whenever focus enters or leaves the StickyNoteControl.  This includes when focus
        /// is set/removed from any element within the StickyNoteControl. 
        /// 
        /// arguments describing the property change
        protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs args)
        { 
            base.OnIsKeyboardFocusWithinChanged(args);
 
            // If we lost focus due to a context menu on some element within us, 
            // we don't consider that a loss of focus.  We simply exit early.
            ContextMenu menu = Keyboard.FocusedElement as ContextMenu; 
            if (menu != null)
            {
                if (menu.PlacementTarget != null && menu.PlacementTarget.IsDescendantOf(this))
                { 
                        return;
                } 
            } 

            // Must update our anchor that we are now focused or not focused. 
            _anchor.Focused = IsKeyboardFocusWithin;
        }

        ///  
        /// An event announcing that the keyboard is focused on this bubble.
        ///  
        /// >FocusChangedEvent Argument 
        protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs args)
        { 
            // No need for calling VerifyAccess since we call the method on the base here.
            base.OnGotKeyboardFocus(args);

            // Dwayne's Input BC(#73066) changed the behavior of mouse button event. 
            // So we could get GotKeyboardFocus event without the visual being set up.
            // Now, we verify the visual is ready by invoking ApplyTemplate. 
            ApplyTemplate(); 

            // We are interested in the expanded note. 
            if ( IsExpanded == true )
            {
                Invariant.Assert(Content != null);
 
                BringToFront();
                // If focus was set on us, we should set the focus on our inner control 
                if ( args.NewFocus == this ) 
                {
                    UIElement innerControl = this.Content.InnerControl as UIElement; 
                    Invariant.Assert(innerControl != null, "InnerControl is null or not a UIElement.");

                    // Don't mess with focus if its already on our inner control
                    if ( innerControl.IsKeyboardFocused == false ) 
                    {
                        // We should set the focus to the inner control after it is added the visual tree. 
                        innerControl.Focus(); 
                    }
                } 
            }
        }

        #endregion // Protected Methods 

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

        #region Internal Methods
 
        /// 
        /// Creates our inner control and adds it to the tree.  If the inner control 
        /// already exists we verify its of the right type for our current data. 
        /// This is called when the template is applied or when the annotation for this
        /// control is set. 
        /// 
        private void EnsureStickyNoteType()
        {
            UIElement contentContainer = GetContentContainer(); 

            // Check whether we need to recreate a content control based on the new type. 
            if (_contentControl != null) 
            {
                // Check if the type has been changed 
                if (_contentControl.Type != _stickyNoteType)
                {
                    // Recreate the content control when the type has been changed.
                    DisconnectContent(); 
                    _contentControl = StickyNoteContentControlFactory.CreateContentControl(_stickyNoteType, contentContainer);
                    ConnectContent(); 
                } 
            }
            else 
            {
                _contentControl = StickyNoteContentControlFactory.CreateContentControl(_stickyNoteType, contentContainer);
                ConnectContent();
            } 
        }
 
        ///  
        /// When our inner control is changing, we disconnect from the existing one
        /// by unregistering for events and removing the control from the visual tree. 
        /// 
        private void DisconnectContent()
        {
            Invariant.Assert(Content != null, "Content is null."); 

            // Unregister for all events and clear bindings 
            StopListenToContentControlEvent(); 
            UnbindContentControlProperties();
 
            _contentControl = null;
        }

        ///  
        /// When a new content control is created we register on different portions of
        /// the visual tree for certain events. 
        ///  
        private void ConnectContent()
        { 
            Invariant.Assert(Content != null);

            // Set the default inking mode and attributes
            InkCanvas innerInkCanvas = Content.InnerControl as InkCanvas; 
            if (innerInkCanvas != null)
            { 
                // Create the event handlers we'll use for ink notes 
                InitializeEventHandlers();
 
                // We set the value on the StickyNoteControl which eventually gets
                // set on the InkCanvas.  The property on the InkCanvas isn't a DP
                // we can't create a one-way binding as would be preferred.
                this.SetValue(InkEditingModeProperty, InkCanvasEditingMode.Ink); 

                UpdateInkDrawingAttributes(); 
            } 

            // Register for events and setup bindings 
            StartListenToContentControlEvent();
            BindContentControlProperties();
        }
 
        /// 
        /// Returns the Content element for this StickyNoteControl.  Should never 
        /// be null when IsExpanded = true. 
        /// 
        internal StickyNoteContentControl Content 
        {
            get
            {
                return _contentControl; 
            }
        } 
 
        /// 
        /// Returns the button used to close the StickyNoteControl (it actually sets IsExpanded to false). 
        /// 
        private Button GetCloseButton()
        {
            return GetTemplateChild(SNBConstants.c_CloseButtonId) as Button; 
        }
 
        ///  
        /// Returns the button when the StickyNoteControl has IsExpanded=false.
        ///  
        private Button GetIconButton()
        {
                return GetTemplateChild(SNBConstants.c_IconButtonId) as Button;
        } 

        ///  
        /// Returns the thumb that controls the dragging of the StickyNote as a whole. 
        /// 
        private Thumb GetTitleThumb() 
        {
            return GetTemplateChild(SNBConstants.c_TitleThumbId) as Thumb;
        }
 
        /// 
        /// Return the ContentControl viewer in the StickyNoteControl. 
        ///  
        private UIElement GetContentContainer()
        { 
            return GetTemplateChild(SNBConstants.c_ContentControlId) as UIElement;
        }

        ///  
        /// Return the resize thumb in the StickyNoteControl.
        ///  
        private Thumb GetResizeThumb() 
        {
            return GetTemplateChild(SNBConstants.c_BottomRightResizeThumbId) as Thumb; 
        }


        #endregion Internal Methods 

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

        #region Internal Properties
 
        /// 
        /// InkEditingMode Property Key 
        ///  
        private static readonly DependencyProperty InkEditingModeProperty =
                        DependencyProperty.Register( 
                                "InkEditingMode",
                                typeof(InkCanvasEditingMode),
                                typeof(StickyNoteControl),
                                new FrameworkPropertyMetadata( 
                                    InkCanvasEditingMode.None));
 
        ///  
        /// Gets/Sets the dirty state of the control.
        ///  
        private bool IsDirty
        {
            get
            { 
                return _dirty;
            } 
            set 
            {
                _dirty = value; 
            }
        }

        #endregion // Internal Properties 

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

        #region Private Methods
 
        /// 
        /// Called when a StickyNoteControl's IsExpanded property changes.  Simply 
        /// pass it on to the StickyNoteControl instance. 
        /// 
        private static void _OnIsExpandedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            StickyNoteControl snc = (StickyNoteControl)d;

            snc.OnIsExpandedChanged(); 
        }
 
        private static void OnFontPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            StickyNoteControl stickyNoteControl = (StickyNoteControl)d; 
            if (stickyNoteControl.Content != null && stickyNoteControl.Content.Type != StickyNoteType.Ink)
            {
                FrameworkElement innerControl = stickyNoteControl.Content.InnerControl;
                if (innerControl != null) 
                    innerControl.SetValue(e.Property, e.NewValue);
            } 
        } 

        ///  
        /// The changed callback attached to the Foreground and PenWidth DPs
        /// 
        private static void _UpdateInkDrawingAttributes(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            // Update the DrawingAttributes
            StickyNoteControl stickyNoteControl = (StickyNoteControl)d; 
            stickyNoteControl.UpdateInkDrawingAttributes(); 

            if (e.Property == ForegroundProperty && stickyNoteControl.Content != null && stickyNoteControl.Content.Type != StickyNoteType.Ink) 
            {
                FrameworkElement innerControl = stickyNoteControl.Content.InnerControl;
                if (innerControl != null)
                    innerControl.SetValue(ForegroundProperty, e.NewValue); 
            }
        } 
 

        // A class handler for TextBox.TextChanged events 
        //      obj       -   the event sender
        //      args    -   Event argument
        private void OnTextChanged(object obj, TextChangedEventArgs args)
        { 
            // We must update the annotation asynchronously because we can't Since Textbox doesn't allow any layout measurement during its content is changing, we have to do
            // the update asynchronously.  We also prevent updating the annotation when the content in the 
            // textbox was changed due to a change in the annotation itself. 
            if (!InternalLocker.IsLocked(LockHelper.LockFlag.DataChanged))
            { 
                //fire trace event
                EventTrace.NormalTraceEvent(EventTraceGuidId.ANNOTATIONTEXTCHANGEDGUID, EventType.StartEvent);

                AsyncUpdateAnnotation(XmlToken.Text); 
                //Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(AsyncUpdateAnnotation), XmlToken.Text);
                IsDirty = true; 
 
                //fire trace event
                EventTrace.NormalTraceEvent(EventTraceGuidId.ANNOTATIONTEXTCHANGEDGUID, EventType.EndEvent); 

            }
        }
 
        private static void _OnDeviceDown(object sender, TEventArgs args)
            where TEventArgs : InputEventArgs 
        { 
            // Block all mouse downs from leaving this control
            args.Handled = true; 
        }

        private static void _OnContextMenuOpening(object sender, ContextMenuEventArgs args)
        { 
            // Block all ContextMenuOpenings from leaving this control
            if (!(args.TargetElement is ScrollBar)) 
            { 
                args.Handled = true;
            } 
        }

        // A generic class handler for both Stylus.PreviewStylusDown and Mouse.PreviewMouseDown events
        //      dc       -   the event sender 
        //      args    -   Event argument
        private static void _OnPreviewDeviceDown(object sender, TEventArgs args) 
            where TEventArgs : InputEventArgs 
        {
            StickyNoteControl snc = sender as StickyNoteControl; 

            IInputElement captured = null;
            StylusDevice stylusDevice = null;
            MouseDevice mouseDevice = null; 

            // Check whether Stylus or Mouse has been captured. 
            stylusDevice = args.Device as StylusDevice; 
            if ( stylusDevice != null )
            { 
                captured = stylusDevice.Captured;
            }
            else
            { 
                mouseDevice = args.Device as MouseDevice;
 
                if (mouseDevice != null) 
                {
                    captured = mouseDevice.Captured; 
                }
            }

            // ContextMenu may capture the inputdevice in front. 
            // If the device is captured by an element other than StickyNote, we should not try to bring note to front.
            if ( snc != null && ( captured == snc || captured == null ) ) 
            { 
                snc.OnPreviewDeviceDown(sender, args);
            } 
        }

        /// 
        /// When the Strokes are replaced on an InkCanvas we must unregister on the previous set 
        /// of strokes and register on the new set of strokes.
        ///  
        private void OnInkCanvasStrokesReplacedEventHandler(object sender, InkCanvasStrokesReplacedEventArgs e) 
        {
            StopListenToStrokesEvent(e.PreviousStrokes); 
            StartListenToStrokesEvent(e.NewStrokes);
        }

        ///  
        /// Raised when the user moves the selection.  We prevent the selection from going into negative
        /// territory because ScrollViewer does not scroll content there and the ink gets lost. 
        /// 
        /// For move, we just clamp X or Y to 0.
        ///  
        private void OnInkCanvasSelectionMovingEventHandler(object sender, InkCanvasSelectionEditingEventArgs e)
        {
            Rect newRectangle = e.NewRectangle;
            if (newRectangle.X < 0 || newRectangle.Y < 0) 
            {
                newRectangle.X = newRectangle.X < 0d ? 0d : newRectangle.X; 
                newRectangle.Y = newRectangle.Y < 0d ? 0d : newRectangle.Y; 
                e.NewRectangle = newRectangle;
            } 
        }

        /// 
        /// Raised when the user resizes the selection.  We prevent the selection from going into negative 
        /// territory because ScrollViewer does not scroll content there and the ink gets lost.
        /// 
        /// For Resize, we recompute the new rect after clamping x or y (or both) to 0,0 
        /// 
        private void OnInkCanvasSelectionResizingEventHandler(object sender, InkCanvasSelectionEditingEventArgs e) 
        {
            Rect newRectangle = e.NewRectangle;
            if (newRectangle.X < 0 || newRectangle.Y < 0)
            { 
                if (newRectangle.X < 0)
                { 
                    //newRect.X is negative, simply add it to width to subtract it 
                    newRectangle.Width = newRectangle.Width + newRectangle.X;
                    newRectangle.X = 0d; 
                }
                if (newRectangle.Y < 0)
                {
                    //newRect.Y is negative, simply add it to height to subtract it 
                    newRectangle.Height = newRectangle.Height + newRectangle.Y;
                    newRectangle.Y = 0d; 
                } 
                e.NewRectangle = newRectangle;
            } 
        }

        // A handler for the events of ink stroke being changed.
        private void OnInkStrokesChanged(object sender, StrokeCollectionChangedEventArgs args) 
        {
            // We have two options for tracking ink's dirty flag. 
            // 1) use the UndoStateChanged event to detect when any data changes in the Ink object model 
            //      Advantages:
            //          Handles ALL data changes in Ink object model 
            //          One event handler
            //      Disadvantages:
            //          Very perf intensive since undo serialization is triggered
            // 2) Handle the StrokesChanged or DrawingAttributesChanged events to detect when specific kinds of data change in the Ink object model. 
            //      Advantages:
            //          Efficient since no serialization occurs. 
            //          Very targeted handling of types of data changes (e.g. points/transforms, drawing attributes) 
            //      Disadvantages:
            //          Does not include changes to ExtendedProperties/ExtendedProperties and potentially 3rd party events. - not a true 100% perfect dirty flag 

            // Since we only care about transforms/points and drawing attributes for now, #2 is a better choice.

            StopListenToStrokeEvent(args.Removed); 
            StartListenToStrokeEvent(args.Added);
 
            if (args.Removed.Count > 0 || args.Added.Count > 0) 
            {
                Invariant.Assert(Content != null && Content.InnerControl is InkCanvas); 
                FrameworkElement parent = VisualTreeHelper.GetParent(Content.InnerControl) as FrameworkElement;

                if (parent != null)
                { 
                    // Invalidate ContentArea's measure so that scrollbar could be updated correctly.
                    parent.InvalidateMeasure(); 
                } 
            }
 
            //fire trace event
            EventTrace.NormalTraceEvent(EventTraceGuidId.ANNOTATIONINKCHANGEDGUID, EventType.StartEvent);

            // Update the Ink in the annotation. 
            UpdateAnnotationWithSNC(XmlToken.Ink);
            IsDirty = true; 
 
            //fire trace event
            EventTrace.NormalTraceEvent(EventTraceGuidId.ANNOTATIONINKCHANGEDGUID, EventType.EndEvent); 

        }

        ///  
        /// Initializes a StickyNoteControl's private members.
        ///  
        private void InitStickyNoteControl() 
        {
            //set the anchor as DataContext 
            XmlQualifiedName type = _stickyNoteType == StickyNoteType.Text ?
                                                                  TextSchemaName : InkSchemaName;
            _anchor = new MarkedHighlightComponent(type, this);
 
            IsDirty = false;
 
            //listen to Loaded event to set Focus if needed 
            Loaded += new RoutedEventHandler(OnLoadedEventHandler);
        } 

        /// 
        /// Create the listeners we will use to register on our InkCanvas when it gets created.
        /// Only called once this StickyNote is first used for ink content. 
        /// 
        private void InitializeEventHandlers() 
        { 
            _propertyDataChangedHandler = new StrokeChangedHandler(this);
            _strokeDrawingAttributesReplacedHandler = new StrokeChangedHandler(this); 
            _strokePacketDataChangedHandler = new StrokeChangedHandler(this);
        }

 
        /// 
        /// Listens for click events from the close button and the icon button. 
        /// Both cause the IsExpanded property to be negated. 
        /// 
        private void OnButtonClick(object sender, RoutedEventArgs e) 
        {
            bool currentExpanded = IsExpanded;
            IsExpanded = !currentExpanded;
        } 

        ///  
        /// Simple method that deletes the current annotation from the annotation store. 
        /// This is called in response to the DeleteNote command.
        ///  
        private void DeleteStickyNote()
        {
            Invariant.Assert(_attachedAnnotation != null, "AttachedAnnotation is null.");
            Invariant.Assert(_attachedAnnotation.Store != null, "AttachedAnnotation's Store is null."); 

            _attachedAnnotation.Store.DeleteAnnotation(_attachedAnnotation.Annotation.Id); 
        } 

        ///  
        /// Handles drag completed events for both thumbs in the Sticky Note Control.
        /// When the drag is completed, we write out the new values that might have changed.
        /// 
        private void OnDragCompleted(object sender, DragCompletedEventArgs args) 
        {
            Thumb source = args.Source as Thumb; 
 
            // Update the cached offsets of StickyNote
            if (source == GetTitleThumb()) 
            {
                // Update the Top and Left in the annotation.
                UpdateAnnotationWithSNC(XmlToken.XOffset | XmlToken.YOffset | XmlToken.Left | XmlToken.Top);
            } 
            else if (source == GetResizeThumb())
            { 
                // Update the Width and Height and Top and Left in the annotation. 
                UpdateAnnotationWithSNC(XmlToken.XOffset | XmlToken.YOffset | XmlToken.Width | XmlToken.Height | XmlToken.Left | XmlToken.Top);
            } 
        }

        /// 
        /// Called when either thumb is dragged.  We then process the drag in specific ways depending 
        /// on which thumb was dragged.
        ///  
        private void OnDragDelta(object sender, DragDeltaEventArgs args) 
        {
            Invariant.Assert(IsExpanded == true, "Dragging occurred when the StickyNoteControl was not expanded."); 

            Thumb source = args.Source as Thumb;
            double horizontalChange = args.HorizontalChange;
 
            // Because we are self-mirroring, we have flipped the layout within the note
            // but our environment isn't flipped.  The Thumb (within the note) is providing 
            // mirrored values but we will use them to position ourselves within the unmirrored 
            // environment, so we flip the values again before using them.
            if (_selfMirroring) 
            {
                horizontalChange = -horizontalChange;
            }
 
            if (source == GetTitleThumb())
            { 
                OnTitleDragDelta(horizontalChange, args.VerticalChange); 
            }
            else if (source == GetResizeThumb()) 
            {
                OnResizeDragDelta(args.HorizontalChange, args.VerticalChange);
            }
 
            // Update the cached offsets of StickyNote
            UpdateOffsets(); 
        } 

        ///  
        /// Handles dragging the title thumb.  This updates the StickyNoteControl's
        /// position.
        /// 
        private void OnTitleDragDelta(double horizontalChange, double verticalChange) 
        {
            Invariant.Assert(IsExpanded != false); 
 
            Rect rectNote = StickyNoteBounds;
            Rect rectPage = PageBounds; 

            // These are the minimum widths that must be visible when a note is partially off
            // the left or right side of a page.  The difference is due to the Close button
            // being on one side and wanting some of the title bar to be visible on that side. 
            double leftBoundary = 45;
            double rightBoundary = 20; 
 
            // Because we are self-mirroring, we need to flip the minimum widths
            if (_selfMirroring) 
            {
                double temp = rightBoundary;
                rightBoundary = leftBoundary;
                leftBoundary = temp; 
            }
 
            // Figure out the new position while enforcing a portion of the note being always on the page. 
            Point minBoundary = new Point(-(rectNote.X + rectNote.Width - leftBoundary), - rectNote.Y);
            Point maxBoundary = new Point(rectPage.Width - rectNote.X - rightBoundary, rectPage.Height - rectNote.Y - 20); 

            horizontalChange = Math.Min(Math.Max(minBoundary.X, horizontalChange), maxBoundary.X);
            verticalChange = Math.Min(Math.Max(minBoundary.Y, verticalChange), maxBoundary.Y);
 
            TranslateTransform currentTransform = PositionTransform;
 
            // Include any temporary delta we are currently using to avoid any visible jumping to the user 
            PositionTransform = new TranslateTransform(currentTransform.X + horizontalChange + _deltaX, currentTransform.Y + verticalChange + _deltaY);
            _deltaX = _deltaY = 0; 

            IsDirty = true;
        }
 

        ///  
        /// Handles dragging the bottom/right resize thumb.  Updates the StickyNoteControl's size. 
        /// 
        private void OnResizeDragDelta(double horizontalChange, double verticalChange) 
        {
            Invariant.Assert(IsExpanded != false);

            Rect rectNote = StickyNoteBounds; 

            double wNew = rectNote.Width + horizontalChange; 
            double hNew = rectNote.Height + verticalChange; 

            // This method doesn't apply during self-mirroring because 
            // we are actually moving the note during which time the note's
            // location is bounded by the page borders (plus a cushion).
            if (!_selfMirroring)
            { 
                // If the new size would put the right side of the SN off the page
                // we don't allow that resize anymore. 
                if (rectNote.X + wNew < 45) 
                    wNew = rectNote.Width;
            } 

            double minWidth = MinWidth;
            double minHeight = MinHeight;
 
            if (wNew < minWidth)
            { 
                wNew = minWidth; 
                // This is only used in self-mirroring - if we clamp the size change,
                // we must also clamp the move (see below) 
                horizontalChange = wNew - this.Width;
            }

            if (hNew < minHeight) 
            {
                hNew = minHeight; 
            } 

            SetValue(WidthProperty, wNew); 
            SetValue(HeightProperty, hNew);

            // Because we are self-mirroring, as the note changes size we have to
            // move it to make it appear its changing size from the left (where the 
            // resize handle is located during mirroring) instead of the right which
            // is what is actually happening. 
            if (_selfMirroring) 
            {
                OnTitleDragDelta(-horizontalChange, 0); 
            }
            else
            {
                // This appears to be a no-op but OnTitleDragDelta also takes 
                // care of applying permanently any temporary offsets
                OnTitleDragDelta(0, 0); 
            } 

            IsDirty = true; 
        }

        /// 
        /// Any click in the StickyNoteControl brings it to the top in z-order and 
        /// requests the focus.
        /// Additionally we must `swallow the event here if the click happend on 
        /// our InkCanvas because the RTI engine isn't setup yet and the user will 
        /// be creating ink without seeing it.
        ///  
        private void OnPreviewDeviceDown(object dc, InputEventArgs args)
        {
            if (IsExpanded)
            { 
                bool eatEvent = false;
 
                if (!IsKeyboardFocusWithin && this.StickyNoteType == StickyNoteType.Ink) 
                {
                    // Only event we want to `swallow here is a click on the InkCanvas 
                    // when the StickyNote isn't focused because RTI isn't set up yet
                    Visual source = args.OriginalSource as Visual;
                    if (source != null)
                    { 
                        Invariant.Assert(Content.InnerControl != null, "InnerControl is null.");
                        eatEvent = source.IsDescendantOf(this.Content.InnerControl); 
                    } 
                }
 
                // Will have no effect if already in front
                BringToFront();

                if (!IsActive || !IsKeyboardFocusWithin) 
                {
                    Focus(); 
                } 

                if (eatEvent == true) 
                {
                    args.Handled = true;
                }
            } 
        }
 
        ///  
        /// Set the focus on SN if needed
        ///  
        /// sender - not used
        /// arguments - not used
        private void OnLoadedEventHandler(object sender, RoutedEventArgs e)
        { 
            if (IsExpanded)
            { 
                // Setup the inner controls with the Annotation's data - we must have correct 
                // values for SN sizes before Focus->BringIntoView is invoked
                UpdateSNCWithAnnotation(SNCAnnotation.Sizes); 

                if (_sncAnnotation.IsNewAnnotation)
                {
                    // NTRAID#WINOS-1169084-2005/05/19-WAYNEZEN 
                    // After the annotations has been added, we should set focus on the element.
                    Focus(); 
                } 
            }
 
            //unregister
            Loaded -= new RoutedEventHandler(OnLoadedEventHandler);
        }
 

        ///  
        /// Unregister from any events on the current visual tree.  Also disconnect the current 
        /// content control.
        ///  
        private void ClearCachedControls()
        {
            if (Content != null)
            { 
                // Disconnect the content control which will be re-connected to the new ContentControl
                // in ApplyTemplate when the new visual tree is populated from the new control template. 
                DisconnectContent(); 
            }
 
            Button closeButton = GetCloseButton();
            if (closeButton != null)
            {
                closeButton.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonClick)); 
            }
 
            Button iconButton = GetIconButton(); 
            if (iconButton != null)
            { 
                iconButton.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonClick));
            }

            Thumb titleThumb = GetTitleThumb(); 
            if (titleThumb != null)
            { 
                titleThumb.RemoveHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta)); 
                titleThumb.RemoveHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted));
            } 

            Thumb resizeThumb = GetResizeThumb();
            if (resizeThumb != null)
            { 
                resizeThumb.RemoveHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta));
                resizeThumb.RemoveHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted)); 
            } 
        }
 
        /// 
        /// Called when this StickyNoteControl's IsExpanded property changes.
        /// 
        private void OnIsExpandedChanged() 
        {
            InvalidateTransform(); 
 
            // Update the Iconized in the annotation.
            UpdateAnnotationWithSNC(XmlToken.IsExpanded); 

            IsDirty = true;

            if (IsExpanded) 
            {
                BringToFront(); 
                // We request the focus from a dispatcher callback because we may 
                // have been called from a
                this.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(AsyncTakeFocus), null); 
            }
            else
            {
                GiveUpFocus(); 
                SendToBack();
            } 
        } 

        ///  
        /// Requests focus to this control.  Used asynchronously from event handlers
        /// to prevent other event handlers from stealing focus right back.
        /// 
        private object AsyncTakeFocus(object notUsed) 
        {
            this.Focus(); 
 
            return null;
        } 

        /// 
        /// If focus us within this control, sets the focus on the first element in the attached
        /// annotation's parent's ancestor chain that accepts it.  If no element accepts it, 
        /// then focus is set to null.
        ///  
        private void GiveUpFocus() 
        {
            // Only send focus away when we actually have it. 
            if (IsKeyboardFocusWithin)
            {
                // Start with the attached annotation's parent,
                // walk up the tree looking for the first element 
                // to take focus.
                bool transferred = false; 
                DependencyObject parent = _attachedAnnotation.Parent; 
                IInputElement newFocus = null;
 
                while (parent != null && !transferred)
                {
                    newFocus = parent as IInputElement;
                    if (newFocus != null) 
                    {
                        transferred = newFocus.Focus(); 
                    } 

                    // Go up the parent chain if focus wasn't taken 
                    if (!transferred)
                    {
                        parent = FrameworkElement.GetFrameworkParent(parent);
                    } 
                }
 
                // If no element was found, just give up focus 
                if (!transferred)
                { 
                    Keyboard.Focus(null);
                }
            }
        } 

        ///  
        /// Request this control be sent to the front of the z-order stack in its 
        /// presentation context.  Call to PresentationContext should have no affect
        /// if its already at the front. 
        /// 
        private void BringToFront()
        {
            PresentationContext pc = ((IAnnotationComponent)this).PresentationContext; 
            if ( pc != null )
            { 
                pc.BringToFront(this); 
            }
        } 

        /// 
        /// Request this control be sent to the back of the z-order stack in its
        /// presentation context.  Call to PresentationContext should have no affect 
        /// if its already at the back.
        ///  
        private void SendToBack() 
        {
            PresentationContext pc = ((IAnnotationComponent)this).PresentationContext; 
            if (pc != null)
            {
                pc.SendToBack(this);
            } 
        }
 
        ///  
        /// Invalidate the Transform for this control in its presentation context.
        ///  
        private void InvalidateTransform()
        {
            PresentationContext pc = ((IAnnotationComponent)this).PresentationContext;
            if ( pc != null ) 
            {
                pc.InvalidateTransform(this); 
            } 
        }
 
        /// 
        /// Updates the attached annotation with the data currently in this control.
        /// Called asynchronously from event handler because TextBox can't handle
        /// changing its content from an event handler.  // Do we need this to be async? 
        /// 
        private object AsyncUpdateAnnotation(object arg) 
        { 
            UpdateAnnotationWithSNC((XmlToken)arg);
            return null; 
        }

        /// 
        /// This binds a new content control's properties to those set on 
        /// the StickyNoteControl.  Should be called each time a new content
        /// control is created. 
        ///  
        private void BindContentControlProperties()
        { 
            Invariant.Assert(Content != null);

            // ISSUE-2005/03/23/WAYNEZEN,
            // Somehow, the bound font family can't be loaded again by Parser once the attribute persists in XAML. 
            // Since InkCanvas doesn't care about FontFamily, we just walk the issue around by not binding the property.
            if (Content.Type != StickyNoteType.Ink) 
            { 
                FrameworkElement innerControl = Content.InnerControl;
                innerControl.SetValue(FontFamilyProperty, GetValue(FontFamilyProperty)); 
                innerControl.SetValue(FontSizeProperty, GetValue(FontSizeProperty));
                innerControl.SetValue(FontStretchProperty, GetValue(FontStretchProperty));
                innerControl.SetValue(FontStyleProperty, GetValue(FontStyleProperty));
                innerControl.SetValue(FontWeightProperty, GetValue(FontWeightProperty)); 
                innerControl.SetValue(ForegroundProperty, GetValue(ForegroundProperty));
            } 
            else 
            {
                // Create a TwoWay MultiBinding for InkCanvas.EditingMode. 
                // The internal InkCanvas' EditingMode will be determined by
                // both StickyNoteControl.InkEditingMode and StickyNoteControl.IsKeyboardFocusWithin
                // If StickyNoteControl.IsKeyboardFocusWithin is false, the InkCanvas.EditingMode should be none.
                // Otherwise InkCanvas.EditingMode is same as the StickyNoteControl.InkEditingMode. 
                MultiBinding inkCanvasEditingMode = new MultiBinding();
                inkCanvasEditingMode.Mode = BindingMode.TwoWay; 
                inkCanvasEditingMode.Converter = new InkEditingModeIsKeyboardFocusWithin2EditingMode(); 

                Binding stickyNoteInkEditingMode = new Binding(); 
                stickyNoteInkEditingMode.Mode = BindingMode.TwoWay;
                stickyNoteInkEditingMode.Path = new PropertyPath(StickyNoteControl.InkEditingModeProperty);
                stickyNoteInkEditingMode.Source = this;
 
                inkCanvasEditingMode.Bindings.Add(stickyNoteInkEditingMode);
 
                Binding stickyNoteIsKeyboardFocusWithin = new Binding(); 
                stickyNoteIsKeyboardFocusWithin.Path = new PropertyPath(UIElement.IsKeyboardFocusWithinProperty);
                stickyNoteIsKeyboardFocusWithin.Source = this; 

                inkCanvasEditingMode.Bindings.Add(stickyNoteIsKeyboardFocusWithin);

                Content.InnerControl.SetBinding(InkCanvas.EditingModeProperty, inkCanvasEditingMode); 
            }
        } 
 
        /// 
        /// Removes the bindings we previously created between the content control 
        /// and the StickyNoteControl.
        /// 
        private void UnbindContentControlProperties()
        { 
            Invariant.Assert(Content != null);
 
            FrameworkElement innerControl = (FrameworkElement)Content.InnerControl; 
            if (Content.Type != StickyNoteType.Ink)
            { 
                innerControl.ClearValue(FontFamilyProperty);
                innerControl.ClearValue(FontSizeProperty);
                innerControl.ClearValue(FontStretchProperty);
                innerControl.ClearValue(FontStyleProperty); 
                innerControl.ClearValue(FontWeightProperty);
                innerControl.ClearValue(ForegroundProperty); 
            } 
            else
            { 
                BindingOperations.ClearBinding(innerControl, InkCanvas.EditingModeProperty);
            }
        }
 
        /// 
        /// Registers for change events from the content control.  This lets us 
        /// update the annotation when something in the controls change.  Should 
        /// be called when a new content control is created.
        ///  
        private void StartListenToContentControlEvent()
        {
            Invariant.Assert(Content != null);
 
            if (Content.Type == StickyNoteType.Ink)
            { 
                InkCanvas inkCanvas = Content.InnerControl as InkCanvas; 
                Invariant.Assert(inkCanvas != null, "InnerControl is not an InkCanvas for note of type Ink.");
                inkCanvas.StrokesReplaced += new InkCanvasStrokesReplacedEventHandler(OnInkCanvasStrokesReplacedEventHandler); 
                inkCanvas.SelectionMoving += new InkCanvasSelectionEditingEventHandler(OnInkCanvasSelectionMovingEventHandler);
                inkCanvas.SelectionResizing += new InkCanvasSelectionEditingEventHandler(OnInkCanvasSelectionResizingEventHandler);
                StartListenToStrokesEvent(inkCanvas.Strokes);
            } 
            else
            { 
                TextBoxBase textBoxBase = Content.InnerControl as TextBoxBase; 
                Invariant.Assert(textBoxBase != null, "InnerControl is not a TextBoxBase for note of type Text.");
                textBoxBase.TextChanged += new TextChangedEventHandler(OnTextChanged); 
            }
        }

        ///  
        /// Unregisters for any events from the content control.  Should be called
        /// when a content control is being changed. 
        ///  
        private void StopListenToContentControlEvent()
        { 
            Invariant.Assert(Content != null);

            if (Content.Type == StickyNoteType.Ink)
            { 
                InkCanvas inkCanvas = Content.InnerControl as InkCanvas;
                Invariant.Assert(inkCanvas != null, "InnerControl is not an InkCanvas for note of type Ink."); 
                inkCanvas.StrokesReplaced -= new InkCanvasStrokesReplacedEventHandler(OnInkCanvasStrokesReplacedEventHandler); 
                inkCanvas.SelectionMoving -= new InkCanvasSelectionEditingEventHandler(OnInkCanvasSelectionMovingEventHandler);
                inkCanvas.SelectionResizing -= new InkCanvasSelectionEditingEventHandler(OnInkCanvasSelectionResizingEventHandler); 
                StopListenToStrokesEvent(inkCanvas.Strokes);
            }
            else
            { 
                TextBoxBase textBoxBase = Content.InnerControl as TextBoxBase;
                Invariant.Assert(textBoxBase != null, "InnerControl is not a TextBoxBase for note of type Text."); 
                textBoxBase.TextChanged -= new TextChangedEventHandler(OnTextChanged); 
            }
        } 

        /// 
        /// Register for events on the StrokeCollection from the InkCanvas.
        ///  
        private void StartListenToStrokesEvent(StrokeCollection strokes)
        { 
            strokes.StrokesChanged += new StrokeCollectionChangedEventHandler(OnInkStrokesChanged); 
            strokes.PropertyDataChanged += new PropertyDataChangedEventHandler(_propertyDataChangedHandler.OnStrokeChanged);
            StartListenToStrokeEvent(strokes); 
        }

        /// 
        /// Unregister for events on the StrokeCollection from the InkCanvas. 
        /// 
        private void StopListenToStrokesEvent(StrokeCollection strokes) 
        { 
            strokes.StrokesChanged -= new StrokeCollectionChangedEventHandler(OnInkStrokesChanged);
            strokes.PropertyDataChanged -= new PropertyDataChangedEventHandler(_propertyDataChangedHandler.OnStrokeChanged); 
            StopListenToStrokeEvent(strokes);
        }

        ///  
        /// Register on each stroke in the InkCanvas.  If any of them change we need to know about it.
        ///  
        private void StartListenToStrokeEvent(IEnumerable strokes) 
        {
            foreach (Stroke s in strokes) 
            {
                s.DrawingAttributes.AttributeChanged += new PropertyDataChangedEventHandler(
                                                            _propertyDataChangedHandler.OnStrokeChanged);
                s.DrawingAttributesReplaced += new DrawingAttributesReplacedEventHandler( 
                                                            _strokeDrawingAttributesReplacedHandler.OnStrokeChanged);
                s.StylusPointsReplaced +=               new StylusPointsReplacedEventHandler( 
                                                            _strokePacketDataChangedHandler.OnStrokeChanged); 
                s.StylusPoints.Changed +=               new EventHandler(
                                                            _strokePacketDataChangedHandler.OnStrokeChanged); 
                s.PropertyDataChanged +=                new PropertyDataChangedEventHandler(
                                                            _propertyDataChangedHandler.OnStrokeChanged);
            }
        } 

        ///  
        /// Unregister on each stroke in the InkCanvas.  We previously registered on each stroke and 
        /// now need to disconnect from them.
        ///  
        private void StopListenToStrokeEvent(IEnumerable strokes)
        {
            foreach (Stroke s in strokes)
            { 
                s.DrawingAttributes.AttributeChanged -= new PropertyDataChangedEventHandler(
                                                            _propertyDataChangedHandler.OnStrokeChanged); 
                s.DrawingAttributesReplaced -= new DrawingAttributesReplacedEventHandler( 
                                                            _strokeDrawingAttributesReplacedHandler.OnStrokeChanged);
                s.StylusPointsReplaced  -=              new StylusPointsReplacedEventHandler( 
                                                            _strokePacketDataChangedHandler.OnStrokeChanged);
                s.StylusPoints.Changed -=               new EventHandler(
                                                            _strokePacketDataChangedHandler.OnStrokeChanged);
                s.PropertyDataChanged -=                new PropertyDataChangedEventHandler( 
                                                            _propertyDataChangedHandler.OnStrokeChanged);
            } 
        } 

        ///  
        /// Set bindings on the menuitems which StickyNote knows about
        /// 
        private void SetupMenu()
        { 
            MenuItem inkMenuItem = GetInkMenuItem();
            if (inkMenuItem != null) 
            { 
                // Bind the EditingMode to item's IsChecked DP.
                Binding checkedBind = new Binding("InkEditingMode"); 
                checkedBind.Mode = BindingMode.OneWay;
                checkedBind.RelativeSource = RelativeSource.TemplatedParent;
                checkedBind.Converter = new InkEditingModeConverter();
                checkedBind.ConverterParameter = InkCanvasEditingMode.Ink; 
                inkMenuItem.SetBinding(MenuItem.IsCheckedProperty, checkedBind);
            } 
 
            MenuItem selectMenuItem = GetSelectMenuItem();
            if (selectMenuItem != null) 
            {
                // Bind the EditingMode to item's IsChecked DP.
                Binding checkedBind = new Binding("InkEditingMode");
                checkedBind.Mode = BindingMode.OneWay; 
                checkedBind.RelativeSource = RelativeSource.TemplatedParent;
                checkedBind.Converter = new InkEditingModeConverter(); 
                checkedBind.ConverterParameter = InkCanvasEditingMode.Select; 
                selectMenuItem.SetBinding(MenuItem.IsCheckedProperty, checkedBind);
            } 

            MenuItem eraseMenuItem = GetEraseMenuItem();
            if (eraseMenuItem != null)
            { 
                // Bind the EditingMode to item's IsChecked DP.
                Binding checkedBind = new Binding("InkEditingMode"); 
                checkedBind.Mode = BindingMode.OneWay; 
                checkedBind.RelativeSource = RelativeSource.TemplatedParent;
                checkedBind.Converter = new InkEditingModeConverter(); 
                checkedBind.ConverterParameter = InkCanvasEditingMode.EraseByStroke;
                eraseMenuItem.SetBinding(MenuItem.IsCheckedProperty, checkedBind);
            }
 
            // Copy and Paste menu items (and their separator) are removed if
            // we don't have Clipboard permissions. 
            bool hasClipboardPermission = SecurityHelper.CallerHasAllClipboardPermission(); 

            // Set the target for the Copy/Paste commands to our inner control 
            MenuItem copyMenuItem = GetCopyMenuItem();
            if (copyMenuItem != null)
            {
                if (hasClipboardPermission) 
                {
                    copyMenuItem.CommandTarget = Content.InnerControl; 
                } 
                else
                { 
                    copyMenuItem.Visibility = Visibility.Collapsed;
                }
            }
 
            MenuItem pasteMenuItem = GetPasteMenuItem();
            if (pasteMenuItem != null) 
            { 
                if (hasClipboardPermission)
                { 
                    pasteMenuItem.CommandTarget = Content.InnerControl;
                }
                else
                { 
                    pasteMenuItem.Visibility = Visibility.Collapsed;
                } 
            } 

            Separator clipboardSeparator = GetClipboardSeparator(); 
            if (clipboardSeparator != null)
            {
                if (!hasClipboardPermission)
                { 
                    clipboardSeparator.Visibility = Visibility.Collapsed;
                } 
            } 
        }
 

        /// 
        /// CommandExecuted Handler - processes the commands for SNC.
        ///     DeleteNoteCommand - deletes the annotation from the store (causing the SNC to disappear) 
        ///     InkCommand - changes the mode of the ink canvas
        ///     Copy/Paste - we pass on to our inner control 
        ///  
        /// 
        ///  
        private static void _OnCommandExecuted(object sender, ExecutedRoutedEventArgs args)
        {
            RoutedCommand command = (RoutedCommand)(args.Command);
            StickyNoteControl snc = sender as StickyNoteControl; 

            Invariant.Assert(snc != null, "Unexpected Commands"); 
            Invariant.Assert(command == StickyNoteControl.DeleteNoteCommand 
                || command == StickyNoteControl.InkCommand, "Unknown Commands");
 
            if ( command == StickyNoteControl.DeleteNoteCommand )
            {
                // DeleteNote Command
                snc.DeleteStickyNote(); 
            }
            else if (command == StickyNoteControl.InkCommand) 
            { 
                StickyNoteContentControl content = snc.Content;
 
                if (content == null || content.Type != StickyNoteType.Ink)
                {
                    throw new InvalidOperationException(SR.Get(SRID.CannotProcessInkCommand));
                } 

                // Set the StickyNoteControl's ink editing mode to the command's parameter 
                InkCanvasEditingMode mode = (InkCanvasEditingMode)args.Parameter; 
                snc.SetValue(InkEditingModeProperty, mode);
            } 
        }

        /// 
        /// QueryCommandEnabled Handler - determines if a command should be enabled or not. 
        ///   DeleteNoteCommand - if the SNC has an attached annotation
        ///   InkCommand - if the SNC is of type InkStickyNote 
        ///   AllOthers - if focus is on our inner control, we let the inner control decide, 
        ///               otherwise we return false
        ///  
        private static void _OnQueryCommandEnabled(object sender, CanExecuteRoutedEventArgs args)
        {
            RoutedCommand command = (RoutedCommand)( args.Command );
            StickyNoteControl snc = sender as StickyNoteControl; 

            Invariant.Assert(snc != null, "Unexpected Commands"); 
            Invariant.Assert(command == StickyNoteControl.DeleteNoteCommand 
                || command == StickyNoteControl.InkCommand, "Unknown Commands");
 
            if ( command == StickyNoteControl.DeleteNoteCommand )
            {
                // Enable/Disable DeleteNote Command based on the Attached Annotation.
                args.CanExecute = snc._attachedAnnotation != null; 
            }
            else if (command == StickyNoteControl.InkCommand) 
            { 
                StickyNoteContentControl content = snc.Content;
 
                // Enabled/Disable InkCommand based on the StickyNote type
                args.CanExecute = (content != null && content.Type == StickyNoteType.Ink);
            }
            else 
            {
                Invariant.Assert(false, "Unknown command."); 
            } 
        }
 

        /// 
        /// Update DrawingAttributes on InkCanvas
        ///  
        private void UpdateInkDrawingAttributes()
        { 
            if ( Content == null || Content.Type != StickyNoteType.Ink ) 
            {
                // Return now if there is no InkCanvas. 
                return;
            }

            DrawingAttributes da = new DrawingAttributes(); 

            SolidColorBrush foreground = Foreground as SolidColorBrush; 
 
            // Make sure the foreground is type of SolidColorBrush.
            if ( foreground == null ) 
            {
                throw new ArgumentException(SR.Get(SRID.InvalidInkForeground), "Foreground");
            }
 
            da.StylusTip = StylusTip.Ellipse;
            da.Width = PenWidth; 
            da.Height = PenWidth; 
            da.Color = foreground.Color;
 
            // Update the DA on InkCanvas.
            ( (InkCanvas)( Content.InnerControl ) ).DefaultDrawingAttributes = da;
        }
 
        #endregion // Private Methods
 
        //-------------------------------------------------------------------------------- 
        //
        // Private Properties 
        //
        //-------------------------------------------------------------------------------

        #region Private Properties 

        ///  
        /// Returns Ink MenuItem 
        /// 
        private MenuItem GetInkMenuItem() 
        {
            return GetTemplateChild(SNBConstants.c_InkMenuId) as MenuItem;
        }
 
        /// 
        /// Returns Select MenuItem 
        ///  
        private MenuItem GetSelectMenuItem()
        { 
            return GetTemplateChild(SNBConstants.c_SelectMenuId) as MenuItem;
        }

        ///  
        /// Returns Erase MenuItem
        ///  
        private MenuItem GetEraseMenuItem() 
        {
            return GetTemplateChild(SNBConstants.c_EraseMenuId) as MenuItem; 
        }

        /// 
        /// Returns Copy MenuItem 
        /// 
        private MenuItem GetCopyMenuItem() 
        { 
            return GetTemplateChild(SNBConstants.c_CopyMenuId) as MenuItem;
        } 

        /// 
        /// Returns Paste MenuItem
        ///  
        private MenuItem GetPasteMenuItem()
        { 
            return GetTemplateChild(SNBConstants.c_PasteMenuId) as MenuItem; 
        }
 
        /// 
        /// Returns Separator for clipboard MenuItems
        /// 
        private Separator GetClipboardSeparator() 
        {
            return GetTemplateChild(SNBConstants.c_ClipboardSeparatorId) as Separator; 
        } 

        // This is the getter of _lockHelper which is a helper object for locking/unlocking a specified flag automatically. 
        private LockHelper InternalLocker
        {
            get
            { 
                // Check if we have create a helper. If not, we go ahead create one.
                if (_lockHelper == null) 
                { 
                    _lockHelper = new LockHelper();
                } 

                return _lockHelper;
            }
        } 

        #endregion // Private Properties 
 
        //-------------------------------------------------------------------------------
        // 
        // Private Fields
        //
        //-------------------------------------------------------------------------------
 
        #region Private Fields
 
        private LockHelper _lockHelper; 

        private MarkedHighlightComponent _anchor; //holds inactive, active, focused state 

        private bool _dirty = false;

        // Cache for the dependency properties 
        private StickyNoteType _stickyNoteType = StickyNoteType.Text;
 
        private StickyNoteContentControl _contentControl; 

        private StrokeChangedHandler _propertyDataChangedHandler; 
        private StrokeChangedHandler _strokeDrawingAttributesReplacedHandler;
        private StrokeChangedHandler _strokePacketDataChangedHandler;

        #endregion // Private Fields 

 
 
        //--------------------------------------------------------------------------------
        // 
        // Private classes
        //
        //-------------------------------------------------------------------------------
 
        #region Private classes
 
        // This is a binding converter which alters the IsChecked DP based on ink StickyNote's EditingMode of its InkCanvas. 
        private class InkEditingModeConverter : IValueConverter
        { 
            public object Convert(object o, Type type, object parameter, CultureInfo culture)
            {
                InkCanvasEditingMode expectedMode = (InkCanvasEditingMode)parameter;
                InkCanvasEditingMode currentMode = (InkCanvasEditingMode)o; 

                // If the current EditingMode is the mode which menuitem is expecting, return true for IsChecked. 
                if ( currentMode == expectedMode ) 
                {
                    return true; 
                }
                else
                {
                    return DependencyProperty.UnsetValue; 
                }
            } 
 
            public object ConvertBack(object o, Type type, object parameter, CultureInfo culture)
            { 
                return null;
            }
        }
 
        // This is a binding converter which alters the InkCanvas.EditingMode DP
        // based on StickyNoteControl.InkEditingMode and StickyNoteControl.IsKeyboardFocusWithin. 
        private class InkEditingModeIsKeyboardFocusWithin2EditingMode : IMultiValueConverter 
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
            {
                InkCanvasEditingMode sncInkEditingMode = (InkCanvasEditingMode)values[0];

                bool sncIsKeyboardFocusWithin = (bool)values[1]; 

                // If there is no focus on the StickyNote, we should return InkCanvasEditingMode.None to disable the RTI. 
                // Otherwise return the  value of the StickyNoteControl.InkEditingMode property. 
                if ( sncIsKeyboardFocusWithin )
                { 
                    return sncInkEditingMode;
                }
                else
                { 
                    return InkCanvasEditingMode.None;
                } 
            } 

            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
            {
                return new object[] { value, Binding.DoNothing };
            }
        } 

        // A helper class which suppresses severial handlers to a single methods by using generic 
        private class StrokeChangedHandler 
        {
            public StrokeChangedHandler(StickyNoteControl snc) 
            {
                Invariant.Assert(snc != null);
                _snc = snc;
            } 

            public void OnStrokeChanged(object sender, TEventArgs t) 
            { 
                // Dirty the ink data
                _snc.UpdateAnnotationWithSNC(XmlToken.Ink); 
                _snc._dirty = true;
            }

            private StickyNoteControl _snc; 
        }
 
        #endregion Private classes 

    } 
}


 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
// In order to disable Presharp warning 6507 - Prefer 'string.IsNullOrEmpty(value)' over checks for null and/or emptiness, 
// we have to disable warnings 1634 and 1691 to make the compiler happy first.
#pragma warning disable 1634, 1691

//---------------------------------------------------------------------------- 
//
//  
//    Copyright (C) Microsoft Corporation.  All rights reserved. 
// 
// 
//
// Description: Implementation of StickyNoteControl control.
//
//              See spec at http://tabletpc/longhorn/Specs/StickyNoteControlSpec.mht 
//
// History: 
//  04/19/2004 - waynezen - Expose more properties and methods 
//  02/17/2004 - waynezen - Moved to TabletFramework
//  10/06/2003 - waynezen - Added Ink and Snippet Image supports 
//  09/23/2003 - waynezen - Ported to WCP.
//  12/16/2002 - waynezen - Created.
//
//--------------------------------------------------------------------------- 

using System; 
using System.ComponentModel; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.Collections.Specialized;
using System.Diagnostics;                           // Assert
using System.Globalization;
using System.IO; 
using System.Reflection;
using System.Xml; 
using System.Xml.Serialization; 
using Microsoft.Win32;              // SystemEvents
using MS.Internal; 
using MS.Internal.Annotations.Component;
using MS.Internal.Controls.StickyNote;
using MS.Internal.Commands;
using MS.Internal.KnownBoxes; 
using MS.Internal.PresentationFramework;
using System.Windows.Threading; 
using System.Windows; 
using System.Windows.Data;
using System.Windows.Annotations; 
using System.Windows.Automation;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Ink; 
using System.Windows.Input;
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes;
using System.Text; 
using System.Text.RegularExpressions;
using MS.Utility;

 
namespace System.Windows.Controls
{ 
    ///  
    /// The type of data handled by a StickyNoteControl.
    ///  
    public enum StickyNoteType
    {
        /// 
        /// Text StickyNote 
        /// 
        Text, 
        ///  
        /// Ink StickyNote
        ///  
        Ink,
    }

 
    /// 
    /// StickyNoteControl control intends to be an UI control for user to make annotation. 
    ///  
    [TemplatePart(Name = SNBConstants.c_CloseButtonId, Type = typeof(Button))]
    [TemplatePart(Name = SNBConstants.c_TitleThumbId, Type = typeof(Thumb))] 
    [TemplatePart(Name = SNBConstants.c_BottomRightResizeThumbId, Type = typeof(Thumb))]
    [TemplatePart(Name = SNBConstants.c_ContentControlId, Type = typeof(ContentControl))]
    [TemplatePart(Name = SNBConstants.c_IconButtonId, Type = typeof(Button))]
    [TemplatePart(Name = SNBConstants.c_CopyMenuId, Type = typeof(MenuItem))] 
    [TemplatePart(Name = SNBConstants.c_PasteMenuId, Type = typeof(MenuItem))]
    [TemplatePart(Name = SNBConstants.c_InkMenuId, Type = typeof(MenuItem))] 
    [TemplatePart(Name = SNBConstants.c_SelectMenuId, Type = typeof(MenuItem))] 
    [TemplatePart(Name = SNBConstants.c_EraseMenuId, Type = typeof(MenuItem))]
    public sealed partial class StickyNoteControl : Control, 
        IAnnotationComponent
    {
        //-------------------------------------------------------------------------------
        // 
        // Constructors
        // 
        //------------------------------------------------------------------------------- 

        #region Constructors 

        /// 
        /// The static constructor
        ///  
        static StickyNoteControl()
        { 
            Type owner = typeof(StickyNoteControl); 

            // Register event handlers 
            // NTRAID-WINDOWS#1136774-WAYNEZEN,
            // We want to bring a note to front when the input device is pressed down on it at the first time.
            // StickyNote invokes PresentationContext.BringToFront method to achieve it.
            // Eventually the Annotation AdornerLayer will re-arrange index of its children to change their "Z-Order". 
            // So, the BringToFront could temporarily remove StickyNote from the visual tree.
            // But the hosted InkCanvas might capture Stylus for collecting packets. If the host note is removed from the tree, the capture 
            // will be released automatically which will mess up the InkCanvas' states. 
            // So we have to do BringToFront before InkCanvas does capture. Adding a handler of PreviewStylusDownEvent fixes the problem.
            // Unfortunately we still need the existing handler of PreviewMouseDownEvent since there is no stylus event for text StickyNote. 

            //

 
            EventManager.RegisterClassHandler(owner, Stylus.PreviewStylusDownEvent, new StylusDownEventHandler(_OnPreviewDeviceDown));
            EventManager.RegisterClassHandler(owner, Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(_OnPreviewDeviceDown)); 
            EventManager.RegisterClassHandler(owner, Mouse.MouseDownEvent, new MouseButtonEventHandler(_OnDeviceDown)); 
            EventManager.RegisterClassHandler(owner, ContextMenuService.ContextMenuOpeningEvent, new ContextMenuEventHandler(_OnContextMenuOpening));
 
            CommandHelpers.RegisterCommandHandler(typeof(StickyNoteControl), StickyNoteControl.DeleteNoteCommand,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled));
            CommandHelpers.RegisterCommandHandler(typeof(StickyNoteControl), StickyNoteControl.InkCommand,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled)); 

            // 
            // set the main style CRK to the default theme style key 
            //
            DefaultStyleKeyProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata( 
                new ComponentResourceKey(typeof(PresentationUIStyleResources), "StickyNoteControlStyleKey")));

            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
            Control.IsTabStopProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(false)); 

            // Override the changed callback of the Foreground Property. 
            ForegroundProperty.OverrideMetadata( 
                    owner,
                    new FrameworkPropertyMetadata(new PropertyChangedCallback(_UpdateInkDrawingAttributes))); 

            FontFamilyProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged)));
            FontSizeProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged)));
            FontStretchProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged))); 
            FontStyleProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged)));
            FontWeightProperty.OverrideMetadata(owner, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnFontPropertyChanged))); 
        } 

        ///  
        /// This is an instance constructor for StickyNoteControl class.  Should not be used
        /// 
        private StickyNoteControl() : this(StickyNoteType.Text)
        { 
        }
 
        ///  
        /// Creates an instance of StickyNoteControl that handles the specified type.
        ///  
        /// the type of data to be handled by the StickyNoteControl
        internal StickyNoteControl(StickyNoteType type) : base()
        {
            _stickyNoteType = type; 
            SetValue(StickyNoteTypePropertyKey, type);
            InitStickyNoteControl(); 
        } 

        #endregion // Constructors 

        //--------------------------------------------------------------------------------
        //
        // Public Methods 
        //
        //------------------------------------------------------------------------------- 
 
        #region Public Methods
 

        /// 
        /// Override OnApplyTemplate method. This method will ensure whether the created visual is one which
        /// StickyNoteControl expects. If so, the internal controls will be cached and Annotation will be applied 
        /// to the UI status.
        ///  
        /// Whether Visuals were added to the tree 
        public override void OnApplyTemplate()
        { 
            // No need for calling VerifyAccess since we call the method on the base here.
            base.OnApplyTemplate();

            // Ensure the type 
            if (this.IsExpanded)
            { 
                EnsureStickyNoteType(); 
            }
 
            // Setup the inner controls with the Annotation's data
            UpdateSNCWithAnnotation(SNCAnnotation.AllValues);

            // If the visual tree just gets populated from the new style, we have to add our event handles to the individual 
            // elements.
            if (!this.IsExpanded) 
            { 
                Button button = GetIconButton();
                if (button != null) 
                {
                    button.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonClick));
                }
            } 
            else
            { 
                Button closeButton = GetCloseButton(); 
                if (closeButton != null)
                { 
                    closeButton.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonClick));
                }

                Thumb titleThumb = GetTitleThumb(); 
                if (titleThumb != null)
                { 
                    titleThumb.AddHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta)); 
                    titleThumb.AddHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted));
                } 

                Thumb resizeThumb = GetResizeThumb();
                if (resizeThumb != null)
                { 
                    resizeThumb.AddHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta));
                    resizeThumb.AddHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted)); 
                } 

                // Set up the bindings to the menuitems. 
                SetupMenu();
            }
        }
 
        #endregion // Public Methods
 
        //-------------------------------------------------------------------------------- 
        //
        // Public Properties 
        //
        //--------------------------------------------------------------------------------

        #region Public Properties 

        ///  
        /// The property key of Author 
        /// 
        internal static readonly DependencyPropertyKey AuthorPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "Author",
                        typeof(string),
                        typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(String.Empty));
 
        ///  
        /// Author Dependency Property
        ///  
        public static readonly DependencyProperty AuthorProperty = AuthorPropertyKey.DependencyProperty;

        /// 
        /// Returns the author of the annotation the StickyNoteControl is editing. 
        /// 
        public String Author 
        { 
            get
            { 
                return (String)GetValue(StickyNoteControl.AuthorProperty);
            }
        }
 
        /// 
        /// Gets/Sets the expanded or minimized state of the StickyNoteControl. 
        /// If Expanded=false, the bubble is in a minimized state. 
        /// 
        public static readonly DependencyProperty IsExpandedProperty = 
                DependencyProperty.Register(
                        "IsExpanded",
                        typeof(bool),
                        typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(
                                BooleanBoxes.TrueBox, 
                                new PropertyChangedCallback(_OnIsExpandedChanged))); 

        ///  
        /// Gets/Sets the expanded or minimized state of the StickyNoteControl.
        /// 
        public bool IsExpanded
        { 
            get { return (bool) GetValue(IsExpandedProperty); }
            set { SetValue(IsExpandedProperty, value); } 
        } 

        ///  
        /// true - StickyNoteControl is active (i.e. has the focus or selection includes part of its anchor)
        ///The value of this property is set by the MarkedHighlightComponent which controls the SN state
        /// 
        public static readonly DependencyProperty IsActiveProperty = 
            DependencyProperty.RegisterAttached("IsActive",
                typeof(bool), 
                typeof(StickyNoteControl), 
                new FrameworkPropertyMetadata(BooleanBoxes.FalseBox,
                    FrameworkPropertyMetadataOptions.Inherits)); 

        /// 
        /// The state of StickyNoteControl - true : active, false:inactive
        ///  
        public bool IsActive
        { 
            get 
            {
                return (bool)GetValue(StickyNoteControl.IsActiveProperty); 
            }
        }

        ///  
        /// If true, mouse is over the SticyNoteControl's anchor (which could be used to change its appearance
        /// in its style). 
        ///  
        internal static readonly DependencyPropertyKey IsMouseOverAnchorPropertyKey =
            DependencyProperty.RegisterReadOnly("IsMouseOverAnchor", 
                typeof(bool),
                typeof(StickyNoteControl),
                    new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        /// 
        /// If true, mouse is over the SticyNoteControl's anchor (which could be used to change its appearance 
        /// in its style). 
        /// 
        public static readonly DependencyProperty IsMouseOverAnchorProperty = IsMouseOverAnchorPropertyKey.DependencyProperty; 

        /// 
        /// True if the mouse is over the StickyNote anchor, false otherwise
        ///  
        public bool IsMouseOverAnchor
        { 
            get 
            {
               return  (bool) GetValue(StickyNoteControl.IsMouseOverAnchorProperty); 
            }
        }

        ///  
        ///     The DependencyProperty for the CaptionFontFamily property.
        ///     Flags:              Can be used in style rules 
        ///     Default Value:      System Dialog Font 
        /// 
        public static readonly DependencyProperty CaptionFontFamilyProperty = 
                DependencyProperty.Register(
                        "CaptionFontFamily",
                        typeof(FontFamily),
                        typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(
                                SystemFonts.MessageFontFamily, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure)); 

        ///  
        ///     The caption font family
        /// 
        public FontFamily CaptionFontFamily
        { 
            get { return (FontFamily) GetValue(CaptionFontFamilyProperty); }
            set { SetValue(CaptionFontFamilyProperty, value); } 
        } 

        ///  
        ///     The DependencyProperty for the CaptionFontSize property.
        ///     Flags:              Can be used in style rules
        ///     Default Value:      System Dialog Font Size
        ///  
        public static readonly DependencyProperty CaptionFontSizeProperty =
                DependencyProperty.Register( 
                        "CaptionFontSize", 
                        typeof(double),
                        typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(
                                SystemFonts.MessageFontSize,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///     The size of the caption font. 
        ///  
        public double CaptionFontSize
        { 
            get { return (double) GetValue(CaptionFontSizeProperty); }
            set { SetValue(CaptionFontSizeProperty, value); }
        }
 
        /// 
        ///     The DependencyProperty for the CaptionFontStretch property. 
        ///     Flags:              Can be used in style rules 
        ///     Default Value:      FontStretches.Normal
        ///  
        public static readonly DependencyProperty CaptionFontStretchProperty =
                DependencyProperty.Register(
                        "CaptionFontStretch",
                        typeof(FontStretch), 
                        typeof(StickyNoteControl),
                        new FrameworkPropertyMetadata( 
                                FontStretches.Normal, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///     The stretch of the caption font.
        /// 
        public FontStretch CaptionFontStretch 
        {
            get { return (FontStretch) GetValue(CaptionFontStretchProperty); } 
            set { SetValue(CaptionFontStretchProperty, value); } 
        }
 
        /// 
        ///     The DependencyProperty for the CaptionFontStyle property.
        ///     Flags:              Can be used in style rules
        ///     Default Value:      System Dialog Font Style 
        /// 
        public static readonly DependencyProperty CaptionFontStyleProperty = 
                DependencyProperty.Register( 
                        "CaptionFontStyle",
                        typeof(FontStyle), typeof(StickyNoteControl), 
                        new FrameworkPropertyMetadata(
                                SystemFonts.MessageFontStyle,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///     The style of the caption font. 
        ///  
        public FontStyle CaptionFontStyle
        { 
            get { return (FontStyle) GetValue(CaptionFontStyleProperty); }
            set { SetValue(CaptionFontStyleProperty, value); }
        }
 
        /// 
        ///     The DependencyProperty for the CaptionFontWeight property. 
        ///     Flags:              Can be used in style rules 
        ///     Default Value:      System Dialog Font Weight
        ///  
        public static readonly DependencyProperty CaptionFontWeightProperty =
                DependencyProperty.Register(
                        "CaptionFontWeight",
                        typeof(FontWeight), 
                        typeof(StickyNoteControl),
                        new FrameworkPropertyMetadata( 
                                SystemFonts.MessageFontWeight, 
                                FrameworkPropertyMetadataOptions.AffectsMeasure));
 
        /// 
        ///     The weight or thickness of the caption font.
        /// 
        public FontWeight CaptionFontWeight 
        {
            get { return (FontWeight) GetValue(CaptionFontWeightProperty); } 
            set { SetValue(CaptionFontWeightProperty, value); } 
        }
 
        /// 
        ///     The DependencyProperty for the PenWidth property.
        ///     Flags:              Can be used in style rules
        ///     Default Value:      The default width of System.Windows.Ink.DrawingAttributes. 
        /// 
        public static readonly DependencyProperty PenWidthProperty = 
                DependencyProperty.Register( 
                        "PenWidth",
                        typeof(double), 
                        typeof(StickyNoteControl),
                        new FrameworkPropertyMetadata(
                                (new DrawingAttributes()).Width,
                                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, 
                                new PropertyChangedCallback(_UpdateInkDrawingAttributes)));
 
        ///  
        ///     The width of the pen for the ink StickyNoteControl.
        ///  
        public double PenWidth
        {
            get { return (double) GetValue(PenWidthProperty); }
            set { SetValue(PenWidthProperty, value); } 
        }
 
        ///  
        /// StickyNoteType Property Key
        ///  
        private static readonly DependencyPropertyKey StickyNoteTypePropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "StickyNoteType",
                        typeof(StickyNoteType), 
                        typeof(StickyNoteControl),
                        new FrameworkPropertyMetadata(StickyNoteType.Text)); 
 
        /// 
        /// StickyNoteType Dependency Property 
        /// 
        public static readonly DependencyProperty StickyNoteTypeProperty = StickyNoteTypePropertyKey.DependencyProperty;

        ///  
        /// Gets StickyNoteType Property
        ///  
        public StickyNoteType StickyNoteType 
        {
            get{ return (StickyNoteType) GetValue(StickyNoteTypeProperty); } 
        }

        /// 
        /// Returns the Annotation this StickyNote is representing. 
        /// 
        public IAnchorInfo AnchorInfo 
        { 
            get
            { 
                if (_attachedAnnotation != null)
                    return _attachedAnnotation;
                return null;
            } 
        }
 
        #endregion  Public Properties 

        //------------------------------------------------------------------------------- 
        //
        // Public Commands
        //
        //-------------------------------------------------------------------------------- 

        #region Public Commands 
 
        /// 
        /// Delete a note 
        /// 
        public static readonly RoutedCommand DeleteNoteCommand = new RoutedCommand("DeleteNote", typeof(StickyNoteControl));

        ///  
        /// Ink Mode
        ///  
        public static readonly RoutedCommand InkCommand = new RoutedCommand("Ink", typeof(StickyNoteControl)); 

        #endregion Public Commands 


        //-------------------------------------------------------------------------------
        // 
        // Protected Methods
        // 
        //------------------------------------------------------------------------------- 

        #region Protected Methods 

        /// 
        /// Called whenever the template changes.
        ///  
        /// Old template
        /// New template 
        protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate) 
        {
            // No need for calling VerifyAccess since we call the method on the base here. 
            base.OnTemplateChanged(oldTemplate, newTemplate);

            // If StickyNote's control template has been changed, we should invalidate current cached controls.
            ClearCachedControls(); 
        }
 
        ///  
        /// Called whenever focus enters or leaves the StickyNoteControl.  This includes when focus
        /// is set/removed from any element within the StickyNoteControl. 
        /// 
        /// arguments describing the property change
        protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs args)
        { 
            base.OnIsKeyboardFocusWithinChanged(args);
 
            // If we lost focus due to a context menu on some element within us, 
            // we don't consider that a loss of focus.  We simply exit early.
            ContextMenu menu = Keyboard.FocusedElement as ContextMenu; 
            if (menu != null)
            {
                if (menu.PlacementTarget != null && menu.PlacementTarget.IsDescendantOf(this))
                { 
                        return;
                } 
            } 

            // Must update our anchor that we are now focused or not focused. 
            _anchor.Focused = IsKeyboardFocusWithin;
        }

        ///  
        /// An event announcing that the keyboard is focused on this bubble.
        ///  
        /// >FocusChangedEvent Argument 
        protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs args)
        { 
            // No need for calling VerifyAccess since we call the method on the base here.
            base.OnGotKeyboardFocus(args);

            // Dwayne's Input BC(#73066) changed the behavior of mouse button event. 
            // So we could get GotKeyboardFocus event without the visual being set up.
            // Now, we verify the visual is ready by invoking ApplyTemplate. 
            ApplyTemplate(); 

            // We are interested in the expanded note. 
            if ( IsExpanded == true )
            {
                Invariant.Assert(Content != null);
 
                BringToFront();
                // If focus was set on us, we should set the focus on our inner control 
                if ( args.NewFocus == this ) 
                {
                    UIElement innerControl = this.Content.InnerControl as UIElement; 
                    Invariant.Assert(innerControl != null, "InnerControl is null or not a UIElement.");

                    // Don't mess with focus if its already on our inner control
                    if ( innerControl.IsKeyboardFocused == false ) 
                    {
                        // We should set the focus to the inner control after it is added the visual tree. 
                        innerControl.Focus(); 
                    }
                } 
            }
        }

        #endregion // Protected Methods 

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

        #region Internal Methods
 
        /// 
        /// Creates our inner control and adds it to the tree.  If the inner control 
        /// already exists we verify its of the right type for our current data. 
        /// This is called when the template is applied or when the annotation for this
        /// control is set. 
        /// 
        private void EnsureStickyNoteType()
        {
            UIElement contentContainer = GetContentContainer(); 

            // Check whether we need to recreate a content control based on the new type. 
            if (_contentControl != null) 
            {
                // Check if the type has been changed 
                if (_contentControl.Type != _stickyNoteType)
                {
                    // Recreate the content control when the type has been changed.
                    DisconnectContent(); 
                    _contentControl = StickyNoteContentControlFactory.CreateContentControl(_stickyNoteType, contentContainer);
                    ConnectContent(); 
                } 
            }
            else 
            {
                _contentControl = StickyNoteContentControlFactory.CreateContentControl(_stickyNoteType, contentContainer);
                ConnectContent();
            } 
        }
 
        ///  
        /// When our inner control is changing, we disconnect from the existing one
        /// by unregistering for events and removing the control from the visual tree. 
        /// 
        private void DisconnectContent()
        {
            Invariant.Assert(Content != null, "Content is null."); 

            // Unregister for all events and clear bindings 
            StopListenToContentControlEvent(); 
            UnbindContentControlProperties();
 
            _contentControl = null;
        }

        ///  
        /// When a new content control is created we register on different portions of
        /// the visual tree for certain events. 
        ///  
        private void ConnectContent()
        { 
            Invariant.Assert(Content != null);

            // Set the default inking mode and attributes
            InkCanvas innerInkCanvas = Content.InnerControl as InkCanvas; 
            if (innerInkCanvas != null)
            { 
                // Create the event handlers we'll use for ink notes 
                InitializeEventHandlers();
 
                // We set the value on the StickyNoteControl which eventually gets
                // set on the InkCanvas.  The property on the InkCanvas isn't a DP
                // we can't create a one-way binding as would be preferred.
                this.SetValue(InkEditingModeProperty, InkCanvasEditingMode.Ink); 

                UpdateInkDrawingAttributes(); 
            } 

            // Register for events and setup bindings 
            StartListenToContentControlEvent();
            BindContentControlProperties();
        }
 
        /// 
        /// Returns the Content element for this StickyNoteControl.  Should never 
        /// be null when IsExpanded = true. 
        /// 
        internal StickyNoteContentControl Content 
        {
            get
            {
                return _contentControl; 
            }
        } 
 
        /// 
        /// Returns the button used to close the StickyNoteControl (it actually sets IsExpanded to false). 
        /// 
        private Button GetCloseButton()
        {
            return GetTemplateChild(SNBConstants.c_CloseButtonId) as Button; 
        }
 
        ///  
        /// Returns the button when the StickyNoteControl has IsExpanded=false.
        ///  
        private Button GetIconButton()
        {
                return GetTemplateChild(SNBConstants.c_IconButtonId) as Button;
        } 

        ///  
        /// Returns the thumb that controls the dragging of the StickyNote as a whole. 
        /// 
        private Thumb GetTitleThumb() 
        {
            return GetTemplateChild(SNBConstants.c_TitleThumbId) as Thumb;
        }
 
        /// 
        /// Return the ContentControl viewer in the StickyNoteControl. 
        ///  
        private UIElement GetContentContainer()
        { 
            return GetTemplateChild(SNBConstants.c_ContentControlId) as UIElement;
        }

        ///  
        /// Return the resize thumb in the StickyNoteControl.
        ///  
        private Thumb GetResizeThumb() 
        {
            return GetTemplateChild(SNBConstants.c_BottomRightResizeThumbId) as Thumb; 
        }


        #endregion Internal Methods 

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

        #region Internal Properties
 
        /// 
        /// InkEditingMode Property Key 
        ///  
        private static readonly DependencyProperty InkEditingModeProperty =
                        DependencyProperty.Register( 
                                "InkEditingMode",
                                typeof(InkCanvasEditingMode),
                                typeof(StickyNoteControl),
                                new FrameworkPropertyMetadata( 
                                    InkCanvasEditingMode.None));
 
        ///  
        /// Gets/Sets the dirty state of the control.
        ///  
        private bool IsDirty
        {
            get
            { 
                return _dirty;
            } 
            set 
            {
                _dirty = value; 
            }
        }

        #endregion // Internal Properties 

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

        #region Private Methods
 
        /// 
        /// Called when a StickyNoteControl's IsExpanded property changes.  Simply 
        /// pass it on to the StickyNoteControl instance. 
        /// 
        private static void _OnIsExpandedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            StickyNoteControl snc = (StickyNoteControl)d;

            snc.OnIsExpandedChanged(); 
        }
 
        private static void OnFontPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            StickyNoteControl stickyNoteControl = (StickyNoteControl)d; 
            if (stickyNoteControl.Content != null && stickyNoteControl.Content.Type != StickyNoteType.Ink)
            {
                FrameworkElement innerControl = stickyNoteControl.Content.InnerControl;
                if (innerControl != null) 
                    innerControl.SetValue(e.Property, e.NewValue);
            } 
        } 

        ///  
        /// The changed callback attached to the Foreground and PenWidth DPs
        /// 
        private static void _UpdateInkDrawingAttributes(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            // Update the DrawingAttributes
            StickyNoteControl stickyNoteControl = (StickyNoteControl)d; 
            stickyNoteControl.UpdateInkDrawingAttributes(); 

            if (e.Property == ForegroundProperty && stickyNoteControl.Content != null && stickyNoteControl.Content.Type != StickyNoteType.Ink) 
            {
                FrameworkElement innerControl = stickyNoteControl.Content.InnerControl;
                if (innerControl != null)
                    innerControl.SetValue(ForegroundProperty, e.NewValue); 
            }
        } 
 

        // A class handler for TextBox.TextChanged events 
        //      obj       -   the event sender
        //      args    -   Event argument
        private void OnTextChanged(object obj, TextChangedEventArgs args)
        { 
            // We must update the annotation asynchronously because we can't Since Textbox doesn't allow any layout measurement during its content is changing, we have to do
            // the update asynchronously.  We also prevent updating the annotation when the content in the 
            // textbox was changed due to a change in the annotation itself. 
            if (!InternalLocker.IsLocked(LockHelper.LockFlag.DataChanged))
            { 
                //fire trace event
                EventTrace.NormalTraceEvent(EventTraceGuidId.ANNOTATIONTEXTCHANGEDGUID, EventType.StartEvent);

                AsyncUpdateAnnotation(XmlToken.Text); 
                //Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(AsyncUpdateAnnotation), XmlToken.Text);
                IsDirty = true; 
 
                //fire trace event
                EventTrace.NormalTraceEvent(EventTraceGuidId.ANNOTATIONTEXTCHANGEDGUID, EventType.EndEvent); 

            }
        }
 
        private static void _OnDeviceDown(object sender, TEventArgs args)
            where TEventArgs : InputEventArgs 
        { 
            // Block all mouse downs from leaving this control
            args.Handled = true; 
        }

        private static void _OnContextMenuOpening(object sender, ContextMenuEventArgs args)
        { 
            // Block all ContextMenuOpenings from leaving this control
            if (!(args.TargetElement is ScrollBar)) 
            { 
                args.Handled = true;
            } 
        }

        // A generic class handler for both Stylus.PreviewStylusDown and Mouse.PreviewMouseDown events
        //      dc       -   the event sender 
        //      args    -   Event argument
        private static void _OnPreviewDeviceDown(object sender, TEventArgs args) 
            where TEventArgs : InputEventArgs 
        {
            StickyNoteControl snc = sender as StickyNoteControl; 

            IInputElement captured = null;
            StylusDevice stylusDevice = null;
            MouseDevice mouseDevice = null; 

            // Check whether Stylus or Mouse has been captured. 
            stylusDevice = args.Device as StylusDevice; 
            if ( stylusDevice != null )
            { 
                captured = stylusDevice.Captured;
            }
            else
            { 
                mouseDevice = args.Device as MouseDevice;
 
                if (mouseDevice != null) 
                {
                    captured = mouseDevice.Captured; 
                }
            }

            // ContextMenu may capture the inputdevice in front. 
            // If the device is captured by an element other than StickyNote, we should not try to bring note to front.
            if ( snc != null && ( captured == snc || captured == null ) ) 
            { 
                snc.OnPreviewDeviceDown(sender, args);
            } 
        }

        /// 
        /// When the Strokes are replaced on an InkCanvas we must unregister on the previous set 
        /// of strokes and register on the new set of strokes.
        ///  
        private void OnInkCanvasStrokesReplacedEventHandler(object sender, InkCanvasStrokesReplacedEventArgs e) 
        {
            StopListenToStrokesEvent(e.PreviousStrokes); 
            StartListenToStrokesEvent(e.NewStrokes);
        }

        ///  
        /// Raised when the user moves the selection.  We prevent the selection from going into negative
        /// territory because ScrollViewer does not scroll content there and the ink gets lost. 
        /// 
        /// For move, we just clamp X or Y to 0.
        ///  
        private void OnInkCanvasSelectionMovingEventHandler(object sender, InkCanvasSelectionEditingEventArgs e)
        {
            Rect newRectangle = e.NewRectangle;
            if (newRectangle.X < 0 || newRectangle.Y < 0) 
            {
                newRectangle.X = newRectangle.X < 0d ? 0d : newRectangle.X; 
                newRectangle.Y = newRectangle.Y < 0d ? 0d : newRectangle.Y; 
                e.NewRectangle = newRectangle;
            } 
        }

        /// 
        /// Raised when the user resizes the selection.  We prevent the selection from going into negative 
        /// territory because ScrollViewer does not scroll content there and the ink gets lost.
        /// 
        /// For Resize, we recompute the new rect after clamping x or y (or both) to 0,0 
        /// 
        private void OnInkCanvasSelectionResizingEventHandler(object sender, InkCanvasSelectionEditingEventArgs e) 
        {
            Rect newRectangle = e.NewRectangle;
            if (newRectangle.X < 0 || newRectangle.Y < 0)
            { 
                if (newRectangle.X < 0)
                { 
                    //newRect.X is negative, simply add it to width to subtract it 
                    newRectangle.Width = newRectangle.Width + newRectangle.X;
                    newRectangle.X = 0d; 
                }
                if (newRectangle.Y < 0)
                {
                    //newRect.Y is negative, simply add it to height to subtract it 
                    newRectangle.Height = newRectangle.Height + newRectangle.Y;
                    newRectangle.Y = 0d; 
                } 
                e.NewRectangle = newRectangle;
            } 
        }

        // A handler for the events of ink stroke being changed.
        private void OnInkStrokesChanged(object sender, StrokeCollectionChangedEventArgs args) 
        {
            // We have two options for tracking ink's dirty flag. 
            // 1) use the UndoStateChanged event to detect when any data changes in the Ink object model 
            //      Advantages:
            //          Handles ALL data changes in Ink object model 
            //          One event handler
            //      Disadvantages:
            //          Very perf intensive since undo serialization is triggered
            // 2) Handle the StrokesChanged or DrawingAttributesChanged events to detect when specific kinds of data change in the Ink object model. 
            //      Advantages:
            //          Efficient since no serialization occurs. 
            //          Very targeted handling of types of data changes (e.g. points/transforms, drawing attributes) 
            //      Disadvantages:
            //          Does not include changes to ExtendedProperties/ExtendedProperties and potentially 3rd party events. - not a true 100% perfect dirty flag 

            // Since we only care about transforms/points and drawing attributes for now, #2 is a better choice.

            StopListenToStrokeEvent(args.Removed); 
            StartListenToStrokeEvent(args.Added);
 
            if (args.Removed.Count > 0 || args.Added.Count > 0) 
            {
                Invariant.Assert(Content != null && Content.InnerControl is InkCanvas); 
                FrameworkElement parent = VisualTreeHelper.GetParent(Content.InnerControl) as FrameworkElement;

                if (parent != null)
                { 
                    // Invalidate ContentArea's measure so that scrollbar could be updated correctly.
                    parent.InvalidateMeasure(); 
                } 
            }
 
            //fire trace event
            EventTrace.NormalTraceEvent(EventTraceGuidId.ANNOTATIONINKCHANGEDGUID, EventType.StartEvent);

            // Update the Ink in the annotation. 
            UpdateAnnotationWithSNC(XmlToken.Ink);
            IsDirty = true; 
 
            //fire trace event
            EventTrace.NormalTraceEvent(EventTraceGuidId.ANNOTATIONINKCHANGEDGUID, EventType.EndEvent); 

        }

        ///  
        /// Initializes a StickyNoteControl's private members.
        ///  
        private void InitStickyNoteControl() 
        {
            //set the anchor as DataContext 
            XmlQualifiedName type = _stickyNoteType == StickyNoteType.Text ?
                                                                  TextSchemaName : InkSchemaName;
            _anchor = new MarkedHighlightComponent(type, this);
 
            IsDirty = false;
 
            //listen to Loaded event to set Focus if needed 
            Loaded += new RoutedEventHandler(OnLoadedEventHandler);
        } 

        /// 
        /// Create the listeners we will use to register on our InkCanvas when it gets created.
        /// Only called once this StickyNote is first used for ink content. 
        /// 
        private void InitializeEventHandlers() 
        { 
            _propertyDataChangedHandler = new StrokeChangedHandler(this);
            _strokeDrawingAttributesReplacedHandler = new StrokeChangedHandler(this); 
            _strokePacketDataChangedHandler = new StrokeChangedHandler(this);
        }

 
        /// 
        /// Listens for click events from the close button and the icon button. 
        /// Both cause the IsExpanded property to be negated. 
        /// 
        private void OnButtonClick(object sender, RoutedEventArgs e) 
        {
            bool currentExpanded = IsExpanded;
            IsExpanded = !currentExpanded;
        } 

        ///  
        /// Simple method that deletes the current annotation from the annotation store. 
        /// This is called in response to the DeleteNote command.
        ///  
        private void DeleteStickyNote()
        {
            Invariant.Assert(_attachedAnnotation != null, "AttachedAnnotation is null.");
            Invariant.Assert(_attachedAnnotation.Store != null, "AttachedAnnotation's Store is null."); 

            _attachedAnnotation.Store.DeleteAnnotation(_attachedAnnotation.Annotation.Id); 
        } 

        ///  
        /// Handles drag completed events for both thumbs in the Sticky Note Control.
        /// When the drag is completed, we write out the new values that might have changed.
        /// 
        private void OnDragCompleted(object sender, DragCompletedEventArgs args) 
        {
            Thumb source = args.Source as Thumb; 
 
            // Update the cached offsets of StickyNote
            if (source == GetTitleThumb()) 
            {
                // Update the Top and Left in the annotation.
                UpdateAnnotationWithSNC(XmlToken.XOffset | XmlToken.YOffset | XmlToken.Left | XmlToken.Top);
            } 
            else if (source == GetResizeThumb())
            { 
                // Update the Width and Height and Top and Left in the annotation. 
                UpdateAnnotationWithSNC(XmlToken.XOffset | XmlToken.YOffset | XmlToken.Width | XmlToken.Height | XmlToken.Left | XmlToken.Top);
            } 
        }

        /// 
        /// Called when either thumb is dragged.  We then process the drag in specific ways depending 
        /// on which thumb was dragged.
        ///  
        private void OnDragDelta(object sender, DragDeltaEventArgs args) 
        {
            Invariant.Assert(IsExpanded == true, "Dragging occurred when the StickyNoteControl was not expanded."); 

            Thumb source = args.Source as Thumb;
            double horizontalChange = args.HorizontalChange;
 
            // Because we are self-mirroring, we have flipped the layout within the note
            // but our environment isn't flipped.  The Thumb (within the note) is providing 
            // mirrored values but we will use them to position ourselves within the unmirrored 
            // environment, so we flip the values again before using them.
            if (_selfMirroring) 
            {
                horizontalChange = -horizontalChange;
            }
 
            if (source == GetTitleThumb())
            { 
                OnTitleDragDelta(horizontalChange, args.VerticalChange); 
            }
            else if (source == GetResizeThumb()) 
            {
                OnResizeDragDelta(args.HorizontalChange, args.VerticalChange);
            }
 
            // Update the cached offsets of StickyNote
            UpdateOffsets(); 
        } 

        ///  
        /// Handles dragging the title thumb.  This updates the StickyNoteControl's
        /// position.
        /// 
        private void OnTitleDragDelta(double horizontalChange, double verticalChange) 
        {
            Invariant.Assert(IsExpanded != false); 
 
            Rect rectNote = StickyNoteBounds;
            Rect rectPage = PageBounds; 

            // These are the minimum widths that must be visible when a note is partially off
            // the left or right side of a page.  The difference is due to the Close button
            // being on one side and wanting some of the title bar to be visible on that side. 
            double leftBoundary = 45;
            double rightBoundary = 20; 
 
            // Because we are self-mirroring, we need to flip the minimum widths
            if (_selfMirroring) 
            {
                double temp = rightBoundary;
                rightBoundary = leftBoundary;
                leftBoundary = temp; 
            }
 
            // Figure out the new position while enforcing a portion of the note being always on the page. 
            Point minBoundary = new Point(-(rectNote.X + rectNote.Width - leftBoundary), - rectNote.Y);
            Point maxBoundary = new Point(rectPage.Width - rectNote.X - rightBoundary, rectPage.Height - rectNote.Y - 20); 

            horizontalChange = Math.Min(Math.Max(minBoundary.X, horizontalChange), maxBoundary.X);
            verticalChange = Math.Min(Math.Max(minBoundary.Y, verticalChange), maxBoundary.Y);
 
            TranslateTransform currentTransform = PositionTransform;
 
            // Include any temporary delta we are currently using to avoid any visible jumping to the user 
            PositionTransform = new TranslateTransform(currentTransform.X + horizontalChange + _deltaX, currentTransform.Y + verticalChange + _deltaY);
            _deltaX = _deltaY = 0; 

            IsDirty = true;
        }
 

        ///  
        /// Handles dragging the bottom/right resize thumb.  Updates the StickyNoteControl's size. 
        /// 
        private void OnResizeDragDelta(double horizontalChange, double verticalChange) 
        {
            Invariant.Assert(IsExpanded != false);

            Rect rectNote = StickyNoteBounds; 

            double wNew = rectNote.Width + horizontalChange; 
            double hNew = rectNote.Height + verticalChange; 

            // This method doesn't apply during self-mirroring because 
            // we are actually moving the note during which time the note's
            // location is bounded by the page borders (plus a cushion).
            if (!_selfMirroring)
            { 
                // If the new size would put the right side of the SN off the page
                // we don't allow that resize anymore. 
                if (rectNote.X + wNew < 45) 
                    wNew = rectNote.Width;
            } 

            double minWidth = MinWidth;
            double minHeight = MinHeight;
 
            if (wNew < minWidth)
            { 
                wNew = minWidth; 
                // This is only used in self-mirroring - if we clamp the size change,
                // we must also clamp the move (see below) 
                horizontalChange = wNew - this.Width;
            }

            if (hNew < minHeight) 
            {
                hNew = minHeight; 
            } 

            SetValue(WidthProperty, wNew); 
            SetValue(HeightProperty, hNew);

            // Because we are self-mirroring, as the note changes size we have to
            // move it to make it appear its changing size from the left (where the 
            // resize handle is located during mirroring) instead of the right which
            // is what is actually happening. 
            if (_selfMirroring) 
            {
                OnTitleDragDelta(-horizontalChange, 0); 
            }
            else
            {
                // This appears to be a no-op but OnTitleDragDelta also takes 
                // care of applying permanently any temporary offsets
                OnTitleDragDelta(0, 0); 
            } 

            IsDirty = true; 
        }

        /// 
        /// Any click in the StickyNoteControl brings it to the top in z-order and 
        /// requests the focus.
        /// Additionally we must `swallow the event here if the click happend on 
        /// our InkCanvas because the RTI engine isn't setup yet and the user will 
        /// be creating ink without seeing it.
        ///  
        private void OnPreviewDeviceDown(object dc, InputEventArgs args)
        {
            if (IsExpanded)
            { 
                bool eatEvent = false;
 
                if (!IsKeyboardFocusWithin && this.StickyNoteType == StickyNoteType.Ink) 
                {
                    // Only event we want to `swallow here is a click on the InkCanvas 
                    // when the StickyNote isn't focused because RTI isn't set up yet
                    Visual source = args.OriginalSource as Visual;
                    if (source != null)
                    { 
                        Invariant.Assert(Content.InnerControl != null, "InnerControl is null.");
                        eatEvent = source.IsDescendantOf(this.Content.InnerControl); 
                    } 
                }
 
                // Will have no effect if already in front
                BringToFront();

                if (!IsActive || !IsKeyboardFocusWithin) 
                {
                    Focus(); 
                } 

                if (eatEvent == true) 
                {
                    args.Handled = true;
                }
            } 
        }
 
        ///  
        /// Set the focus on SN if needed
        ///  
        /// sender - not used
        /// arguments - not used
        private void OnLoadedEventHandler(object sender, RoutedEventArgs e)
        { 
            if (IsExpanded)
            { 
                // Setup the inner controls with the Annotation's data - we must have correct 
                // values for SN sizes before Focus->BringIntoView is invoked
                UpdateSNCWithAnnotation(SNCAnnotation.Sizes); 

                if (_sncAnnotation.IsNewAnnotation)
                {
                    // NTRAID#WINOS-1169084-2005/05/19-WAYNEZEN 
                    // After the annotations has been added, we should set focus on the element.
                    Focus(); 
                } 
            }
 
            //unregister
            Loaded -= new RoutedEventHandler(OnLoadedEventHandler);
        }
 

        ///  
        /// Unregister from any events on the current visual tree.  Also disconnect the current 
        /// content control.
        ///  
        private void ClearCachedControls()
        {
            if (Content != null)
            { 
                // Disconnect the content control which will be re-connected to the new ContentControl
                // in ApplyTemplate when the new visual tree is populated from the new control template. 
                DisconnectContent(); 
            }
 
            Button closeButton = GetCloseButton();
            if (closeButton != null)
            {
                closeButton.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonClick)); 
            }
 
            Button iconButton = GetIconButton(); 
            if (iconButton != null)
            { 
                iconButton.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonClick));
            }

            Thumb titleThumb = GetTitleThumb(); 
            if (titleThumb != null)
            { 
                titleThumb.RemoveHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta)); 
                titleThumb.RemoveHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted));
            } 

            Thumb resizeThumb = GetResizeThumb();
            if (resizeThumb != null)
            { 
                resizeThumb.RemoveHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta));
                resizeThumb.RemoveHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted)); 
            } 
        }
 
        /// 
        /// Called when this StickyNoteControl's IsExpanded property changes.
        /// 
        private void OnIsExpandedChanged() 
        {
            InvalidateTransform(); 
 
            // Update the Iconized in the annotation.
            UpdateAnnotationWithSNC(XmlToken.IsExpanded); 

            IsDirty = true;

            if (IsExpanded) 
            {
                BringToFront(); 
                // We request the focus from a dispatcher callback because we may 
                // have been called from a
                this.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(AsyncTakeFocus), null); 
            }
            else
            {
                GiveUpFocus(); 
                SendToBack();
            } 
        } 

        ///  
        /// Requests focus to this control.  Used asynchronously from event handlers
        /// to prevent other event handlers from stealing focus right back.
        /// 
        private object AsyncTakeFocus(object notUsed) 
        {
            this.Focus(); 
 
            return null;
        } 

        /// 
        /// If focus us within this control, sets the focus on the first element in the attached
        /// annotation's parent's ancestor chain that accepts it.  If no element accepts it, 
        /// then focus is set to null.
        ///  
        private void GiveUpFocus() 
        {
            // Only send focus away when we actually have it. 
            if (IsKeyboardFocusWithin)
            {
                // Start with the attached annotation's parent,
                // walk up the tree looking for the first element 
                // to take focus.
                bool transferred = false; 
                DependencyObject parent = _attachedAnnotation.Parent; 
                IInputElement newFocus = null;
 
                while (parent != null && !transferred)
                {
                    newFocus = parent as IInputElement;
                    if (newFocus != null) 
                    {
                        transferred = newFocus.Focus(); 
                    } 

                    // Go up the parent chain if focus wasn't taken 
                    if (!transferred)
                    {
                        parent = FrameworkElement.GetFrameworkParent(parent);
                    } 
                }
 
                // If no element was found, just give up focus 
                if (!transferred)
                { 
                    Keyboard.Focus(null);
                }
            }
        } 

        ///  
        /// Request this control be sent to the front of the z-order stack in its 
        /// presentation context.  Call to PresentationContext should have no affect
        /// if its already at the front. 
        /// 
        private void BringToFront()
        {
            PresentationContext pc = ((IAnnotationComponent)this).PresentationContext; 
            if ( pc != null )
            { 
                pc.BringToFront(this); 
            }
        } 

        /// 
        /// Request this control be sent to the back of the z-order stack in its
        /// presentation context.  Call to PresentationContext should have no affect 
        /// if its already at the back.
        ///  
        private void SendToBack() 
        {
            PresentationContext pc = ((IAnnotationComponent)this).PresentationContext; 
            if (pc != null)
            {
                pc.SendToBack(this);
            } 
        }
 
        ///  
        /// Invalidate the Transform for this control in its presentation context.
        ///  
        private void InvalidateTransform()
        {
            PresentationContext pc = ((IAnnotationComponent)this).PresentationContext;
            if ( pc != null ) 
            {
                pc.InvalidateTransform(this); 
            } 
        }
 
        /// 
        /// Updates the attached annotation with the data currently in this control.
        /// Called asynchronously from event handler because TextBox can't handle
        /// changing its content from an event handler.  // Do we need this to be async? 
        /// 
        private object AsyncUpdateAnnotation(object arg) 
        { 
            UpdateAnnotationWithSNC((XmlToken)arg);
            return null; 
        }

        /// 
        /// This binds a new content control's properties to those set on 
        /// the StickyNoteControl.  Should be called each time a new content
        /// control is created. 
        ///  
        private void BindContentControlProperties()
        { 
            Invariant.Assert(Content != null);

            // ISSUE-2005/03/23/WAYNEZEN,
            // Somehow, the bound font family can't be loaded again by Parser once the attribute persists in XAML. 
            // Since InkCanvas doesn't care about FontFamily, we just walk the issue around by not binding the property.
            if (Content.Type != StickyNoteType.Ink) 
            { 
                FrameworkElement innerControl = Content.InnerControl;
                innerControl.SetValue(FontFamilyProperty, GetValue(FontFamilyProperty)); 
                innerControl.SetValue(FontSizeProperty, GetValue(FontSizeProperty));
                innerControl.SetValue(FontStretchProperty, GetValue(FontStretchProperty));
                innerControl.SetValue(FontStyleProperty, GetValue(FontStyleProperty));
                innerControl.SetValue(FontWeightProperty, GetValue(FontWeightProperty)); 
                innerControl.SetValue(ForegroundProperty, GetValue(ForegroundProperty));
            } 
            else 
            {
                // Create a TwoWay MultiBinding for InkCanvas.EditingMode. 
                // The internal InkCanvas' EditingMode will be determined by
                // both StickyNoteControl.InkEditingMode and StickyNoteControl.IsKeyboardFocusWithin
                // If StickyNoteControl.IsKeyboardFocusWithin is false, the InkCanvas.EditingMode should be none.
                // Otherwise InkCanvas.EditingMode is same as the StickyNoteControl.InkEditingMode. 
                MultiBinding inkCanvasEditingMode = new MultiBinding();
                inkCanvasEditingMode.Mode = BindingMode.TwoWay; 
                inkCanvasEditingMode.Converter = new InkEditingModeIsKeyboardFocusWithin2EditingMode(); 

                Binding stickyNoteInkEditingMode = new Binding(); 
                stickyNoteInkEditingMode.Mode = BindingMode.TwoWay;
                stickyNoteInkEditingMode.Path = new PropertyPath(StickyNoteControl.InkEditingModeProperty);
                stickyNoteInkEditingMode.Source = this;
 
                inkCanvasEditingMode.Bindings.Add(stickyNoteInkEditingMode);
 
                Binding stickyNoteIsKeyboardFocusWithin = new Binding(); 
                stickyNoteIsKeyboardFocusWithin.Path = new PropertyPath(UIElement.IsKeyboardFocusWithinProperty);
                stickyNoteIsKeyboardFocusWithin.Source = this; 

                inkCanvasEditingMode.Bindings.Add(stickyNoteIsKeyboardFocusWithin);

                Content.InnerControl.SetBinding(InkCanvas.EditingModeProperty, inkCanvasEditingMode); 
            }
        } 
 
        /// 
        /// Removes the bindings we previously created between the content control 
        /// and the StickyNoteControl.
        /// 
        private void UnbindContentControlProperties()
        { 
            Invariant.Assert(Content != null);
 
            FrameworkElement innerControl = (FrameworkElement)Content.InnerControl; 
            if (Content.Type != StickyNoteType.Ink)
            { 
                innerControl.ClearValue(FontFamilyProperty);
                innerControl.ClearValue(FontSizeProperty);
                innerControl.ClearValue(FontStretchProperty);
                innerControl.ClearValue(FontStyleProperty); 
                innerControl.ClearValue(FontWeightProperty);
                innerControl.ClearValue(ForegroundProperty); 
            } 
            else
            { 
                BindingOperations.ClearBinding(innerControl, InkCanvas.EditingModeProperty);
            }
        }
 
        /// 
        /// Registers for change events from the content control.  This lets us 
        /// update the annotation when something in the controls change.  Should 
        /// be called when a new content control is created.
        ///  
        private void StartListenToContentControlEvent()
        {
            Invariant.Assert(Content != null);
 
            if (Content.Type == StickyNoteType.Ink)
            { 
                InkCanvas inkCanvas = Content.InnerControl as InkCanvas; 
                Invariant.Assert(inkCanvas != null, "InnerControl is not an InkCanvas for note of type Ink.");
                inkCanvas.StrokesReplaced += new InkCanvasStrokesReplacedEventHandler(OnInkCanvasStrokesReplacedEventHandler); 
                inkCanvas.SelectionMoving += new InkCanvasSelectionEditingEventHandler(OnInkCanvasSelectionMovingEventHandler);
                inkCanvas.SelectionResizing += new InkCanvasSelectionEditingEventHandler(OnInkCanvasSelectionResizingEventHandler);
                StartListenToStrokesEvent(inkCanvas.Strokes);
            } 
            else
            { 
                TextBoxBase textBoxBase = Content.InnerControl as TextBoxBase; 
                Invariant.Assert(textBoxBase != null, "InnerControl is not a TextBoxBase for note of type Text.");
                textBoxBase.TextChanged += new TextChangedEventHandler(OnTextChanged); 
            }
        }

        ///  
        /// Unregisters for any events from the content control.  Should be called
        /// when a content control is being changed. 
        ///  
        private void StopListenToContentControlEvent()
        { 
            Invariant.Assert(Content != null);

            if (Content.Type == StickyNoteType.Ink)
            { 
                InkCanvas inkCanvas = Content.InnerControl as InkCanvas;
                Invariant.Assert(inkCanvas != null, "InnerControl is not an InkCanvas for note of type Ink."); 
                inkCanvas.StrokesReplaced -= new InkCanvasStrokesReplacedEventHandler(OnInkCanvasStrokesReplacedEventHandler); 
                inkCanvas.SelectionMoving -= new InkCanvasSelectionEditingEventHandler(OnInkCanvasSelectionMovingEventHandler);
                inkCanvas.SelectionResizing -= new InkCanvasSelectionEditingEventHandler(OnInkCanvasSelectionResizingEventHandler); 
                StopListenToStrokesEvent(inkCanvas.Strokes);
            }
            else
            { 
                TextBoxBase textBoxBase = Content.InnerControl as TextBoxBase;
                Invariant.Assert(textBoxBase != null, "InnerControl is not a TextBoxBase for note of type Text."); 
                textBoxBase.TextChanged -= new TextChangedEventHandler(OnTextChanged); 
            }
        } 

        /// 
        /// Register for events on the StrokeCollection from the InkCanvas.
        ///  
        private void StartListenToStrokesEvent(StrokeCollection strokes)
        { 
            strokes.StrokesChanged += new StrokeCollectionChangedEventHandler(OnInkStrokesChanged); 
            strokes.PropertyDataChanged += new PropertyDataChangedEventHandler(_propertyDataChangedHandler.OnStrokeChanged);
            StartListenToStrokeEvent(strokes); 
        }

        /// 
        /// Unregister for events on the StrokeCollection from the InkCanvas. 
        /// 
        private void StopListenToStrokesEvent(StrokeCollection strokes) 
        { 
            strokes.StrokesChanged -= new StrokeCollectionChangedEventHandler(OnInkStrokesChanged);
            strokes.PropertyDataChanged -= new PropertyDataChangedEventHandler(_propertyDataChangedHandler.OnStrokeChanged); 
            StopListenToStrokeEvent(strokes);
        }

        ///  
        /// Register on each stroke in the InkCanvas.  If any of them change we need to know about it.
        ///  
        private void StartListenToStrokeEvent(IEnumerable strokes) 
        {
            foreach (Stroke s in strokes) 
            {
                s.DrawingAttributes.AttributeChanged += new PropertyDataChangedEventHandler(
                                                            _propertyDataChangedHandler.OnStrokeChanged);
                s.DrawingAttributesReplaced += new DrawingAttributesReplacedEventHandler( 
                                                            _strokeDrawingAttributesReplacedHandler.OnStrokeChanged);
                s.StylusPointsReplaced +=               new StylusPointsReplacedEventHandler( 
                                                            _strokePacketDataChangedHandler.OnStrokeChanged); 
                s.StylusPoints.Changed +=               new EventHandler(
                                                            _strokePacketDataChangedHandler.OnStrokeChanged); 
                s.PropertyDataChanged +=                new PropertyDataChangedEventHandler(
                                                            _propertyDataChangedHandler.OnStrokeChanged);
            }
        } 

        ///  
        /// Unregister on each stroke in the InkCanvas.  We previously registered on each stroke and 
        /// now need to disconnect from them.
        ///  
        private void StopListenToStrokeEvent(IEnumerable strokes)
        {
            foreach (Stroke s in strokes)
            { 
                s.DrawingAttributes.AttributeChanged -= new PropertyDataChangedEventHandler(
                                                            _propertyDataChangedHandler.OnStrokeChanged); 
                s.DrawingAttributesReplaced -= new DrawingAttributesReplacedEventHandler( 
                                                            _strokeDrawingAttributesReplacedHandler.OnStrokeChanged);
                s.StylusPointsReplaced  -=              new StylusPointsReplacedEventHandler( 
                                                            _strokePacketDataChangedHandler.OnStrokeChanged);
                s.StylusPoints.Changed -=               new EventHandler(
                                                            _strokePacketDataChangedHandler.OnStrokeChanged);
                s.PropertyDataChanged -=                new PropertyDataChangedEventHandler( 
                                                            _propertyDataChangedHandler.OnStrokeChanged);
            } 
        } 

        ///  
        /// Set bindings on the menuitems which StickyNote knows about
        /// 
        private void SetupMenu()
        { 
            MenuItem inkMenuItem = GetInkMenuItem();
            if (inkMenuItem != null) 
            { 
                // Bind the EditingMode to item's IsChecked DP.
                Binding checkedBind = new Binding("InkEditingMode"); 
                checkedBind.Mode = BindingMode.OneWay;
                checkedBind.RelativeSource = RelativeSource.TemplatedParent;
                checkedBind.Converter = new InkEditingModeConverter();
                checkedBind.ConverterParameter = InkCanvasEditingMode.Ink; 
                inkMenuItem.SetBinding(MenuItem.IsCheckedProperty, checkedBind);
            } 
 
            MenuItem selectMenuItem = GetSelectMenuItem();
            if (selectMenuItem != null) 
            {
                // Bind the EditingMode to item's IsChecked DP.
                Binding checkedBind = new Binding("InkEditingMode");
                checkedBind.Mode = BindingMode.OneWay; 
                checkedBind.RelativeSource = RelativeSource.TemplatedParent;
                checkedBind.Converter = new InkEditingModeConverter(); 
                checkedBind.ConverterParameter = InkCanvasEditingMode.Select; 
                selectMenuItem.SetBinding(MenuItem.IsCheckedProperty, checkedBind);
            } 

            MenuItem eraseMenuItem = GetEraseMenuItem();
            if (eraseMenuItem != null)
            { 
                // Bind the EditingMode to item's IsChecked DP.
                Binding checkedBind = new Binding("InkEditingMode"); 
                checkedBind.Mode = BindingMode.OneWay; 
                checkedBind.RelativeSource = RelativeSource.TemplatedParent;
                checkedBind.Converter = new InkEditingModeConverter(); 
                checkedBind.ConverterParameter = InkCanvasEditingMode.EraseByStroke;
                eraseMenuItem.SetBinding(MenuItem.IsCheckedProperty, checkedBind);
            }
 
            // Copy and Paste menu items (and their separator) are removed if
            // we don't have Clipboard permissions. 
            bool hasClipboardPermission = SecurityHelper.CallerHasAllClipboardPermission(); 

            // Set the target for the Copy/Paste commands to our inner control 
            MenuItem copyMenuItem = GetCopyMenuItem();
            if (copyMenuItem != null)
            {
                if (hasClipboardPermission) 
                {
                    copyMenuItem.CommandTarget = Content.InnerControl; 
                } 
                else
                { 
                    copyMenuItem.Visibility = Visibility.Collapsed;
                }
            }
 
            MenuItem pasteMenuItem = GetPasteMenuItem();
            if (pasteMenuItem != null) 
            { 
                if (hasClipboardPermission)
                { 
                    pasteMenuItem.CommandTarget = Content.InnerControl;
                }
                else
                { 
                    pasteMenuItem.Visibility = Visibility.Collapsed;
                } 
            } 

            Separator clipboardSeparator = GetClipboardSeparator(); 
            if (clipboardSeparator != null)
            {
                if (!hasClipboardPermission)
                { 
                    clipboardSeparator.Visibility = Visibility.Collapsed;
                } 
            } 
        }
 

        /// 
        /// CommandExecuted Handler - processes the commands for SNC.
        ///     DeleteNoteCommand - deletes the annotation from the store (causing the SNC to disappear) 
        ///     InkCommand - changes the mode of the ink canvas
        ///     Copy/Paste - we pass on to our inner control 
        ///  
        /// 
        ///  
        private static void _OnCommandExecuted(object sender, ExecutedRoutedEventArgs args)
        {
            RoutedCommand command = (RoutedCommand)(args.Command);
            StickyNoteControl snc = sender as StickyNoteControl; 

            Invariant.Assert(snc != null, "Unexpected Commands"); 
            Invariant.Assert(command == StickyNoteControl.DeleteNoteCommand 
                || command == StickyNoteControl.InkCommand, "Unknown Commands");
 
            if ( command == StickyNoteControl.DeleteNoteCommand )
            {
                // DeleteNote Command
                snc.DeleteStickyNote(); 
            }
            else if (command == StickyNoteControl.InkCommand) 
            { 
                StickyNoteContentControl content = snc.Content;
 
                if (content == null || content.Type != StickyNoteType.Ink)
                {
                    throw new InvalidOperationException(SR.Get(SRID.CannotProcessInkCommand));
                } 

                // Set the StickyNoteControl's ink editing mode to the command's parameter 
                InkCanvasEditingMode mode = (InkCanvasEditingMode)args.Parameter; 
                snc.SetValue(InkEditingModeProperty, mode);
            } 
        }

        /// 
        /// QueryCommandEnabled Handler - determines if a command should be enabled or not. 
        ///   DeleteNoteCommand - if the SNC has an attached annotation
        ///   InkCommand - if the SNC is of type InkStickyNote 
        ///   AllOthers - if focus is on our inner control, we let the inner control decide, 
        ///               otherwise we return false
        ///  
        private static void _OnQueryCommandEnabled(object sender, CanExecuteRoutedEventArgs args)
        {
            RoutedCommand command = (RoutedCommand)( args.Command );
            StickyNoteControl snc = sender as StickyNoteControl; 

            Invariant.Assert(snc != null, "Unexpected Commands"); 
            Invariant.Assert(command == StickyNoteControl.DeleteNoteCommand 
                || command == StickyNoteControl.InkCommand, "Unknown Commands");
 
            if ( command == StickyNoteControl.DeleteNoteCommand )
            {
                // Enable/Disable DeleteNote Command based on the Attached Annotation.
                args.CanExecute = snc._attachedAnnotation != null; 
            }
            else if (command == StickyNoteControl.InkCommand) 
            { 
                StickyNoteContentControl content = snc.Content;
 
                // Enabled/Disable InkCommand based on the StickyNote type
                args.CanExecute = (content != null && content.Type == StickyNoteType.Ink);
            }
            else 
            {
                Invariant.Assert(false, "Unknown command."); 
            } 
        }
 

        /// 
        /// Update DrawingAttributes on InkCanvas
        ///  
        private void UpdateInkDrawingAttributes()
        { 
            if ( Content == null || Content.Type != StickyNoteType.Ink ) 
            {
                // Return now if there is no InkCanvas. 
                return;
            }

            DrawingAttributes da = new DrawingAttributes(); 

            SolidColorBrush foreground = Foreground as SolidColorBrush; 
 
            // Make sure the foreground is type of SolidColorBrush.
            if ( foreground == null ) 
            {
                throw new ArgumentException(SR.Get(SRID.InvalidInkForeground), "Foreground");
            }
 
            da.StylusTip = StylusTip.Ellipse;
            da.Width = PenWidth; 
            da.Height = PenWidth; 
            da.Color = foreground.Color;
 
            // Update the DA on InkCanvas.
            ( (InkCanvas)( Content.InnerControl ) ).DefaultDrawingAttributes = da;
        }
 
        #endregion // Private Methods
 
        //-------------------------------------------------------------------------------- 
        //
        // Private Properties 
        //
        //-------------------------------------------------------------------------------

        #region Private Properties 

        ///  
        /// Returns Ink MenuItem 
        /// 
        private MenuItem GetInkMenuItem() 
        {
            return GetTemplateChild(SNBConstants.c_InkMenuId) as MenuItem;
        }
 
        /// 
        /// Returns Select MenuItem 
        ///  
        private MenuItem GetSelectMenuItem()
        { 
            return GetTemplateChild(SNBConstants.c_SelectMenuId) as MenuItem;
        }

        ///  
        /// Returns Erase MenuItem
        ///  
        private MenuItem GetEraseMenuItem() 
        {
            return GetTemplateChild(SNBConstants.c_EraseMenuId) as MenuItem; 
        }

        /// 
        /// Returns Copy MenuItem 
        /// 
        private MenuItem GetCopyMenuItem() 
        { 
            return GetTemplateChild(SNBConstants.c_CopyMenuId) as MenuItem;
        } 

        /// 
        /// Returns Paste MenuItem
        ///  
        private MenuItem GetPasteMenuItem()
        { 
            return GetTemplateChild(SNBConstants.c_PasteMenuId) as MenuItem; 
        }
 
        /// 
        /// Returns Separator for clipboard MenuItems
        /// 
        private Separator GetClipboardSeparator() 
        {
            return GetTemplateChild(SNBConstants.c_ClipboardSeparatorId) as Separator; 
        } 

        // This is the getter of _lockHelper which is a helper object for locking/unlocking a specified flag automatically. 
        private LockHelper InternalLocker
        {
            get
            { 
                // Check if we have create a helper. If not, we go ahead create one.
                if (_lockHelper == null) 
                { 
                    _lockHelper = new LockHelper();
                } 

                return _lockHelper;
            }
        } 

        #endregion // Private Properties 
 
        //-------------------------------------------------------------------------------
        // 
        // Private Fields
        //
        //-------------------------------------------------------------------------------
 
        #region Private Fields
 
        private LockHelper _lockHelper; 

        private MarkedHighlightComponent _anchor; //holds inactive, active, focused state 

        private bool _dirty = false;

        // Cache for the dependency properties 
        private StickyNoteType _stickyNoteType = StickyNoteType.Text;
 
        private StickyNoteContentControl _contentControl; 

        private StrokeChangedHandler _propertyDataChangedHandler; 
        private StrokeChangedHandler _strokeDrawingAttributesReplacedHandler;
        private StrokeChangedHandler _strokePacketDataChangedHandler;

        #endregion // Private Fields 

 
 
        //--------------------------------------------------------------------------------
        // 
        // Private classes
        //
        //-------------------------------------------------------------------------------
 
        #region Private classes
 
        // This is a binding converter which alters the IsChecked DP based on ink StickyNote's EditingMode of its InkCanvas. 
        private class InkEditingModeConverter : IValueConverter
        { 
            public object Convert(object o, Type type, object parameter, CultureInfo culture)
            {
                InkCanvasEditingMode expectedMode = (InkCanvasEditingMode)parameter;
                InkCanvasEditingMode currentMode = (InkCanvasEditingMode)o; 

                // If the current EditingMode is the mode which menuitem is expecting, return true for IsChecked. 
                if ( currentMode == expectedMode ) 
                {
                    return true; 
                }
                else
                {
                    return DependencyProperty.UnsetValue; 
                }
            } 
 
            public object ConvertBack(object o, Type type, object parameter, CultureInfo culture)
            { 
                return null;
            }
        }
 
        // This is a binding converter which alters the InkCanvas.EditingMode DP
        // based on StickyNoteControl.InkEditingMode and StickyNoteControl.IsKeyboardFocusWithin. 
        private class InkEditingModeIsKeyboardFocusWithin2EditingMode : IMultiValueConverter 
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
            {
                InkCanvasEditingMode sncInkEditingMode = (InkCanvasEditingMode)values[0];

                bool sncIsKeyboardFocusWithin = (bool)values[1]; 

                // If there is no focus on the StickyNote, we should return InkCanvasEditingMode.None to disable the RTI. 
                // Otherwise return the  value of the StickyNoteControl.InkEditingMode property. 
                if ( sncIsKeyboardFocusWithin )
                { 
                    return sncInkEditingMode;
                }
                else
                { 
                    return InkCanvasEditingMode.None;
                } 
            } 

            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
            {
                return new object[] { value, Binding.DoNothing };
            }
        } 

        // A helper class which suppresses severial handlers to a single methods by using generic 
        private class StrokeChangedHandler 
        {
            public StrokeChangedHandler(StickyNoteControl snc) 
            {
                Invariant.Assert(snc != null);
                _snc = snc;
            } 

            public void OnStrokeChanged(object sender, TEventArgs t) 
            { 
                // Dirty the ink data
                _snc.UpdateAnnotationWithSNC(XmlToken.Ink); 
                _snc._dirty = true;
            }

            private StickyNoteControl _snc; 
        }
 
        #endregion Private classes 

    } 
}


 


// 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