InkCanvas.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / InkCanvas.cs / 1305600 / InkCanvas.cs

                            //#define DEBUG_LASSO_FEEDBACK // DO NOT LEAVE ENABLED IN CHECKED IN CODE 
//----------------------------------------------------------------------------
//
// File: InkCanvas.cs
// 
// Description:
//      Defines an inkable canvas that represents the primary api for 
//      editing ink 
//
// Features: 
//
// History:
//  1/29/2002 samgeo:       Created
//  9/12/2003 samgeo:       Started porting to WCP 
//
// Copyright (C) 2001 by Microsoft Corporation.  All rights reserved. 
// 
//---------------------------------------------------------------------------
 
using MS.Utility;
using MS.Internal;
using MS.Internal.Commands;
using MS.Internal.Controls; 
using MS.Internal.Ink;
using MS.Internal.KnownBoxes; 
using System; 
using System.Collections;
using System.Collections.ObjectModel; 
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics; 
using System.IO;
using System.Windows; 
using System.Collections.Generic; 
using System.Security;
using System.Security.Permissions; 
using System.Runtime.InteropServices;
using System.Windows.Media;
using System.Windows.Data;
using System.Windows.Documents; 
using System.Windows.Ink;
using System.Windows.Input; 
using System.Windows.Input.StylusPlugIns; 
using System.Windows.Controls;
using System.Windows.Markup; // IAddChild, ContentPropertyAttribute 
using System.Windows.Threading;
using System.Windows.Automation.Peers;

namespace System.Windows.Controls 
{
 
    ///  
    /// InkCanvas is used to allow inking on a canvas
    ///  
    [ContentProperty("Children")]
    public class InkCanvas : FrameworkElement, IAddChild
    {
 
        #region Constructors / Initialization
 
        ///  
        /// The static constructor
        ///  
        static InkCanvas()
        {
            Type ownerType = typeof(InkCanvas);
 
            // NTRAID-WINDOWS#1423922-2005/12/15-WAYNEZEN,
            // We should add the following listener as the class handler which will be guarantied to receive the 
            // notification before the handler on the instances. So we won't be trapped in the bad state due to the 
            // event routing.
            // Listen to stylus events which will be redirected to the current StylusEditingBehavior 

            //Down
            EventManager.RegisterClassHandler(ownerType, Stylus.StylusDownEvent,
                new StylusDownEventHandler(_OnDeviceDown)); 
            EventManager.RegisterClassHandler(ownerType, Mouse.MouseDownEvent,
                new MouseButtonEventHandler(_OnDeviceDown)); 
 
            //Up
            EventManager.RegisterClassHandler(ownerType, Stylus.StylusUpEvent, 
                new StylusEventHandler(_OnDeviceUp));
            EventManager.RegisterClassHandler(ownerType, Mouse.MouseUpEvent,
                new MouseButtonEventHandler(_OnDeviceUp));
 

 
            EventManager.RegisterClassHandler(ownerType, Mouse.QueryCursorEvent, 
                new QueryCursorEventHandler(_OnQueryCursor), true);
 
            // Set up the commanding handlers
            _RegisterClipboardHandlers();
            CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.Delete,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled)); 

            CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.SelectAll, 
                Key.A, ModifierKeys.Control, new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled)); 

            CommandHelpers.RegisterCommandHandler(ownerType, InkCanvas.DeselectCommand, 
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled),
                SRID.InkCanvasDeselectKey, SRID.InkCanvasDeselectKeyDisplayString);

            // 
            //set our clipping
            // 
            ClipToBoundsProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(BooleanBoxes.TrueBox)); 

            // 
            //enable input focus
            //
            FocusableProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(BooleanBoxes.TrueBox));
 
            // The default InkCanvas style
            Style defaultStyle = new Style(ownerType); 
            // The background - Window Color 
            defaultStyle.Setters.Add(new Setter(InkCanvas.BackgroundProperty,
                            new DynamicResourceExtension(SystemColors.WindowBrushKey))); 
            // Default InkCanvas to having flicks disabled by default.
            defaultStyle.Setters.Add(new Setter(Stylus.IsFlicksEnabledProperty, false));
            // Default InkCanvas to having tap feedback disabled by default.
            defaultStyle.Setters.Add(new Setter(Stylus.IsTapFeedbackEnabledProperty, false)); 
            // Default InkCanvas to having touch feedback disabled by default.
            defaultStyle.Setters.Add(new Setter(Stylus.IsTouchFeedbackEnabledProperty, false)); 
 
            // Set MinWidth to 350d if Width is set to Auto
            Trigger trigger = new Trigger(); 
            trigger.Property = WidthProperty;
            trigger.Value = double.NaN;
            Setter setter = new Setter();
            setter.Property = MinWidthProperty; 
            setter.Value = 350d;
            trigger.Setters.Add(setter); 
            defaultStyle.Triggers.Add(trigger); 

            // Set MinHeight to 250d if Height is set to Auto 
            trigger = new Trigger();
            trigger.Property = HeightProperty;
            trigger.Value = double.NaN;
            setter = new Setter(); 
            setter.Property = MinHeightProperty;
            setter.Value = 250d; 
            trigger.Setters.Add(setter); 
            defaultStyle.Triggers.Add(trigger);
 
            // Seal the default style
            defaultStyle.Seal();

            StyleProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(defaultStyle)); 
            DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(typeof(InkCanvas)));
 
            FocusVisualStyleProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata((object)null /* default value */)); 
        }
 
        /// 
        /// Public constructor.
        /// 
        public InkCanvas() : base() 
        {
            Initialize(); 
        } 

        ///  
        /// Private initialization method used by the constructors
        /// 
        private void Initialize()
        { 
            //
            // instance the DynamicRenderer and add it to the StylusPlugIns 
            // 
            _dynamicRenderer = new DynamicRenderer();
            _dynamicRenderer.Enabled = false; 
            this.StylusPlugIns.Add(_dynamicRenderer);

            //
            // create and initialize an editing coordinator 
            //
            _editingCoordinator = new EditingCoordinator(this); 
            _editingCoordinator.UpdateActiveEditingState(); 

 
            // connect the attributes event handler after setting the stylus shape to avoid unnecessary
            //      calls into the RTI service
            DefaultDrawingAttributes.AttributeChanged += new PropertyDataChangedEventHandler(DefaultDrawingAttributes_Changed);
 
            //
            // 
            // We must initialize this here (after adding DynamicRenderer to Sytlus). 
            //
            this.InitializeInkObject(); 

            _rtiHighContrastCallback = new RTIHighContrastCallback(this);

            // Register rti high contrast callback. Then check whether we are under the high contrast already. 
            HighContrastHelper.RegisterHighContrastCallback(_rtiHighContrastCallback);
            if ( SystemParameters.HighContrast ) 
            { 
                _rtiHighContrastCallback.TurnHighContrastOn(SystemColors.WindowTextColor);
            } 
        }

        /// 
        /// Private helper used to change the Ink objects.  Used in the constructor 
        /// and the Ink property.
        /// 
        /// NOTE -- Caller is responsible for clearing any selection!  (We can't clear it 
        ///         here because the Constructor calls this method and it would end up calling
        ///         looking like it could call a virtual method and FxCop doesn't like that!) 
        ///
        /// 
        private void InitializeInkObject()
        { 
            // Update the RealTimeInking PlugIn for the Renderer changes.
            UpdateDynamicRenderer(); 
 
            // Initialize DefaultPacketDescription
            _defaultStylusPointDescription = new StylusPointDescription(); 

        }
        #endregion Constructors  / Initialization
 
        #region Protected Overrides
 
        ///  
        /// MeasureOverride
        ///  
        /// 
        /// 
        protected override Size MeasureOverride(Size availableSize)
        { 
            // No need to invoke VerifyAccess since _localAdornerDecorator.Measure should check it.
            if ( _localAdornerDecorator == null ) 
            { 
                ApplyTemplate();
            } 

            _localAdornerDecorator.Measure(availableSize);

            return  _localAdornerDecorator.DesiredSize; 
        }
 
        ///  
        /// ArrangeOverride
        ///  
        /// 
        /// 
        protected override Size ArrangeOverride(Size arrangeSize)
        { 
            // No need to invoke VerifyAccess since _localAdornerDecorator.Arrange should check it.
 
            if ( _localAdornerDecorator == null ) 
            {
                ApplyTemplate(); 
            }

            _localAdornerDecorator.Arrange(new Rect(arrangeSize));
 
            return arrangeSize;
        } 
 

        ///  
        /// HitTestCore implements precise hit testing against render contents
        /// 
        protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParams)
        { 
            VerifyAccess();
 
            Rect r = new Rect(new Point(), RenderSize); 
            if (r.Contains(hitTestParams.HitPoint))
            { 
                return new PointHitTestResult(this, hitTestParams.HitPoint);
            }

            return null; 
        }
 
        ///  
        /// OnPropertyChanged
        ///  
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
 
            if (e.IsAValueChange || e.IsASubPropertyChange)
            { 
                if (e.Property == UIElement.RenderTransformProperty || 
                    e.Property == FrameworkElement.LayoutTransformProperty)
                { 
                    EditingCoordinator.InvalidateTransform();

                    Transform transform = e.NewValue as Transform;
                    if (transform != null && !transform.HasAnimatedProperties) 
                    {
                        TransformGroup transformGroup = transform as TransformGroup; 
                        if ( transformGroup != null ) 
                        {
                            //walk down the tree looking for animated transforms 
                            Stack transforms = new Stack();
                            transforms.Push(transform);
                            while ( transforms.Count > 0 )
                            { 
                                transform = transforms.Pop();
                                if ( transform.HasAnimatedProperties ) 
                                { 
                                    return;
                                } 
                                transformGroup = transform as TransformGroup;
                                if ( transformGroup != null )
                                {
                                    for ( int i = 0; i < transformGroup.Children.Count; i++ ) 
                                    {
                                        transforms.Push(transformGroup.Children[i]); 
                                    } 
                                }
                            } 
                        }

                        //
                        // only invalidate when there is not an animation on the xf, 
                        // or we could wind up creating thousands of new cursors.  That's bad.
                        // 
                        _editingCoordinator.InvalidateBehaviorCursor(_editingCoordinator.InkCollectionBehavior); 
                        EditingCoordinator.UpdatePointEraserCursor();
                    } 
                }
                if (e.Property == FrameworkElement.FlowDirectionProperty)
                {
                    //flow direction only affects the inking cursor. 
                    _editingCoordinator.InvalidateBehaviorCursor(_editingCoordinator.InkCollectionBehavior);
                } 
            } 
        }
 
        /// 
        /// Called when the Template's tree is about to be generated
        /// 
        internal override void OnPreApplyTemplate() 
        {
            // No need for calling VerifyAccess since we call the method on the base here. 
 
            base.OnPreApplyTemplate();
 
            // Build our visual tree here.
            // 
            //     
            //          
            //             
            //                            
            //                                 
            //         
            //                                 
            //             
            //                  
            //         
            //      
            //  
 
            if ( _localAdornerDecorator == null ) 
            {
                // 
                _localAdornerDecorator = new AdornerDecorator();
                InkPresenter inkPresenter = InkPresenter;

                // Build the visual tree top-down 
                AddVisualChild(_localAdornerDecorator);
                _localAdornerDecorator.Child = inkPresenter; 
                inkPresenter.Child = InnerCanvas; 

                // Add the SelectionAdorner after Canvas is added. 
                _localAdornerDecorator.AdornerLayer.Add(SelectionAdorner);
            }
        }
 
        /// 
        /// Returns the Visual children count. 
        ///  
        protected override int VisualChildrenCount
        { 
            get { return (_localAdornerDecorator == null) ? 0 : 1; }
        }

        ///  
        /// Returns the child at the specified index.
        ///  
        protected override Visual GetVisualChild(int index) 
        {
            if (    (_localAdornerDecorator == null) 
                ||  (index != 0))
            {
                throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
            } 

            return _localAdornerDecorator; 
        } 

        ///  
        /// UIAutomation support
        /// 
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new InkCanvasAutomationPeer(this);
        } 
 
        #endregion Protected Overrides
 
        #region Public Properties

        /// 
        ///     The DependencyProperty for the Background property. 
        /// 
        public static readonly DependencyProperty BackgroundProperty = 
                Panel.BackgroundProperty.AddOwner( 
                        typeof(InkCanvas),
                        new FrameworkPropertyMetadata( 
                                null,
                                FrameworkPropertyMetadataOptions.AffectsRender));

        ///  
        ///     An object that describes the background.
        ///  
        [Bindable(true), Category("Appearance")] 
        public Brush Background
        { 
            get { return (Brush) GetValue(BackgroundProperty); }
            set { SetValue(BackgroundProperty, value); }
        }
 
        /// 
        /// Top DependencyProperty 
        ///  
        public static readonly DependencyProperty TopProperty =
                DependencyProperty.RegisterAttached("Top", typeof(double), typeof(InkCanvas), 
                    new FrameworkPropertyMetadata(Double.NaN, new PropertyChangedCallback(OnPositioningChanged)),
                    new ValidateValueCallback(System.Windows.Shapes.Shape.IsDoubleFiniteOrNaN));

        ///  
        /// Reads the attached property Top from the given element.
        ///  
        /// The element from which to read the Top attached property. 
        /// The property's value.
        ///  
        [TypeConverter("System.Windows.LengthConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")]
        [AttachedPropertyBrowsableForChildren()]
        public static double GetTop(UIElement element)
        { 
            if (element == null) { throw new ArgumentNullException("element"); }
            return (double)element.GetValue(TopProperty); 
        } 

        ///  
        /// Writes the attached property Top to the given element.
        /// 
        /// The element to which to write the Top attached property.
        /// The length to set 
        /// 
        public static void SetTop(UIElement element, double length) 
        { 
            if (element == null) { throw new ArgumentNullException("element"); }
            element.SetValue(TopProperty, length); 
        }

        /// 
        /// The Bottom DependencyProperty 
        /// 
        public static readonly DependencyProperty BottomProperty = 
                DependencyProperty.RegisterAttached("Bottom", typeof(double), typeof(InkCanvas), 
                    new FrameworkPropertyMetadata(Double.NaN, new PropertyChangedCallback(OnPositioningChanged)),
                    new ValidateValueCallback(System.Windows.Shapes.Shape.IsDoubleFiniteOrNaN)); 

        /// 
        /// Reads the attached property Bottom from the given element.
        ///  
        /// The element from which to read the Bottom attached property.
        /// The property's Length value. 
        ///  
        [TypeConverter("System.Windows.LengthConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")]
        [AttachedPropertyBrowsableForChildren()] 
        public static double GetBottom(UIElement element)
        {
            if (element == null) { throw new ArgumentNullException("element"); }
            return (double)element.GetValue(BottomProperty); 
        }
 
        ///  
        /// Writes the attached property Bottom to the given element.
        ///  
        /// The element to which to write the Bottom attached property.
        /// The Length to set
        /// 
        public static void SetBottom(UIElement element, double length) 
        {
            if (element == null) { throw new ArgumentNullException("element"); } 
            element.SetValue(BottomProperty, length); 
        }
 
        /// 
        /// The Left DependencyProperty
        /// 
        public static readonly DependencyProperty LeftProperty = 
                DependencyProperty.RegisterAttached("Left", typeof(double), typeof(InkCanvas),
                    new FrameworkPropertyMetadata(Double.NaN, new PropertyChangedCallback(OnPositioningChanged)), 
                    new ValidateValueCallback(System.Windows.Shapes.Shape.IsDoubleFiniteOrNaN)); 

        ///  
        /// Reads the attached property Left from the given element.
        /// 
        /// The element from which to read the Left attached property.
        /// The property's value. 
        /// 
        [TypeConverter("System.Windows.LengthConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")] 
        [AttachedPropertyBrowsableForChildren()] 
        public static double GetLeft(UIElement element)
        { 
            if (element == null) { throw new ArgumentNullException("element"); }
            return (double)element.GetValue(LeftProperty);
        }
 
        /// 
        /// Writes the attached property Left to the given element. 
        ///  
        /// The element to which to write the Left attached property.
        /// The length to set 
        /// 
        public static void SetLeft(UIElement element, double length)
        {
            if (element == null) { throw new ArgumentNullException("element"); } 
            element.SetValue(LeftProperty, length);
        } 
 
        /// 
        /// The Right DependencyProperty 
        /// 
        public static readonly DependencyProperty RightProperty =
                DependencyProperty.RegisterAttached("Right", typeof(double), typeof(InkCanvas),
                    new FrameworkPropertyMetadata(Double.NaN, new PropertyChangedCallback(OnPositioningChanged)), 
                    new ValidateValueCallback(System.Windows.Shapes.Shape.IsDoubleFiniteOrNaN));
 
        ///  
        /// Reads the attached property Right from the given element.
        ///  
        /// The element from which to read the Right attached property.
        /// The property's Length value.
        /// 
        [TypeConverter("System.Windows.LengthConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")] 
        [AttachedPropertyBrowsableForChildren()]
        public static double GetRight(UIElement element) 
        { 
            if (element == null) { throw new ArgumentNullException("element"); }
            return (double)element.GetValue(RightProperty); 
        }

        /// 
        /// Writes the attached property Right to the given element. 
        /// 
        /// The element to which to write the Right attached property. 
        /// The Length to set 
        /// 
        public static void SetRight(UIElement element, double length) 
        {
            if (element == null) { throw new ArgumentNullException("element"); }
            element.SetValue(RightProperty, length);
        } 

        ///  
        /// OnPositioningChanged 
        /// 
        ///  
        /// 
        private static void OnPositioningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement uie = d as UIElement; 
            if ( uie != null )
            { 
                // Make sure the UIElement is a child of InkCanvasInnerCanvas. 
                InkCanvasInnerCanvas p = VisualTreeHelper.GetParent(uie) as InkCanvasInnerCanvas;
                if ( p != null ) 
                {
                    if ( e.Property == InkCanvas.LeftProperty
                        || e.Property == InkCanvas.TopProperty )
                    { 
                        // Invalidate measure for Left and/or Top.
                        p.InvalidateMeasure(); 
                    } 
                    else
                    { 
                        Debug.Assert(e.Property == InkCanvas.RightProperty || e.Property == InkCanvas.BottomProperty,
                            string.Format(System.Globalization.CultureInfo.InvariantCulture, "Unknown dependency property detected - {0}.", e.Property));

                        // Invalidate arrange for Right and/or Bottom. 
                        p.InvalidateArrange();
                    } 
                } 
            }
        } 

        /// 
        ///     The DependencyProperty for the Strokes property.
        ///  
        public static readonly DependencyProperty StrokesProperty =
                InkPresenter.StrokesProperty.AddOwner( 
                        typeof(InkCanvas), 
                        new FrameworkPropertyMetadata(
                                new StrokeCollectionDefaultValueFactory(), 
                                new PropertyChangedCallback(OnStrokesChanged)));

        /// 
        /// Gets/Sets the Strokes property. 
        /// 
        public StrokeCollection Strokes 
        { 
            get { return (StrokeCollection)GetValue(StrokesProperty); }
            set { SetValue(StrokesProperty, value); } 
        }

        private static void OnStrokesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            InkCanvas inkCanvas = (InkCanvas)d;
            StrokeCollection oldValue = (StrokeCollection)e.OldValue; 
            StrokeCollection newValue = (StrokeCollection)e.NewValue; 

            // 
            // only change the prop if it's a different object.  We don't
            // want to be doing this for no reason
            //
            if ( !object.ReferenceEquals(oldValue, newValue) ) 
            {
                // Clear the selected strokes without raising event. 
                inkCanvas.CoreChangeSelection(new StrokeCollection(), inkCanvas.InkCanvasSelection.SelectedElements, false); 

                inkCanvas.InitializeInkObject(); 

                InkCanvasStrokesReplacedEventArgs args =
                    new InkCanvasStrokesReplacedEventArgs(newValue, oldValue); //new, previous
 
                //raise the StrokesChanged event through our protected virtual
                inkCanvas.OnStrokesReplaced(args); 
            } 

        } 

        /// 
        /// Returns the SelectionAdorner
        ///  
        internal InkCanvasSelectionAdorner SelectionAdorner
        { 
            get 
            {
                // We have to create our visual at this point. 
                if ( _selectionAdorner == null )
                {
                    // Create the selection Adorner.
                    _selectionAdorner = new InkCanvasSelectionAdorner(InnerCanvas); 

                    // Bind the InkCanvas.ActiveEditingModeProperty 
                    // to SelectionAdorner.VisibilityProperty. 
                    Binding activeEditingModeBinding = new Binding();
                    activeEditingModeBinding.Path = new PropertyPath(InkCanvas.ActiveEditingModeProperty); 
                    activeEditingModeBinding.Mode = BindingMode.OneWay;
                    activeEditingModeBinding.Source = this;
                    activeEditingModeBinding.Converter = new ActiveEditingMode2VisibilityConverter();
                    _selectionAdorner.SetBinding(UIElement.VisibilityProperty, activeEditingModeBinding); 
                }
 
                return _selectionAdorner; 
            }
        } 

        /// 
        /// Returns the FeedbackAdorner
        ///  
        internal InkCanvasFeedbackAdorner FeedbackAdorner
        { 
            get 
            {
                VerifyAccess(); 

                if ( _feedbackAdorner == null )
                {
                    _feedbackAdorner = new InkCanvasFeedbackAdorner(this); 
                }
 
                return _feedbackAdorner; 
            }
        } 

        /// 
        /// Read/Write access to the EraserShape property.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsGestureRecognizerAvailable 
        { 
            get
            { 
                //this property will verify access
                return this.GestureRecognizer.IsRecognizerAvailable;
            }
        } 

 
        ///  
        /// Emulate Panel's Children property.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public UIElementCollection Children
        {
            get 
            {
                // No need to invoke VerifyAccess since the call is forwarded. 
 
                return InnerCanvas.Children;
            } 
        }

        /// 
        /// The DependencyProperty for the DefaultDrawingAttributes property. 
        /// 
        public static readonly DependencyProperty DefaultDrawingAttributesProperty = 
                DependencyProperty.Register( 
                        "DefaultDrawingAttributes",
                        typeof(DrawingAttributes), 
                        typeof(InkCanvas),
                        new FrameworkPropertyMetadata(
                                new DrawingAttributesDefaultValueFactory(),
                                new PropertyChangedCallback(OnDefaultDrawingAttributesChanged)), 
                        (ValidateValueCallback)delegate(object value)
                            { return value != null; }); 
 
        /// 
        /// Gets/Sets the DefaultDrawingAttributes property. 
        /// 
        public DrawingAttributes DefaultDrawingAttributes
        {
            get { return (DrawingAttributes)GetValue(DefaultDrawingAttributesProperty); } 
            set { SetValue(DefaultDrawingAttributesProperty, value); }
        } 
 
        private static void OnDefaultDrawingAttributesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            InkCanvas inkCanvas = (InkCanvas)d;

            DrawingAttributes oldValue = (DrawingAttributes)e.OldValue;
            DrawingAttributes newValue = (DrawingAttributes)e.NewValue; 

            // This can throw, so call it first 
            inkCanvas.UpdateDynamicRenderer(newValue); 

            // We only fire Changed event when there is an instance change. 
            if ( !object.ReferenceEquals(oldValue, newValue) )
            {
                //we didn't throw, change our backing value
                oldValue.AttributeChanged -= new PropertyDataChangedEventHandler(inkCanvas.DefaultDrawingAttributes_Changed); 
                DrawingAttributesReplacedEventArgs args =
                    new DrawingAttributesReplacedEventArgs(newValue, oldValue); 
 
                newValue.AttributeChanged += new PropertyDataChangedEventHandler(inkCanvas.DefaultDrawingAttributes_Changed);
                inkCanvas.RaiseDefaultDrawingAttributeReplaced(args); 
            }
        }

        ///  
        /// Read/Write access to the EraserShape property.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public StylusShape EraserShape
        { 
            get
            {
                VerifyAccess();
                if (_eraserShape == null) 
                {
                    _eraserShape = new RectangleStylusShape(8f, 8f); 
                } 
                return _eraserShape;
 
            }
            set
            {
                VerifyAccess(); 
                if (value == null)
                { 
                    throw new ArgumentNullException("value"); 
                }
                else 
                {
                    // Invoke getter since this property is lazily created.
                    StylusShape oldShape = EraserShape;
 
                    _eraserShape = value;
 
 
                    if ( oldShape.Width != _eraserShape.Width || oldShape.Height != _eraserShape.Height
                        || oldShape.Rotation != _eraserShape.Rotation || oldShape.GetType() != _eraserShape.GetType()) 
                    {
                        EditingCoordinator.UpdatePointEraserCursor();
                    }
                } 
            }
        } 
 

        ///  
        /// ActiveEditingMode
        /// 
        internal static readonly DependencyPropertyKey ActiveEditingModePropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "ActiveEditingMode",
                        typeof(InkCanvasEditingMode), 
                        typeof(InkCanvas), 
                        new FrameworkPropertyMetadata(InkCanvasEditingMode.Ink));
 
        /// 
        /// ActiveEditingModeProperty Dependency Property
        /// 
        public static readonly DependencyProperty ActiveEditingModeProperty = ActiveEditingModePropertyKey.DependencyProperty; 

        ///  
        /// Gets the ActiveEditingMode 
        /// 
        public InkCanvasEditingMode ActiveEditingMode 
        {
            get { return (InkCanvasEditingMode)GetValue(ActiveEditingModeProperty); }
        }
 
        /// 
        /// The DependencyProperty for the EditingMode property. 
        ///  
        public static readonly DependencyProperty EditingModeProperty =
                DependencyProperty.Register( 
                        "EditingMode",
                        typeof(InkCanvasEditingMode),
                        typeof(InkCanvas),
                        new FrameworkPropertyMetadata( 
                                InkCanvasEditingMode.Ink,
                                new PropertyChangedCallback(OnEditingModeChanged)), 
                        new ValidateValueCallback(ValidateEditingMode)); 

 
        /// 
        /// Gets/Sets EditingMode
        /// 
        public InkCanvasEditingMode EditingMode 
        {
            get { return (InkCanvasEditingMode)GetValue(EditingModeProperty); } 
            set { SetValue(EditingModeProperty, value); } 
        }
 

        private static void OnEditingModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ( (InkCanvas)d ).RaiseEditingModeChanged( 
                                new RoutedEventArgs(InkCanvas.EditingModeChangedEvent, d));
        } 
 
        /// 
        /// The DependencyProperty for the EditingModeInverted property. 
        /// 
        public static readonly DependencyProperty EditingModeInvertedProperty =
                DependencyProperty.Register(
                        "EditingModeInverted", 
                        typeof(InkCanvasEditingMode),
                        typeof(InkCanvas), 
                        new FrameworkPropertyMetadata( 
                                InkCanvasEditingMode.EraseByStroke,
                                new PropertyChangedCallback(OnEditingModeInvertedChanged)), 
                        new ValidateValueCallback(ValidateEditingMode));

        /// 
        /// Gets/Sets EditingMode 
        /// 
        public InkCanvasEditingMode EditingModeInverted 
        { 
            get { return (InkCanvasEditingMode)GetValue(EditingModeInvertedProperty); }
            set { SetValue(EditingModeInvertedProperty, value); } 
        }

        private static void OnEditingModeInvertedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ( (InkCanvas)d ).RaiseEditingModeInvertedChanged(
                new RoutedEventArgs(InkCanvas.EditingModeInvertedChangedEvent, d)); 
        } 

        private static bool ValidateEditingMode(object value) 
        {
            return EditingModeHelper.IsDefined((InkCanvasEditingMode)value);
        }
 
        /// 
        /// This flag indicates whether the developer is using a custom mouse cursor. 
        /// 
        /// If this flag is true, we will never change the current cursor on them. Not
        /// on edit mode change. 
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool UseCustomCursor
        { 
            get
            { 
                VerifyAccess(); 
                return _useCustomCursor;
            } 
            set
            {
                VerifyAccess();
 
                if ( _useCustomCursor != value )
                { 
                    _useCustomCursor = value; 
                    UpdateCursor();
                } 
            }
        }

        ///  
        /// Gets or set if moving of selection is enabled
        ///  
        /// bool 
        public bool MoveEnabled
        { 
            get
            {
                VerifyAccess();
                return _editingCoordinator.MoveEnabled; 
            }
            set 
            { 
                VerifyAccess();
                bool oldValue = _editingCoordinator.MoveEnabled; 

                if (oldValue != value)
                {
                    _editingCoordinator.MoveEnabled = value; 
                }
            } 
        } 

        ///  
        /// Gets or set if resizing selection is enabled
        /// 
        /// bool
        public bool ResizeEnabled 
        {
            get 
            { 
                VerifyAccess();
                return _editingCoordinator.ResizeEnabled; 
            }
            set
            {
                VerifyAccess(); 
                bool oldValue = _editingCoordinator.ResizeEnabled;
 
                if (oldValue != value) 
                {
                    _editingCoordinator.ResizeEnabled = value; 
                }
            }
        }
 

        ///  
        /// Read/Write access to the DefaultPacketDescription property. 
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public StylusPointDescription DefaultStylusPointDescription
        {
            get
            { 
                VerifyAccess();
 
                return _defaultStylusPointDescription; 
            }
            set 
            {
                VerifyAccess();

                // 
                // no nulls allowed
                // 
                if ( value == null ) 
                {
                    throw new ArgumentNullException("value"); 
                }

                _defaultStylusPointDescription = value;
            } 
        }
 
        ///  
        /// Read/Write the enabled ClipboardFormats
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IEnumerable PreferredPasteFormats
        {
            get 
            {
                VerifyAccess(); 
 
                return ClipboardProcessor.PreferredFormats;
            } 
            set
            {
                VerifyAccess();
 
                // Cannot be null
                if ( value == null ) 
                { 
                    // Null is not allowed as the argument value
                    throw new ArgumentNullException("value"); 
                }

                ClipboardProcessor.PreferredFormats = value;
            } 
        }
 
        #endregion Public Properties 

        #region Public Events 

        /// 
        ///     The StrokeErased Routed Event
        ///  
        public static readonly RoutedEvent StrokeCollectedEvent =
            EventManager.RegisterRoutedEvent("StrokeCollected", RoutingStrategy.Bubble, typeof(InkCanvasStrokeCollectedEventHandler), typeof(InkCanvas)); 
 
        /// 
        ///     Add / Remove StrokeCollected handler 
        /// 
        [Category("Behavior")]
        public event InkCanvasStrokeCollectedEventHandler StrokeCollected
        { 
            add
            { 
                AddHandler(InkCanvas.StrokeCollectedEvent, value); 
            }
 
            remove
            {
                RemoveHandler(InkCanvas.StrokeCollectedEvent, value);
            } 
        }
 
        ///  
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// InkCanvasStrokeCollectedEventArgs to raise the event with
        protected virtual void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free.
 
            if ( e == null ) 
            {
                throw new ArgumentNullException("e"); 
            }

            RaiseEvent(e);
        } 

        ///  
        /// Allows the InkCollectionBehavior to raise the StrokeCollected event via the protected virtual 
        /// 
        /// InkCanvasStrokeCollectedEventArgs to raise the event with 
        /// true only if 100% of the stylusPoints that makes up the stroke
        /// came from eventargs with the UserInitiated flag set to true
        /// 
        ///     Critical: Calls critical method GestureRecognizer.CriticalRecognize.  It is important 
        ///         that this is only called if userInitiated is true.
        ///  
        [SecurityCritical] 
        internal void RaiseGestureOrStrokeCollected(InkCanvasStrokeCollectedEventArgs e, bool userInitiated)
        { 
            Debug.Assert(e != null, "EventArg can not be null");
            bool addStrokeToInkCanvas = true; // Initialize our flag.

            // The follow code raises Gesture event 
            // The out-side code could throw exception in the their handlers. We use try/finally block to protect our status.
            try 
            { 
                //
                // perform gesture reco before raising this event 
                // if we're in the right mode
                //
                //IMPORTANT: only call gesture recognition if userInitiated.  See SecurityNote.
                if (userInitiated) 
                {
                    if ((this.ActiveEditingMode == InkCanvasEditingMode.InkAndGesture || 
                          this.ActiveEditingMode == InkCanvasEditingMode.GestureOnly) && 
                          this.GestureRecognizer.IsRecognizerAvailable)
                    { 
                        StrokeCollection strokes = new StrokeCollection();
                        strokes.Add(e.Stroke);

                        // 
                        // GestureRecognizer.Recognize demands unmanaged code, we assert it here
                        // as this codepath is only called in response to user input 
                        // 
                        ReadOnlyCollection results =
                            this.GestureRecognizer.CriticalRecognize(strokes); 

                        if (results.Count > 0)
                        {
                            InkCanvasGestureEventArgs args = 
                                new InkCanvasGestureEventArgs(strokes, results);
 
                            if (results[0].ApplicationGesture == ApplicationGesture.NoGesture) 
                            {
                                // 
                                // we set Cancel=true if we didn't detect a gesture
                                //
                                args.Cancel = true;
                            } 
                            else
                            { 
                                args.Cancel = false; 
                            }
 
                            this.OnGesture(args);

                            //
                            // now that we've raised the Gesture event and the developer 
                            // has had a chance to change args.Cancel, see what their intent is.
                            // 
                            if (args.Cancel == false) 
                            {
                                //bail out and don't add 
                                //the stroke to InkCanvas.Strokes
                                addStrokeToInkCanvas = false; // Reset the flag.
                                return;
                            } 
                        }
                    } 
                } 

                // Reset the flag. 
                addStrokeToInkCanvas = false;

                //
                // only raise StrokeCollected if we're in InkCanvasEditingMode.Ink or InkCanvasEditingMode.InkAndGesture 
                //
                if ( this.ActiveEditingMode == InkCanvasEditingMode.Ink || 
                    this.ActiveEditingMode == InkCanvasEditingMode.InkAndGesture ) 
                {
                    //add the stroke to the StrokeCollection and raise this event 
                    this.Strokes.Add(e.Stroke);
                    this.OnStrokeCollected(e);
                }
            } 
            finally
            { 
                // If the gesture events are failed, we should still add Stroke to the InkCanvas so that the data won't be lost. 
                if ( addStrokeToInkCanvas )
                { 
                    this.Strokes.Add(e.Stroke);
                }
            }
        } 

        ///  
        ///     The Gesture Routed Event 
        /// 
        public static readonly RoutedEvent GestureEvent = 
            EventManager.RegisterRoutedEvent("Gesture", RoutingStrategy.Bubble, typeof(InkCanvasGestureEventHandler), typeof(InkCanvas));

        /// 
        ///     Add / Remove Gesture handler 
        /// 
        [Category("Behavior")] 
        public event InkCanvasGestureEventHandler Gesture 
        {
            add 
            {
                AddHandler(InkCanvas.GestureEvent, value);
            }
 
            remove
            { 
                RemoveHandler(InkCanvas.GestureEvent, value); 
            }
        } 

        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// InkCanvasGestureEventArgs to raise the event with 
        protected virtual void OnGesture(InkCanvasGestureEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null )
            {
                throw new ArgumentNullException("e"); 
            }
 
            RaiseEvent(e); 
        }
 
        /// 
        /// Raised when the InkCanvas.Strokes StrokeCollection has been replaced with another one
        /// 
        public event InkCanvasStrokesReplacedEventHandler StrokesReplaced; 

        ///  
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        ///  
        /// InkCanvasStrokesChangedEventArgs to raise the event with
        protected virtual void OnStrokesReplaced(InkCanvasStrokesReplacedEventArgs e)
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null ) 
            { 
                throw new ArgumentNullException("e");
            } 
            if (null != this.StrokesReplaced)
            {
                StrokesReplaced(this, e);
            } 
        }
 
        ///  
        /// Raised when the InkCanvas.DefaultDrawingAttributes has been replaced with another one
        ///  
        public event DrawingAttributesReplacedEventHandler DefaultDrawingAttributesReplaced;

        /// 
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        ///  
        /// DrawingAttributesReplacedEventArgs to raise the event with 
        protected virtual void OnDefaultDrawingAttributesReplaced(DrawingAttributesReplacedEventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free.

            if (e == null)
            { 
                throw new ArgumentNullException("e");
            } 
            if (null != this.DefaultDrawingAttributesReplaced) 
            {
                DefaultDrawingAttributesReplaced(this, e); 
            }
        }

        ///  
        /// Private helper for raising DDAReplaced.  Invalidates the inking cursor
        ///  
        ///  
        private void RaiseDefaultDrawingAttributeReplaced(DrawingAttributesReplacedEventArgs e)
        { 
            this.OnDefaultDrawingAttributesReplaced(e);

            // Invalidate the inking cursor
            _editingCoordinator.InvalidateBehaviorCursor(_editingCoordinator.InkCollectionBehavior); 
        }
 
        ///  
        ///     Event corresponds to ActiveEditingModeChanged
        ///  
        public static readonly RoutedEvent ActiveEditingModeChangedEvent =
            EventManager.RegisterRoutedEvent("ActiveEditingModeChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InkCanvas));

        ///  
        ///     Add / Remove ActiveEditingModeChanged handler
        ///  
        [Category("Behavior")] 
        public event RoutedEventHandler ActiveEditingModeChanged
        { 
            add
            {
                AddHandler(InkCanvas.ActiveEditingModeChangedEvent, value);
            } 
            remove
            { 
                RemoveHandler(InkCanvas.ActiveEditingModeChangedEvent, value); 
            }
        } 

        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// EventArgs to raise the event with 
        protected virtual void OnActiveEditingModeChanged(RoutedEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if (e == null)
            {
                throw new ArgumentNullException("e"); 
            }
 
            RaiseEvent(e); 
        }
 
        /// 
        /// Private helper that raises ActiveEditingModeChanged
        /// 
        /// EventArgs to raise the event with 
        internal void RaiseActiveEditingModeChanged(RoutedEventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null"); 

            InkCanvasEditingMode mode = this.ActiveEditingMode; 
            if (mode != _editingCoordinator.ActiveEditingMode)
            {
                //change our DP, then raise the event via our protected override
                SetValue(ActiveEditingModePropertyKey, _editingCoordinator.ActiveEditingMode); 

                this.OnActiveEditingModeChanged(e); 
            } 
        }
 


        /// 
        ///     Event corresponds to EditingModeChanged 
        /// 
        public static readonly RoutedEvent EditingModeChangedEvent = 
            EventManager.RegisterRoutedEvent("EditingModeChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InkCanvas)); 

        ///  
        ///     Add / Remove EditingModeChanged handler
        /// 
        [Category("Behavior")]
        public event RoutedEventHandler EditingModeChanged 
        {
            add 
            { 
                AddHandler(InkCanvas.EditingModeChangedEvent, value);
            } 

            remove
            {
                RemoveHandler(InkCanvas.EditingModeChangedEvent, value); 
            }
        } 
 
        /// 
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        /// 
        /// EventArgs to raise the event with
        protected virtual void OnEditingModeChanged(RoutedEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 
 
            if ( e == null )
            { 
                throw new ArgumentNullException("e");
            }

            RaiseEvent(e); 
        }
        ///  
        /// Private helper that raises EditingModeChanged but first 
        /// talks to the InkEditor about it
        ///  
        /// EventArgs to raise the event with
        private void RaiseEditingModeChanged(RoutedEventArgs e)
        {
            Debug.Assert(e != null, "EventArg can not be null"); 

            _editingCoordinator.UpdateEditingState(false /* EditingMode */); 
 
            this.OnEditingModeChanged(e);
        } 

        //note: there is no need for an internal RaiseEditingModeInvertedChanging
        //since this isn't a dynamic property and therefore can not be set
        //outside of this class 

        ///  
        ///     Event corresponds to EditingModeInvertedChanged 
        /// 
        public static readonly RoutedEvent EditingModeInvertedChangedEvent = 
            EventManager.RegisterRoutedEvent("EditingModeInvertedChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InkCanvas));

        /// 
        ///     Add / Remove EditingModeChanged handler 
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler EditingModeInvertedChanged 
        {
            add 
            {
                AddHandler(InkCanvas.EditingModeInvertedChangedEvent, value);
            }
 
            remove
            { 
                RemoveHandler(InkCanvas.EditingModeInvertedChangedEvent, value); 
            }
        } 

        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// EventArgs to raise the event with 
        protected virtual void OnEditingModeInvertedChanged(RoutedEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null )
            {
                throw new ArgumentNullException("e"); 
            }
 
            RaiseEvent(e); 
        }
        ///  
        /// Private helper that raises EditingModeInvertedChanged but first
        /// talks to the InkEditor about it
        /// 
        /// EventArgs to raise the event with 
        private void RaiseEditingModeInvertedChanged(RoutedEventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null"); 

            _editingCoordinator.UpdateEditingState(true /* EditingModeInverted */); 

            this.OnEditingModeInvertedChanged(e);
        }
 
        /// 
        /// Occurs when the user has moved the selection, after they lift their stylus to commit the change. 
        /// This event allows the developer to cancel the move. 
        /// 
        public event  InkCanvasSelectionEditingEventHandler SelectionMoving; 
        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event.
        ///  
        ///  InkCanvasSelectionEditingEventArgs to raise the event with
        protected virtual void OnSelectionMoving( InkCanvasSelectionEditingEventArgs e) 
        { 
            // No need to invoke VerifyAccess since this method is thread free.
 
            if ( e == null )
            {
                throw new ArgumentNullException("e");
            } 
            if (null != SelectionMoving)
            { 
                SelectionMoving(this, e); 
            }
        } 

        /// 
        /// Allows the EditingBehaviors to raise the SelectionMoving event via the protected virtual
        ///  
        ///  InkCanvasSelectionEditingEventArgs to raise the event with
        internal void RaiseSelectionMoving( InkCanvasSelectionEditingEventArgs e) 
        { 
            Debug.Assert(e != null, "EventArg can not be null");
            this.OnSelectionMoving(e); 
        }

        /// 
        /// Occurs when the user has moved the selection, after they lift their stylus to commit the change. 
        /// This event allows the developer to cancel the move.
        ///  
        public event EventHandler SelectionMoved; 
        /// 
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        /// 
        /// EventArgs to raise the event with
        protected virtual void OnSelectionMoved(EventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 
 
            if ( e == null )
            { 
                throw new ArgumentNullException("e");
            }
            if (null != SelectionMoved)
            { 
                SelectionMoved(this, e);
            } 
        } 

        ///  
        /// Allows the EditingBehaviors to raise the SelectionMoved event via the protected virtual
        /// 
        /// EventArgs to raise the event with
        internal void RaiseSelectionMoved(EventArgs e) 
        {
            Debug.Assert(e != null, "EventArg can not be null"); 
 
            this.OnSelectionMoved(e);
            // Update the cursor of SelectionEditor behavior. 
            EditingCoordinator.SelectionEditor.OnInkCanvasSelectionChanged();
        }

        ///  
        /// Occurs when the user has erased Strokes using the erase behavior
        /// 
        /// This event allows the developer to cancel the erase -- therefore, the Stroke should not disappear until 
        /// this event has finished.
        ///  
        public event InkCanvasStrokeErasingEventHandler StrokeErasing;
        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// InkCanvasStrokeErasingEventArgs to raise the event with 
        protected virtual void OnStrokeErasing(InkCanvasStrokeErasingEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null )
            {
                throw new ArgumentNullException("e"); 
            }
            if (null != StrokeErasing) 
            { 
                StrokeErasing(this, e);
            } 
        }

        /// 
        /// Allows the EditingBehaviors to raise the InkErasing event via the protected virtual 
        /// 
        /// InkCanvasStrokeErasingEventArgs to raise the event with 
        internal void RaiseStrokeErasing(InkCanvasStrokeErasingEventArgs e) 
        {
            Debug.Assert(e != null, "EventArg can not be null"); 
            this.OnStrokeErasing(e);
        }

        ///  
        ///     The StrokeErased Routed Event
        ///  
        public static readonly RoutedEvent StrokeErasedEvent = 
            EventManager.RegisterRoutedEvent("StrokeErased", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InkCanvas));
 
        /// 
        ///     Add / Remove EditingModeChanged handler
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler StrokeErased
        { 
            add 
            {
                AddHandler(InkCanvas.StrokeErasedEvent, value); 
            }

            remove
            { 
                RemoveHandler(InkCanvas.StrokeErasedEvent, value);
            } 
        } 

        ///  
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event.
        /// 
        /// EventArgs to raise the event with 
        protected virtual void OnStrokeErased(RoutedEventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null ) 
            {
                throw new ArgumentNullException("e");
            }
            RaiseEvent(e); 
        }
 
        ///  
        /// Allows the EditingBehaviors to raise the InkErasing event via the protected virtual
        ///  
        internal void RaiseInkErased()
        {
            this.OnStrokeErased(
                new RoutedEventArgs(InkCanvas.StrokeErasedEvent, this)); 
        }
 
        ///  
        /// Occurs when the user has resized the selection, after they lift their stylus to commit the change.
        /// This event allows the developer to cancel the resize. 
        /// 
        public event  InkCanvasSelectionEditingEventHandler SelectionResizing;
        /// 
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        ///  
        ///  InkCanvasSelectionEditingEventArgs to raise the event with 
        protected virtual void OnSelectionResizing( InkCanvasSelectionEditingEventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free.

            if ( e == null )
            { 
                throw new ArgumentNullException("e");
            } 
            if (null != SelectionResizing) 
            {
                SelectionResizing(this, e); 
            }
        }

        ///  
        /// Allows the EditingBehaviors to raise the SelectionResizing event via the protected virtual
        ///  
        ///  InkCanvasSelectionEditingEventArgs to raise the event with 
        internal void RaiseSelectionResizing( InkCanvasSelectionEditingEventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null");
            this.OnSelectionResizing(e);
        }
 
        /// 
        /// Occurs when the selection has been resized via UI interaction. 
        ///  
        public event EventHandler SelectionResized;
        ///  
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event.
        /// 
        /// EventArgs to raise the event with 
        protected virtual void OnSelectionResized(EventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null ) 
            {
                throw new ArgumentNullException("e");
            }
            if (null != SelectionResized) 
            {
                SelectionResized(this, e); 
            } 
        }
 
        /// 
        /// Allows the EditingBehaviors to raise the SelectionResized event via the protected virtual
        /// 
        /// EventArgs to raise the event with 
        internal void RaiseSelectionResized(EventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null"); 

            this.OnSelectionResized(e); 
            // Update the cursor of SelectionEditor behavior.
            EditingCoordinator.SelectionEditor.OnInkCanvasSelectionChanged();
        }
 
        /// 
        /// Occurs when the selection has been changed, either using the lasso or programmatically. 
        /// This event allows the developer to cancel the change. 
        /// 
        public event InkCanvasSelectionChangingEventHandler SelectionChanging; 
        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event.
        ///  
        /// InkCanvasSelectionChangingEventArgs to raise the event with
        protected virtual void OnSelectionChanging(InkCanvasSelectionChangingEventArgs e) 
        { 
            // No need to invoke VerifyAccess since this method is thread free.
 
            if ( e == null )
            {
                throw new ArgumentNullException("e");
            } 
            if (null != SelectionChanging)
            { 
                SelectionChanging(this, e); 
            }
        } 

        /// 
        /// Allows the EditingBehaviors to raise the SelectionChanging event via the protected virtual
        ///  
        /// InkCanvasSelectionChangingEventArgs to raise the event with
        private void RaiseSelectionChanging(InkCanvasSelectionChangingEventArgs e) 
        { 
            Debug.Assert(e != null, "EventArg can not be null");
            this.OnSelectionChanging(e); 
        }

        /// 
        /// Occurs when the selection has been changed 
        /// 
        public event EventHandler SelectionChanged; 
        ///  
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// EventArgs to raise the event with
        protected virtual void OnSelectionChanged(EventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free.
 
            if ( e == null ) 
            {
                throw new ArgumentNullException("e"); 
            }
            if (null != SelectionChanged)
            {
                SelectionChanged(this, e); 
            }
        } 
 
        /// 
        /// Allows the EditingBehaviors to raise the SelectionChanged event via the protected virtual 
        /// 
        /// EventArgs to raise the event with
        internal void RaiseSelectionChanged(EventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null");
 
            this.OnSelectionChanged(e); 
            // Update the cursor of SelectionEditor behavior.
            EditingCoordinator.SelectionEditor.OnInkCanvasSelectionChanged(); 
        }

        /// 
        /// The InkCanvas uses an inner Canvas to host children.  When the inner Canvas's children 
        /// are changed, we need to call the protected virtual OnVisualChildrenChanged on the InkCanvas
        /// so that subclasses can be notified 
        ///  
        internal void RaiseOnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
        { 
            this.OnVisualChildrenChanged(visualAdded, visualRemoved);
        }

        #endregion Public Events 

        #region Public Methods 
 
        /// 
        /// Returns the enabled gestures.  This method throws an exception if GestureRecognizerAvailable 
        /// is false
        /// 
        /// 
        public ReadOnlyCollection GetEnabledGestures() 
        {
            // No need to invoke VerifyAccess since it's checked in GestureRecognizer.GetEnabledGestures. 
 
            //gestureRecognizer throws appropriately if there is no gesture recognizer available
            return new ReadOnlyCollection(this.GestureRecognizer.GetEnabledGestures()); 
        }

        /// 
        /// Sets the enabled gestures.  This method throws an exception if GestureRecognizerAvailable 
        /// is false
        ///  
        ///  
        public void SetEnabledGestures(IEnumerable applicationGestures)
        { 
            // No need to invoke VerifyAccess since it's checked in GestureRecognizer.GetEnabledGestures.

            //gestureRecognizer throws appropriately if there is no gesture recognizer available
            this.GestureRecognizer.SetEnabledGestures(applicationGestures); 
        }
 
        ///  
        /// Get the selection bounds.
        ///  
        /// 
        public Rect GetSelectionBounds()
        {
            VerifyAccess(); 

            return InkCanvasSelection.SelectionBounds; 
        } 

        ///  
        /// provides access to the currently selected elements which are children of this InkCanvas
        /// 
        public ReadOnlyCollection GetSelectedElements()
        { 
            VerifyAccess();
            return InkCanvasSelection.SelectedElements; 
        } 

        ///  
        /// provides read access to the currently selected strokes
        /// 
        public StrokeCollection GetSelectedStrokes()
        { 
            VerifyAccess();
 
            StrokeCollection sc = new StrokeCollection(); 
            sc.Add(InkCanvasSelection.SelectedStrokes);
            return sc; 
        }

        /// 
        /// Overload which calls the more complex version, passing null for selectedElements 
        /// 
        /// The strokes to select 
        public void Select(StrokeCollection selectedStrokes) 
        {
            // No need to invoke VerifyAccess since this call is forwarded. 
            Select(selectedStrokes, null);
        }

        ///  
        /// Overload which calls the more complex version, passing null for selectedStrokes
        ///  
        /// The elements to select 
        public void Select(IEnumerable selectedElements)
        { 
            // No need to invoke VerifyAccess since this call is forwarded.
            Select(null, selectedElements);
        }
 
        /// 
        /// Overload which calls the more complex version, passing null for selectedStrokes 
        ///  
        /// The strokes to select
        /// The elements to select 
        public void Select(StrokeCollection selectedStrokes, IEnumerable selectedElements)
        {
            VerifyAccess();
 
            // NTRAID-WINDOWS#1134932-2005/12/01-WAYNEZEN
            // Try to switch to Select mode first. If we fail to change the mode, then just simply no-op. 
            if ( EnsureActiveEditingMode(InkCanvasEditingMode.Select) ) 
            {
                // 
                // validate
                //
                UIElement[] validElements = ValidateSelectedElements(selectedElements);
                StrokeCollection validStrokes = ValidateSelectedStrokes(selectedStrokes); 

                // 
                // this will raise the 'SelectionChanging' event ONLY if the selection 
                // is actually different
                // 
                ChangeInkCanvasSelection(validStrokes, validElements);
            }
        }
 
        /// 
        /// Hit test on the selection 
        ///  
        /// 
        ///  
        public InkCanvasSelectionHitResult HitTestSelection(Point point)
        {
            VerifyAccess();
 
            // Ensure the visual tree.
            if ( _localAdornerDecorator == null ) 
            { 
                ApplyTemplate();
            } 

            return InkCanvasSelection.HitTestSelection(point);
        }
 
        /// 
        /// Copy the current selection in the InkCanvas to the clipboard 
        ///  
        public void CopySelection()
        { 
            VerifyAccess();
            PrivateCopySelection();
        }
 
        /// 
        /// Copy the current selection in the InkCanvas to the clipboard and then delete it 
        ///  
        public void CutSelection()
        { 
            VerifyAccess();

            // Copy first
            InkCanvasClipboardDataFormats copiedDataFormats = PrivateCopySelection(); 

            // Don't even bother if we don't have a selection. 
            if ( copiedDataFormats != InkCanvasClipboardDataFormats.None ) 
            {
                // Then delete the current selection. Note the XAML format won't be avaliable under Partial 
                // Trust. So, the selected element shouldn't be copied or removed.
                DeleteCurrentSelection(
                    /* We want to delete the selected Strokes if there is ISF and/or XAML data being copied */
                    (copiedDataFormats & 
                        (InkCanvasClipboardDataFormats.ISF | InkCanvasClipboardDataFormats.XAML)) != 0,
                    /* We only want to delete the selected elements if there is XAML data being copied */ 
                    (copiedDataFormats & InkCanvasClipboardDataFormats.XAML) != 0); 
            }
        } 

        /// 
        /// Paste the contents of the clipboard into the InkCanvas
        ///  
        public void Paste()
        { 
            // No need to call VerifyAccess since this call is forwarded. 

            // We always paste the data to the default location which is (0,0). 
            Paste(new Point(c_pasteDefaultLocation, c_pasteDefaultLocation));
        }

        ///  
        /// Paste the contents of the clipboard to the specified location in the InkCanvas
        ///  
        public void Paste(Point point) 
        {
            VerifyAccess(); 

            if (DoubleUtil.IsNaN(point.X) ||
                DoubleUtil.IsNaN(point.Y) ||
                Double.IsInfinity(point.X)|| 
                Double.IsInfinity(point.Y) )
            { 
                    throw new ArgumentException(SR.Get(SRID.InvalidPoint), "point"); 
            }
 

            //
            // only do this if the user is not editing (input active)
            // or we will violate a dispatcher lock 
            //
            if (!_editingCoordinator.UserIsEditing) 
            { 
                IDataObject dataObj = null;
                try 
                {
                    dataObj = Clipboard.GetDataObject();
                }
                catch (ExternalException) 
                {
                    //harden against ExternalException 
                    return; 
                }
                if (dataObj != null) 
                {
                    PasteFromDataObject(dataObj, point);
                }
            } 
        }
 
        ///  
        /// Return true if clipboard contents can be pasted into the InkCanvas.
        ///  
        public bool CanPaste()
        {
            VerifyAccess();
 
            bool ret = false;
            // 
            // can't paste if the user is editing (input active) 
            // or we will violate a dispatcher lock
            // 
            if (_editingCoordinator.UserIsEditing)
            {
                return false;
            } 

            // Check whether the caller has the clipboard permission. 
            if ( !SecurityHelper.CallerHasAllClipboardPermission() ) 
            {
                return false; 
            }

            ret = PrivateCanPaste();
 
            return ret;
        } 
 
        #endregion Public Methods
 
        //-----------------------------------------------------
        //
        //  IAddChild Interface
        // 
        //-----------------------------------------------------
 
        #region IAddChild Interface 

        /// 
        /// Called to Add the object as a Child.
        ///
        ///
        /// Object to add as a child 
        ///
        void IAddChild.AddChild(Object value) 
        { 
            //             VerifyAccess();
 
            if ( value == null )
            {
                throw new ArgumentNullException("value");
            } 

            ( (IAddChild)InnerCanvas ).AddChild(value); 
        } 

        /// 
        /// Called when text appears under the tag in markup.
        ///
        ///
        /// Text to Add to the Canvas 
        ///
        void IAddChild.AddText(string textData) 
        { 
            //             VerifyAccess();
 
            ( (IAddChild)InnerCanvas ).AddText(textData);
        }

        #endregion IAddChild Interface 

        //------------------------------------------------------ 
        // 
        //  Protected Properties
        // 
        //-----------------------------------------------------

        #region Protected Properties
 
        /// 
        /// Returns enumerator to logical children. 
        ///  
        protected internal override IEnumerator LogicalChildren
        { 
            get
            {
                //        VerifyAccess( );
 
                // Return the private logical children of the InnerCanvas
                return ( (InkCanvasInnerCanvas)InnerCanvas).PrivateLogicalChildren; 
            } 
        }
 
        /// 
        /// Protected DynamicRenderer property.
        /// 
        protected DynamicRenderer DynamicRenderer 
        {
            get 
            { 
                VerifyAccess();
                return InternalDynamicRenderer; 
            }
            set
            {
                VerifyAccess(); 
                if (!object.ReferenceEquals(value, _dynamicRenderer))
                { 
                    int previousIndex = -1; 
                    //remove the existing plugin
                    if (_dynamicRenderer != null) 
                    {
                        //remove the plugin from the collection
                        previousIndex = this.StylusPlugIns.IndexOf(_dynamicRenderer);
                        if (-1 != previousIndex) 
                        {
                            this.StylusPlugIns.RemoveAt(previousIndex); 
                        } 

                        //remove the plugin's visual from the InkPresenter 
                        if (this.InkPresenter.ContainsAttachedVisual(_dynamicRenderer.RootVisual))
                        {
                            this.InkPresenter.DetachVisuals(_dynamicRenderer.RootVisual);
                        } 
                    }
 
                    _dynamicRenderer = value; 

                    if (_dynamicRenderer != null) //null is acceptable 
                    {
                        //remove the plugin from the collection
                        if (!this.StylusPlugIns.Contains(_dynamicRenderer))
                        { 
                            if (-1 != previousIndex)
                            { 
                                //insert the new DR in the same location as the old one 
                                this.StylusPlugIns.Insert(previousIndex, _dynamicRenderer);
                            } 
                            else
                            {
                                this.StylusPlugIns.Add(_dynamicRenderer);
                            } 
                        }
 
                        //refer to the same DrawingAttributes as the InkCanvas 
                        _dynamicRenderer.DrawingAttributes = this.DefaultDrawingAttributes;
 
                        //attach the DynamicRenderer if it is not already
                        if (!(this.InkPresenter.ContainsAttachedVisual(_dynamicRenderer.RootVisual)) &&
                            _dynamicRenderer.Enabled &&
                            _dynamicRenderer.RootVisual != null) 
                        {
                            this.InkPresenter.AttachVisuals(_dynamicRenderer.RootVisual, this.DefaultDrawingAttributes); 
                        } 
                    }
                } 
            }
        }

        ///  
        /// Protected read only access to the InkPresenter this InkCanvas uses
        ///  
        protected InkPresenter InkPresenter 
        {
            get 
            {
                VerifyAccess();
                if ( _inkPresenter == null )
                { 
                    _inkPresenter = new InkPresenter();
 
                    // Bind the InkPresenter.Strokes to InkCanvas.Strokes 
                    Binding strokes = new Binding();
                    strokes.Path = new PropertyPath(InkCanvas.StrokesProperty); 
                    strokes.Mode = BindingMode.OneWay;
                    strokes.Source = this;
                    _inkPresenter.SetBinding(InkPresenter.StrokesProperty, strokes);
 
                }
                return _inkPresenter; 
            } 
        }
 
        #endregion Protected Properties

        #region Internal Properties / Methods
 

        ///  
        /// Deselect the current selection 
        /// 
        internal static readonly RoutedCommand DeselectCommand = new RoutedCommand("Deselect", typeof(InkCanvas)); 

        /// 
        /// UserInitiatedCanPaste
        ///  
        /// 
        ///  
        ///     Critical -      Elevates the AllClipboard permission for checking the supported data in InkCanvas. 
        /// 
        [SecurityCritical] 
        private bool UserInitiatedCanPaste()
        {
            ( new UIPermission(UIPermissionClipboard.AllClipboard) ).Assert();//BlessedAssert
            try 
            {
                return PrivateCanPaste(); 
            } 
            finally
            { 
                UIPermission.RevertAssert();
            }

        } 

        ///  
        /// PrivateCanPaste 
        /// 
        ///  
        private bool PrivateCanPaste()
        {
            bool canPaste = false;
            IDataObject dataObj = null; 
            try
            { 
                dataObj = Clipboard.GetDataObject(); 
            }
            catch (ExternalException) 
            {
                //harden against ExternalException
                return false;
            } 
            if ( dataObj != null )
            { 
                canPaste = ClipboardProcessor.CheckDataFormats(dataObj); 
            }
 
            return canPaste;
        }

        ///  
        /// This method pastes data from an IDataObject object
        ///  
        internal void PasteFromDataObject(IDataObject dataObj, Point point) 
        {
            // Reset the current selection 
            ClearSelection(false);

            // Assume that there is nothing to be selected.
            StrokeCollection newStrokes = new StrokeCollection(); 
            List newElements = new List();
 
            // Paste the data from the data object. 
            if ( !ClipboardProcessor.PasteData(dataObj, ref newStrokes, ref newElements) )
            { 
                // Paste was failed.
                return;
            }
            else if ( newStrokes.Count == 0 && newElements.Count == 0 ) 
            {
                // Nothing has been received from the clipboard. 
                return; 
            }
 
            // We add elements here. Then we have to wait for the layout update.
            UIElementCollection children = Children;
            foreach ( UIElement element in newElements )
            { 
                children.Add(element);
            } 
 
            if ( newStrokes != null )
            { 
                Strokes.Add(newStrokes);
            }

            try 
            {
                // We should fire SelectionChanged event if the current editing mode is Select. 
                CoreChangeSelection(newStrokes, newElements.ToArray(), EditingMode == InkCanvasEditingMode.Select); 
            }
            finally 
            {
                // Now move the selection to the desired location.
                Rect bounds = GetSelectionBounds( );
                InkCanvasSelection.CommitChanges(Rect.Offset(bounds, -bounds.Left + point.X, -bounds.Top + point.Y), false); 

                if (EditingMode != InkCanvasEditingMode.Select) 
                { 
                    // Clear the selection without the event if the editing mode is not Select.
                    ClearSelection(false); 
                }
            }
        }
 
        /// 
        /// Copies the InkCanvas contents to a DataObject and returns it to the caller. 
        ///  Can return NULL for DataObject. 
        /// 
        ///  
        ///     Critical: Clipboard.SetDataObject will invoke DataObject.DataStore.GetFormats.
        ///                 The methods demands SerializationPermission. We perform the elevation before
        ///                 calling SetDataObject.
        ///     TreatAsSafe: There is no input here. The ISF data are safe to being put in the clipboard. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private InkCanvasClipboardDataFormats CopyToDataObject() 
        {
             DataObject dataObj; 
            (new UIPermission(UIPermissionClipboard.AllClipboard)).Assert();//BlessedAssert
            try
            {
                dataObj = new DataObject(); 
            }
            finally 
            { 
                UIPermission.RevertAssert();
            } 
            InkCanvasClipboardDataFormats copiedDataFormats = InkCanvasClipboardDataFormats.None;

            // Try to copy the data from the InkCanvas to the clipboard.
            copiedDataFormats = ClipboardProcessor.CopySelectedData(dataObj); 

            if ( copiedDataFormats != InkCanvasClipboardDataFormats.None ) 
            { 
                PermissionSet ps = new PermissionSet(PermissionState.None);
                ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter)); 
                ps.AddPermission(new UIPermission(UIPermissionClipboard.AllClipboard));
                ps.Assert(); // BlessedAssert
                try
                { 
                    // Put our data object into the clipboard.
                    Clipboard.SetDataObject(dataObj, true); 
                } 
                finally
                { 
                    SecurityPermission.RevertAssert();
                }
            }
 
            return copiedDataFormats;
        } 
 
        /// 
        /// Read-only property of the associated EditingCoordinator. 
        /// 
        internal EditingCoordinator EditingCoordinator
        {
            get 
            {
                return _editingCoordinator; 
            } 
        }
 
        /// 
        /// Internal access to the protected DynamicRenderer.  Can be null.
        /// 
        internal DynamicRenderer InternalDynamicRenderer 
        {
            get 
            { 
                return _dynamicRenderer;
            } 
        }

        /// 
        /// Return the inner Canvas. 
        /// 
        internal InkCanvasInnerCanvas InnerCanvas 
        { 
            get
            { 
                // We have to create our visual at this point.
                if (_innerCanvas == null)
                {
                    // Create our InnerCanvas to change the logical parent of Canvas' children. 
                    _innerCanvas = new InkCanvasInnerCanvas(this);
 
                    // Bind the inner Canvas' Background to InkCanvas' Background 
                    Binding background = new Binding();
                    background.Path = new PropertyPath(InkCanvas.BackgroundProperty); 
                    background.Mode = BindingMode.OneWay;
                    background.Source = this;
                    _innerCanvas.SetBinding(Panel.BackgroundProperty, background);
                } 

                return _innerCanvas; 
            } 
        }
 
        /// 
        /// Internal access to the current selection
        /// 
        internal InkCanvasSelection InkCanvasSelection 
        {
            get 
            { 
                if ( _selection == null )
                { 
                    _selection = new InkCanvasSelection(this);
                }

                return _selection; 
            }
        } 
 

        ///  
        /// Internal helper called by the LassoSelectionBehavior
        /// 
        internal void BeginDynamicSelection(Visual visual)
        { 
            EditingCoordinator.DebugCheckActiveBehavior(EditingCoordinator.LassoSelectionBehavior);
 
            _dynamicallySelectedStrokes = new StrokeCollection(); 

            InkPresenter.AttachVisuals(visual, new DrawingAttributes()); 
        }

        /// 
        /// Internal helper called by LassoSelectionBehavior to update the display 
        /// of dynamically added strokes
        ///  
        internal void UpdateDynamicSelection(   StrokeCollection strokesToDynamicallySelect, 
                                                StrokeCollection strokesToDynamicallyUnselect)
        { 
            EditingCoordinator.DebugCheckActiveBehavior(EditingCoordinator.LassoSelectionBehavior);

            //
            // update our internal stroke collections used by dynamic selection 
            //
            if (strokesToDynamicallySelect != null) 
            { 
                foreach (Stroke s in strokesToDynamicallySelect)
                { 
                    _dynamicallySelectedStrokes.Add(s);
                    s.IsSelected = true;
                }
            } 

            if (strokesToDynamicallyUnselect != null) 
            { 
                foreach (Stroke s in strokesToDynamicallyUnselect)
                { 
                    System.Diagnostics.Debug.Assert(_dynamicallySelectedStrokes.Contains(s));
                    _dynamicallySelectedStrokes.Remove(s);
                    s.IsSelected = false;
                } 
            }
        } 
 
        /// 
        /// Internal helper used by LassoSelectionBehavior 
        /// 
        internal StrokeCollection EndDynamicSelection(Visual visual)
        {
            EditingCoordinator.DebugCheckActiveBehavior(EditingCoordinator.LassoSelectionBehavior); 

            InkPresenter.DetachVisuals(visual); 
 
            StrokeCollection selectedStrokes = _dynamicallySelectedStrokes;
            _dynamicallySelectedStrokes = null; 

            return selectedStrokes;
        }
 
        /// 
        /// Clears the selection in the ink canvas 
        /// and returns a bool indicating if the selection was actually cleared 
        /// (developers can cancel selectionchanging)
        /// 
        /// If the InkCanvas has no selection, selectionchanging is not raised
        /// and this method returns true
        ///
        /// used by InkEditor during editing operations 
        /// 
        /// true if selection was cleared even after raising selectionchanging 
        internal bool ClearSelectionRaiseSelectionChanging() 
        {
            if ( !InkCanvasSelection.HasSelection ) 
            {
                return true;
            }
 
            //
            // attempt to clear selection 
            // 
            ChangeInkCanvasSelection(new StrokeCollection(), new UIElement[]{});
 
            return !InkCanvasSelection.HasSelection;
        }

        ///  
        /// ClearSelection
        ///     Called by: 
        ///         PasteFromDataObject 
        ///         EditingCoordinator.UpdateEditingState
        ///  
        internal void ClearSelection(bool raiseSelectionChangedEvent)
        {
            if ( InkCanvasSelection.HasSelection )
            { 
                // Reset the current selection
                CoreChangeSelection(new StrokeCollection(), new UIElement[] { }, raiseSelectionChangedEvent); 
            } 
        }
 

        /// 
        /// Helper that creates selection for an InkCanvas.  Used by the SelectedStrokes and
        /// SelectedElements properties 
        /// 
        internal void ChangeInkCanvasSelection(StrokeCollection strokes, UIElement[] elements) 
        { 
            //validate in debug only for this internal static
            Debug.Assert(strokes != null 
                        && elements != null,
                        "Invalid arguments in ChangeInkCanvasSelection");

            bool strokesAreDifferent; 
            bool elementsAreDifferent;
            InkCanvasSelection.SelectionIsDifferentThanCurrent(strokes, out strokesAreDifferent, elements, out elementsAreDifferent); 
            if ( strokesAreDifferent || elementsAreDifferent ) 
            {
                InkCanvasSelectionChangingEventArgs args = new InkCanvasSelectionChangingEventArgs(strokes, elements); 

                StrokeCollection validStrokes = strokes;
                UIElement[] validElements = elements;
 
                this.RaiseSelectionChanging(args);
 
                //now that the event has been raised and all of the delegates 
                //have had their way with it, process the result
                if ( !args.Cancel ) 
                {

                    //
                    // rock and roll, time to validate our arguments 
                    // note: these event args are visible outside the apis,
                    // so we need to validate them again 
                    // 

                    // PERF-2006/05/02-WAYNEZEN, 
                    // Check our internal flag. If the SelectedStrokes has been changed, we shouldn't do any extra work here.
                    if ( args.StrokesChanged )
                    {
                        validStrokes = ValidateSelectedStrokes(args.GetSelectedStrokes()); 
                        int countOldSelectedStrokes = strokes.Count;
                        for ( int i = 0; i < countOldSelectedStrokes; i++ ) 
                        { 
                            // PERF-2006/05/02-WAYNEZEN,
                            // We only have to reset IsSelected for the elements no longer exists in the new collection. 
                            if ( !validStrokes.Contains(strokes[i]) )
                            {
                                // NTRAID#WINDOWS-1045099-2006/05/02-waynezen,
                                // Make sure we reset the IsSelected property which could have been 
                                // set to true in the dynamic selection.
                                strokes[i].IsSelected = false; 
                            } 
                        }
                    } 


                    // PERF-2006/05/02-WAYNEZEN,
                    // Check our internal flag. If the SelectedElements has been changed, we shouldn't do any extra work here. 
                    if ( args.ElementsChanged )
                    { 
                        validElements = ValidateSelectedElements(args.GetSelectedElements()); 
                    }
 
                    CoreChangeSelection(validStrokes, validElements, true);
                }
                else
                { 
                    StrokeCollection currentSelectedStrokes = InkCanvasSelection.SelectedStrokes;
                    int countOldSelectedStrokes = strokes.Count; 
                    for ( int i = 0; i < countOldSelectedStrokes; i++ ) 
                    {
                        // Make sure we reset the IsSelected property which could have been 
                        // set to true in the dynamic selection but not being selected previously.
                        if ( !currentSelectedStrokes.Contains(strokes[i]) )
                        {
                            strokes[i].IsSelected = false; 
                        }
                    } 
                } 
            }
        } 


        /// 
        /// Helper method used by ChangeInkCanvasSelection and directly by ClearSelectionWithoutSelectionChanging 
        /// 
        /// validStrokes 
        /// validElements 
        /// raiseSelectionChanged
        private void CoreChangeSelection(StrokeCollection validStrokes, IList validElements, bool raiseSelectionChanged) 
        {
            InkCanvasSelection.Select(validStrokes, validElements, raiseSelectionChanged);
        }
 
#if DEBUG_LASSO_FEEDBACK
        internal ContainerVisual RendererRootContainer 
        { 
            get {return _inkContainerVisual;}
        } 
#endif


        ///  
        /// Private helper method used to retrieve a StrokeCollection which does AND operation on two input collections.
        ///  
        /// The possible subset 
        /// The container set
        /// True if subset is a subset of superset, false otherwise 
        internal static StrokeCollection GetValidStrokes(StrokeCollection subset, StrokeCollection superset)
        {
            StrokeCollection validStrokes = new StrokeCollection();
 
            int subsetCount = subset.Count;
 
            // special case an empty subset as a guaranteed subset 
            if ( subsetCount == 0 )
            { 
                return validStrokes;
            }

            for ( int i = 0; i < subsetCount; i++ ) 
            {
                Stroke stroke = subset[i]; 
                if ( superset.Contains(stroke) ) 
                {
                    validStrokes.Add(stroke); 
                }
            }

            return validStrokes; 
        }
 
        ///  
        /// Register the commanding handlers for the clipboard operations
        ///  
        /// 
        ///     Critical: Elevates to associate a protected command (paste) with keyboard
        ///     TreatAsSafe: We don't take user input here. Shift+Insert is the correct key binding,
        ///                  and therefore is expected by the user. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private static void _RegisterClipboardHandlers() 
        {
            Type ownerType = typeof(InkCanvas); 

            CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.Cut,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled),
                SRID.KeyShiftDelete, SRID.KeyShiftDeleteDisplayString); 
            CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.Copy,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled), 
                SRID.KeyCtrlInsert, SRID.KeyCtrlInsertDisplayString); 

            // Use temp variables to reduce code under elevation 
            ExecutedRoutedEventHandler pasteExecuteEventHandler = new ExecutedRoutedEventHandler(_OnCommandExecuted);
            CanExecuteRoutedEventHandler pasteQueryEnabledEventHandler = new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled);
            InputGesture pasteInputGesture = KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyShiftInsert), SR.Get(SRID.KeyShiftInsertDisplayString));
 
            new UIPermission(UIPermissionClipboard.AllClipboard).Assert(); // BlessedAssert:
            try 
            { 
                CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.Paste,
                    pasteExecuteEventHandler, pasteQueryEnabledEventHandler, pasteInputGesture); 
            }
            finally
            {
                CodeAccessPermission.RevertAssert(); 
            }
        } 
 
        /// 
        /// Private helper used to ensure that any stroke collection 
        /// passed to the InkCanvas is valid.  Throws exceptions if the argument is invalid
        /// 
        private StrokeCollection ValidateSelectedStrokes(StrokeCollection strokes)
        { 
            //
            //  null is a valid input 
            // 
            if (strokes == null)
            { 
                return new StrokeCollection();
            }
            else
            { 
                return GetValidStrokes(strokes, this.Strokes);
            } 
        } 

        ///  
        /// Private helper used to ensure that a UIElement argument passed in
        /// is valid.
        /// 
        private UIElement[] ValidateSelectedElements(IEnumerable selectedElements) 
        {
            if (selectedElements == null) 
            { 
                return new UIElement[]{};
            } 

            List elements = new List();
            foreach (UIElement element in selectedElements)
            { 
                // NTRAID:WINDOWSOS#1621480-2006/04/26-WAYNEZEN,
                // Don't add the duplicated element. 
                if ( !elements.Contains(element) ) 
                {
                    // 
                    // check the common case first, e
                    //
                    if ( InkCanvasIsAncestorOf(element) )
                    { 
                        elements.Add(element);
                    } 
                } 
            }
 
            return elements.ToArray();
        }

        ///  
        /// Helper method used by DesignActivation to see if an element
        /// has this InkCanvas as an Ancestor 
        ///  
        private bool InkCanvasIsAncestorOf(UIElement element)
        { 
            if (this != element && this.IsAncestorOf(element))
            {
                return true;
            } 
            return false;
        } 
 
        /// 
        /// Handler called whenever changes are made to properties of the DefaultDrawingAttributes 
        /// 
        /// 
        /// 
        /// For example, when a developer changes the Color property on the DefaultDrawingAttributes, 
        /// this event will fire - allowing the InkCanvas a chance to notify the BasicRTI Service.
        /// Also - we do not currently call through the DefaultDrawingAttributes setter since 
        /// parameter validation in the setter may detect if the reference isn't changing, and ignore 
        /// the call. Also - there is no need for extra parameter validation.
        private void DefaultDrawingAttributes_Changed(object sender, PropertyDataChangedEventArgs args) 
        {
            // note that sender should be the same as _defaultDrawingAttributes
            // If a developer writes code to change the DefaultDrawingAttributes inside of the event
            //      handler before the InkCanvas receives the notification (multi-cast delegate scenario) - 
            //      The DefaultDrawingAttributes should still be updated, and in that case we would
            //      update the RTI DAC twice. Typically, however, this will just refresh the 
            //      attributes in the RTI thread. 
            System.Diagnostics.Debug.Assert(object.ReferenceEquals(sender, DefaultDrawingAttributes));
 
            InvalidateSubProperty(DefaultDrawingAttributesProperty);

            // Be sure to update the RealTimeInking PlugIn with the drawing attribute changes.
            UpdateDynamicRenderer(); 

            // Invalidate the inking cursor 
            _editingCoordinator.InvalidateBehaviorCursor(_editingCoordinator.InkCollectionBehavior); 
        }
 
        /// 
        /// Helper method used to set up the DynamicRenderer.
        /// 
        internal void UpdateDynamicRenderer() 
        {
            UpdateDynamicRenderer(DefaultDrawingAttributes); 
        } 
        /// 
        /// Helper method used to set up the DynamicRenderer. 
        /// 
        private void UpdateDynamicRenderer(DrawingAttributes newDrawingAttributes)
        {
            ApplyTemplate(); 

            if (this.DynamicRenderer != null) 
            { 
                this.DynamicRenderer.DrawingAttributes = newDrawingAttributes;
 
                if (!this.InkPresenter.AttachedVisualIsPositionedCorrectly(this.DynamicRenderer.RootVisual, newDrawingAttributes))
                {
                    if (this.InkPresenter.ContainsAttachedVisual(this.DynamicRenderer.RootVisual))
                    { 
                        this.InkPresenter.DetachVisuals(this.DynamicRenderer.RootVisual);
                    } 
 
                    // Only hook up if we are enabled.  As we change editing modes this routine will be called
                    // to clean up things. 
                    if (this.DynamicRenderer.Enabled && this.DynamicRenderer.RootVisual != null)
                    {
                        this.InkPresenter.AttachVisuals(this.DynamicRenderer.RootVisual, newDrawingAttributes);
                    } 
                }
            } 
        } 

        private bool EnsureActiveEditingMode(InkCanvasEditingMode newEditingMode) 
        {
            bool ret = true;

            if ( ActiveEditingMode != newEditingMode ) 
            {
                if ( EditingCoordinator.IsStylusInverted ) 
                { 
                    EditingModeInverted = newEditingMode;
                } 
                else
                {
                    EditingMode = newEditingMode;
                } 

                // Verify whether user has cancelled the change in EditingModeChanging event. 
                ret = ( ActiveEditingMode == newEditingMode ); 
            }
 
            return ret;
        }

        // The ClipboardProcessor instance which deals with the operations relevant to the clipboard. 
        private ClipboardProcessor ClipboardProcessor
        { 
            get 
            {
                if ( _clipboardProcessor == null ) 
                {
                    _clipboardProcessor = new ClipboardProcessor(this);
                }
 
                return _clipboardProcessor;
            } 
        } 

        //lazy instance the gesture recognizer 
        private GestureRecognizer GestureRecognizer
        {
            get
            { 
                if (_gestureRecognizer == null)
                { 
                    _gestureRecognizer = new GestureRecognizer(); 
                }
                return _gestureRecognizer; 
            }
        }

        ///  
        /// Delete the current selection
        ///  
        private void DeleteCurrentSelection(bool removeSelectedStrokes, bool removeSelectedElements) 
        {
            Debug.Assert(removeSelectedStrokes || removeSelectedElements, "At least either Strokes or Elements should be removed!"); 

            // Now delete the current selection.
            StrokeCollection strokes = GetSelectedStrokes();
            IList elements = GetSelectedElements(); 

            // Clear the selection first. 
            CoreChangeSelection( 
                removeSelectedStrokes ? new StrokeCollection() : strokes,
                removeSelectedElements ? new List() : elements, 
                true);

            // Remove the ink.
            if ( removeSelectedStrokes && strokes != null && strokes.Count != 0 ) 
            {
                Strokes.Remove(strokes); 
            } 

            // Remove the elements. 
            if ( removeSelectedElements )
            {
                UIElementCollection children = Children;
                foreach ( UIElement element in elements ) 
                {
                    children.Remove(element); 
                } 
            }
        } 

        /// 
        /// A class handler of the Commands
        ///  
        /// 
        ///  
        private static void _OnCommandExecuted(object sender, ExecutedRoutedEventArgs args) 
        {
            ICommand command = args.Command; 
            InkCanvas inkCanvas = sender as InkCanvas;

            Debug.Assert(inkCanvas != null);
 
            if ( inkCanvas.IsEnabled && !inkCanvas.EditingCoordinator.UserIsEditing )
            { 
                if ( command == ApplicationCommands.Delete ) 
                {
                    inkCanvas.DeleteCurrentSelection(true, true); 
                }
                else if ( command == ApplicationCommands.Cut )
                {
                    inkCanvas.CutSelection(); 
                }
                else if ( command == ApplicationCommands.Copy ) 
                { 
                    inkCanvas.CopySelection();
                } 
                else if ( command == ApplicationCommands.SelectAll )
                {
                    if ( inkCanvas.ActiveEditingMode == InkCanvasEditingMode.Select )
                    { 
                        IEnumerable children = null;
                        UIElementCollection uiElementCollection = inkCanvas.Children; 
                        if ( uiElementCollection.Count > 0 ) 
                        {
                            //UIElementCollection doesn't implement IEnumerable 
                            //for some reason
                            UIElement[] uiElementArray = new UIElement[uiElementCollection.Count];
                            for ( int i = 0; i < uiElementCollection.Count; i++ )
                            { 
                                uiElementArray[i] = uiElementCollection[i];
                            } 
                            children = uiElementArray; 
                        }
                        inkCanvas.Select(inkCanvas.Strokes, children); 
                    }
                }
                else if ( command == ApplicationCommands.Paste )
                { 
                    try
                    { 
                        inkCanvas.Paste(); 
                    }
                    // Eat it and do nothing if one of the following exceptions is caught. 
                    catch ( System.Runtime.InteropServices.COMException )
                    {
                        // The window may be destroyed which could cause the opening failed..
                    } 
                    catch ( XamlParseException )
                    { 
                        // The Xaml parser fails 
                    }
                    catch ( ArgumentException ) 
                    {
                        // The ISF decoder fails
                    }
                } 
                else if ( command == InkCanvas.DeselectCommand )
                { 
                    inkCanvas.ClearSelectionRaiseSelectionChanging(); 
                }
            } 
        }

        /// 
        /// A class handler for querying the enabled status of the commands. 
        /// 
        ///  
        ///  
        /// 
        ///     Critical -      Call into UserInitiatedCanPaste which is SecurityCritical. 
        ///     TreatAsSafe -   We check whether QueryCanPaste is initiated by user or not
        ///                     before invoking the critical method.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private static void _OnQueryCommandEnabled(object sender, CanExecuteRoutedEventArgs args)
        { 
            RoutedCommand command = (RoutedCommand)(args.Command); 
            InkCanvas inkCanvas = sender as InkCanvas;
 
            Debug.Assert(inkCanvas != null);

            if ( inkCanvas.IsEnabled
                // NTRAID-WINDOWSOS#1578484-2006/04/14-WAYNEZEN, 
                // If user is editing, we should disable all commands.
                && !inkCanvas.EditingCoordinator.UserIsEditing ) 
            { 
                if ( command == ApplicationCommands.Delete
                    || command == ApplicationCommands.Cut 
                    || command == ApplicationCommands.Copy
                    || command == InkCanvas.DeselectCommand )
                {
                    args.CanExecute = inkCanvas.InkCanvasSelection.HasSelection; 
                }
                else if ( command == ApplicationCommands.Paste ) 
                { 
                    try
                    { 
                        args.CanExecute = args.UserInitiated
                                            ? inkCanvas.UserInitiatedCanPaste() /* Call UserInitiatedCanPaste when the query is initiated by user */
                                            : inkCanvas.CanPaste() /* Call the public CanPaste if not */;
                    } 
                    catch ( System.Runtime.InteropServices.COMException )
                    { 
                        // The window may be destroyed which could cause the opening failed.. 
                        // Eat the exception and do nothing.
                        args.CanExecute = false; 
                    }
                }
                else if ( command == ApplicationCommands.SelectAll )
                { 
                    //anything to select?
                    args.CanExecute = ( inkCanvas.ActiveEditingMode == InkCanvasEditingMode.Select 
                                            && (inkCanvas.Strokes.Count > 0 || inkCanvas.Children.Count > 0)); 
                }
            } 
            else
            {
                // NTRAID:WINDOWSOS#1564508-2006/03/20-WAYNEZEN,
                // Return false for CanExecute if InkCanvas is disabled. 
                args.CanExecute = false;
            } 
 
            // NTRAID#WINDOWS-1371659-2005/11/08-waynezen,
            // Mark Handled as true so that the clipboard commands stops routing to InkCanvas' ancestors. 
            if ( command == ApplicationCommands.Cut || command == ApplicationCommands.Copy
                || command == ApplicationCommands.Paste )
            {
                args.Handled = true; 
            }
 
        } 

        private InkCanvasClipboardDataFormats PrivateCopySelection() 
        {
            InkCanvasClipboardDataFormats copiedDataFormats = InkCanvasClipboardDataFormats.None;

            // Don't even bother if we don't have a selection or UserIsEditing has been set. 
            if ( InkCanvasSelection.HasSelection && !_editingCoordinator.UserIsEditing)
            { 
                copiedDataFormats = CopyToDataObject(); 
            }
 
            return copiedDataFormats;
        }

 
        /// 
        /// _OnDeviceDown 
        ///  
        /// 
        ///  
        /// 
        private static void _OnDeviceDown(object sender, TEventArgs e)
            where TEventArgs : InputEventArgs
        { 
            ( (InkCanvas)sender ).EditingCoordinator.OnInkCanvasDeviceDown(sender, e);
        } 
 
        /// 
        /// _OnDeviceUp 
        /// 
        /// 
        /// 
        ///  
        private static void _OnDeviceUp(object sender, TEventArgs e)
            where TEventArgs : InputEventArgs 
        { 
            ((InkCanvas)sender).EditingCoordinator.OnInkCanvasDeviceUp(sender, e);
        } 

        /// 
        /// _OnQueryCursor
        ///  
        /// 
        ///  
        private static void _OnQueryCursor(object sender, QueryCursorEventArgs e) 
        {
            InkCanvas inkCanvas = (InkCanvas)sender; 

            if ( inkCanvas.UseCustomCursor )
            {
                // If UseCustomCursor is set, we bail out. Let the base class (FrameworkElement) to do the rest. 
                return;
            } 
 
            // We should behave like our base - honor ForceCursor property.
            if ( !e.Handled || inkCanvas.ForceCursor ) 
            {
                Cursor cursor = inkCanvas.EditingCoordinator.GetActiveBehaviorCursor();

                // If cursor is null, we don't handle the event and leave it as whatever the default is. 
                if ( cursor != null )
                { 
                    e.Cursor = cursor; 
                    e.Handled = true;
                } 
            }
        }

        ///  
        /// Update the current cursor if mouse is over InkCanvas. Called by
        ///     EditingCoordinator.InvalidateBehaviorCursor 
        ///     EditingCoordinator.UpdateEditingState 
        ///     InkCanvas.set_UseCustomCursor
        ///  
        internal void UpdateCursor()
        {
            if ( IsMouseOver )
            { 
                Mouse.UpdateCursor();
            } 
        } 

        #endregion Private Properties / Methods 

        //------------------------------------------------------
        //
        //  Private Classes 
        //
        //------------------------------------------------------ 
 
        #region Private Classes
 

        /// 
        /// A helper class for RTI high contrast support
        ///  
        private class RTIHighContrastCallback : HighContrastCallback
        { 
            //----------------------------------------------------- 
            //
            //  Cnostructors 
            //
            //------------------------------------------------------

            #region Constructors 

            internal RTIHighContrastCallback(InkCanvas inkCanvas) 
            { 
                _thisInkCanvas = inkCanvas;
            } 

            private RTIHighContrastCallback() { }

            #endregion Constructors 

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

            #region Internal Methods
 
            /// 
            /// TurnHighContrastOn 
            ///  
            /// 
            internal override void TurnHighContrastOn(Color highContrastColor) 
            {
                // The static strokes already have been taken care of by InkPresenter.
                // We only update the RTI renderer here.
                DrawingAttributes highContrastDa = _thisInkCanvas.DefaultDrawingAttributes.Clone(); 
                highContrastDa.Color = highContrastColor;
                _thisInkCanvas.UpdateDynamicRenderer(highContrastDa); 
            } 

            ///  
            /// TurnHighContrastOff
            /// 
            internal override void TurnHighContrastOff()
            { 
                // The static strokes already have been taken care of by InkPresenter.
                // We only update the RTI renderer here. 
                _thisInkCanvas.UpdateDynamicRenderer(_thisInkCanvas.DefaultDrawingAttributes); 
            }
 
            #endregion Internal Methods

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

            #region Internal Properties 

            /// 
            /// Returns the dispatcher if the object is associated to a UIContext.
            ///  
            internal override Dispatcher Dispatcher
            { 
                get 
                {
                    return _thisInkCanvas.Dispatcher; 
                }
            }

            #endregion Internal Properties 

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

            #region Private Fields
 
            private InkCanvas _thisInkCanvas;
 
            #endregion Private Fields 
        }
 
        /// 
        /// This is a binding converter which translates the InkCanvas.ActiveEditingMode to UIElement.Visibility.
        /// 
        private class ActiveEditingMode2VisibilityConverter : IValueConverter 
        {
            public object Convert(object o, Type type, object parameter, System.Globalization.CultureInfo culture) 
            { 
                InkCanvasEditingMode activeMode = (InkCanvasEditingMode)o;
 
                // If the current EditingMode is the mode which menuitem is expecting, return true for IsChecked.
                if ( activeMode != InkCanvasEditingMode.None )
                {
                    return Visibility.Visible; 
                }
                else 
                { 
                    return Visibility.Collapsed;
                } 
            }

            public object ConvertBack(object o, Type type, object parameter, System.Globalization.CultureInfo culture)
            { 
                // Non-reversed convertion
                return null; 
            } 
        }
 
        #endregion Private Classes

        #region Private Members
 
        /// 
        /// The element that represents the selected ink strokes, if any exist.  Will frequently be null. 
        ///  
        private InkCanvasSelection          _selection = null;
        private InkCanvasSelectionAdorner   _selectionAdorner = null; 
        private InkCanvasFeedbackAdorner    _feedbackAdorner = null;

        /// 
        /// The internal Canvas used to hold elements 
        /// 
        private InkCanvasInnerCanvas        _innerCanvas = null; 
 
        /// 
        /// The internal private AdornerDecorator 
        /// 
        private AdornerDecorator            _localAdornerDecorator = null;

        ///  
        /// Runtime Selection StrokeCollection
        ///  
        private StrokeCollection            _dynamicallySelectedStrokes; 

        ///  
        /// Our editing logic
        /// 
        private EditingCoordinator          _editingCoordinator;
 
        /// 
        /// Defines the default StylusPointDescription 
        ///  
        private StylusPointDescription     _defaultStylusPointDescription;
 

        /// 
        /// Defines the shape of the eraser tip
        ///  
        private StylusShape                 _eraserShape;
 
        ///  
        /// Determines if EditingBehaviors should use their own cursor or a custom one specified.
        ///  
        private bool                        _useCustomCursor = false;


        // 
        // Rendering support.
        // 
        private InkPresenter                _inkPresenter; 

        // 
        // The RealTimeInking PlugIn that handles our off UIContext rendering.
        //
        private DynamicRenderer             _dynamicRenderer;
 
        //
        // Clipboard Helper 
        // 
        private ClipboardProcessor          _clipboardProcessor;
 
        //
        // Gesture support
        //
        private GestureRecognizer           _gestureRecognizer; 

        // 
        // HighContrast support 
        //
        private RTIHighContrastCallback     _rtiHighContrastCallback; 

        private const double                    c_pasteDefaultLocation = 0.0;

        #endregion Private Members 
    }
} 
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//#define DEBUG_LASSO_FEEDBACK // DO NOT LEAVE ENABLED IN CHECKED IN CODE 
//----------------------------------------------------------------------------
//
// File: InkCanvas.cs
// 
// Description:
//      Defines an inkable canvas that represents the primary api for 
//      editing ink 
//
// Features: 
//
// History:
//  1/29/2002 samgeo:       Created
//  9/12/2003 samgeo:       Started porting to WCP 
//
// Copyright (C) 2001 by Microsoft Corporation.  All rights reserved. 
// 
//---------------------------------------------------------------------------
 
using MS.Utility;
using MS.Internal;
using MS.Internal.Commands;
using MS.Internal.Controls; 
using MS.Internal.Ink;
using MS.Internal.KnownBoxes; 
using System; 
using System.Collections;
using System.Collections.ObjectModel; 
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics; 
using System.IO;
using System.Windows; 
using System.Collections.Generic; 
using System.Security;
using System.Security.Permissions; 
using System.Runtime.InteropServices;
using System.Windows.Media;
using System.Windows.Data;
using System.Windows.Documents; 
using System.Windows.Ink;
using System.Windows.Input; 
using System.Windows.Input.StylusPlugIns; 
using System.Windows.Controls;
using System.Windows.Markup; // IAddChild, ContentPropertyAttribute 
using System.Windows.Threading;
using System.Windows.Automation.Peers;

namespace System.Windows.Controls 
{
 
    ///  
    /// InkCanvas is used to allow inking on a canvas
    ///  
    [ContentProperty("Children")]
    public class InkCanvas : FrameworkElement, IAddChild
    {
 
        #region Constructors / Initialization
 
        ///  
        /// The static constructor
        ///  
        static InkCanvas()
        {
            Type ownerType = typeof(InkCanvas);
 
            // NTRAID-WINDOWS#1423922-2005/12/15-WAYNEZEN,
            // We should add the following listener as the class handler which will be guarantied to receive the 
            // notification before the handler on the instances. So we won't be trapped in the bad state due to the 
            // event routing.
            // Listen to stylus events which will be redirected to the current StylusEditingBehavior 

            //Down
            EventManager.RegisterClassHandler(ownerType, Stylus.StylusDownEvent,
                new StylusDownEventHandler(_OnDeviceDown)); 
            EventManager.RegisterClassHandler(ownerType, Mouse.MouseDownEvent,
                new MouseButtonEventHandler(_OnDeviceDown)); 
 
            //Up
            EventManager.RegisterClassHandler(ownerType, Stylus.StylusUpEvent, 
                new StylusEventHandler(_OnDeviceUp));
            EventManager.RegisterClassHandler(ownerType, Mouse.MouseUpEvent,
                new MouseButtonEventHandler(_OnDeviceUp));
 

 
            EventManager.RegisterClassHandler(ownerType, Mouse.QueryCursorEvent, 
                new QueryCursorEventHandler(_OnQueryCursor), true);
 
            // Set up the commanding handlers
            _RegisterClipboardHandlers();
            CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.Delete,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled)); 

            CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.SelectAll, 
                Key.A, ModifierKeys.Control, new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled)); 

            CommandHelpers.RegisterCommandHandler(ownerType, InkCanvas.DeselectCommand, 
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled),
                SRID.InkCanvasDeselectKey, SRID.InkCanvasDeselectKeyDisplayString);

            // 
            //set our clipping
            // 
            ClipToBoundsProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(BooleanBoxes.TrueBox)); 

            // 
            //enable input focus
            //
            FocusableProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(BooleanBoxes.TrueBox));
 
            // The default InkCanvas style
            Style defaultStyle = new Style(ownerType); 
            // The background - Window Color 
            defaultStyle.Setters.Add(new Setter(InkCanvas.BackgroundProperty,
                            new DynamicResourceExtension(SystemColors.WindowBrushKey))); 
            // Default InkCanvas to having flicks disabled by default.
            defaultStyle.Setters.Add(new Setter(Stylus.IsFlicksEnabledProperty, false));
            // Default InkCanvas to having tap feedback disabled by default.
            defaultStyle.Setters.Add(new Setter(Stylus.IsTapFeedbackEnabledProperty, false)); 
            // Default InkCanvas to having touch feedback disabled by default.
            defaultStyle.Setters.Add(new Setter(Stylus.IsTouchFeedbackEnabledProperty, false)); 
 
            // Set MinWidth to 350d if Width is set to Auto
            Trigger trigger = new Trigger(); 
            trigger.Property = WidthProperty;
            trigger.Value = double.NaN;
            Setter setter = new Setter();
            setter.Property = MinWidthProperty; 
            setter.Value = 350d;
            trigger.Setters.Add(setter); 
            defaultStyle.Triggers.Add(trigger); 

            // Set MinHeight to 250d if Height is set to Auto 
            trigger = new Trigger();
            trigger.Property = HeightProperty;
            trigger.Value = double.NaN;
            setter = new Setter(); 
            setter.Property = MinHeightProperty;
            setter.Value = 250d; 
            trigger.Setters.Add(setter); 
            defaultStyle.Triggers.Add(trigger);
 
            // Seal the default style
            defaultStyle.Seal();

            StyleProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(defaultStyle)); 
            DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(typeof(InkCanvas)));
 
            FocusVisualStyleProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata((object)null /* default value */)); 
        }
 
        /// 
        /// Public constructor.
        /// 
        public InkCanvas() : base() 
        {
            Initialize(); 
        } 

        ///  
        /// Private initialization method used by the constructors
        /// 
        private void Initialize()
        { 
            //
            // instance the DynamicRenderer and add it to the StylusPlugIns 
            // 
            _dynamicRenderer = new DynamicRenderer();
            _dynamicRenderer.Enabled = false; 
            this.StylusPlugIns.Add(_dynamicRenderer);

            //
            // create and initialize an editing coordinator 
            //
            _editingCoordinator = new EditingCoordinator(this); 
            _editingCoordinator.UpdateActiveEditingState(); 

 
            // connect the attributes event handler after setting the stylus shape to avoid unnecessary
            //      calls into the RTI service
            DefaultDrawingAttributes.AttributeChanged += new PropertyDataChangedEventHandler(DefaultDrawingAttributes_Changed);
 
            //
            // 
            // We must initialize this here (after adding DynamicRenderer to Sytlus). 
            //
            this.InitializeInkObject(); 

            _rtiHighContrastCallback = new RTIHighContrastCallback(this);

            // Register rti high contrast callback. Then check whether we are under the high contrast already. 
            HighContrastHelper.RegisterHighContrastCallback(_rtiHighContrastCallback);
            if ( SystemParameters.HighContrast ) 
            { 
                _rtiHighContrastCallback.TurnHighContrastOn(SystemColors.WindowTextColor);
            } 
        }

        /// 
        /// Private helper used to change the Ink objects.  Used in the constructor 
        /// and the Ink property.
        /// 
        /// NOTE -- Caller is responsible for clearing any selection!  (We can't clear it 
        ///         here because the Constructor calls this method and it would end up calling
        ///         looking like it could call a virtual method and FxCop doesn't like that!) 
        ///
        /// 
        private void InitializeInkObject()
        { 
            // Update the RealTimeInking PlugIn for the Renderer changes.
            UpdateDynamicRenderer(); 
 
            // Initialize DefaultPacketDescription
            _defaultStylusPointDescription = new StylusPointDescription(); 

        }
        #endregion Constructors  / Initialization
 
        #region Protected Overrides
 
        ///  
        /// MeasureOverride
        ///  
        /// 
        /// 
        protected override Size MeasureOverride(Size availableSize)
        { 
            // No need to invoke VerifyAccess since _localAdornerDecorator.Measure should check it.
            if ( _localAdornerDecorator == null ) 
            { 
                ApplyTemplate();
            } 

            _localAdornerDecorator.Measure(availableSize);

            return  _localAdornerDecorator.DesiredSize; 
        }
 
        ///  
        /// ArrangeOverride
        ///  
        /// 
        /// 
        protected override Size ArrangeOverride(Size arrangeSize)
        { 
            // No need to invoke VerifyAccess since _localAdornerDecorator.Arrange should check it.
 
            if ( _localAdornerDecorator == null ) 
            {
                ApplyTemplate(); 
            }

            _localAdornerDecorator.Arrange(new Rect(arrangeSize));
 
            return arrangeSize;
        } 
 

        ///  
        /// HitTestCore implements precise hit testing against render contents
        /// 
        protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParams)
        { 
            VerifyAccess();
 
            Rect r = new Rect(new Point(), RenderSize); 
            if (r.Contains(hitTestParams.HitPoint))
            { 
                return new PointHitTestResult(this, hitTestParams.HitPoint);
            }

            return null; 
        }
 
        ///  
        /// OnPropertyChanged
        ///  
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
 
            if (e.IsAValueChange || e.IsASubPropertyChange)
            { 
                if (e.Property == UIElement.RenderTransformProperty || 
                    e.Property == FrameworkElement.LayoutTransformProperty)
                { 
                    EditingCoordinator.InvalidateTransform();

                    Transform transform = e.NewValue as Transform;
                    if (transform != null && !transform.HasAnimatedProperties) 
                    {
                        TransformGroup transformGroup = transform as TransformGroup; 
                        if ( transformGroup != null ) 
                        {
                            //walk down the tree looking for animated transforms 
                            Stack transforms = new Stack();
                            transforms.Push(transform);
                            while ( transforms.Count > 0 )
                            { 
                                transform = transforms.Pop();
                                if ( transform.HasAnimatedProperties ) 
                                { 
                                    return;
                                } 
                                transformGroup = transform as TransformGroup;
                                if ( transformGroup != null )
                                {
                                    for ( int i = 0; i < transformGroup.Children.Count; i++ ) 
                                    {
                                        transforms.Push(transformGroup.Children[i]); 
                                    } 
                                }
                            } 
                        }

                        //
                        // only invalidate when there is not an animation on the xf, 
                        // or we could wind up creating thousands of new cursors.  That's bad.
                        // 
                        _editingCoordinator.InvalidateBehaviorCursor(_editingCoordinator.InkCollectionBehavior); 
                        EditingCoordinator.UpdatePointEraserCursor();
                    } 
                }
                if (e.Property == FrameworkElement.FlowDirectionProperty)
                {
                    //flow direction only affects the inking cursor. 
                    _editingCoordinator.InvalidateBehaviorCursor(_editingCoordinator.InkCollectionBehavior);
                } 
            } 
        }
 
        /// 
        /// Called when the Template's tree is about to be generated
        /// 
        internal override void OnPreApplyTemplate() 
        {
            // No need for calling VerifyAccess since we call the method on the base here. 
 
            base.OnPreApplyTemplate();
 
            // Build our visual tree here.
            // 
            //     
            //          
            //             
            //                            
            //                                 
            //         
            //                                 
            //             
            //                  
            //         
            //      
            //  
 
            if ( _localAdornerDecorator == null ) 
            {
                // 
                _localAdornerDecorator = new AdornerDecorator();
                InkPresenter inkPresenter = InkPresenter;

                // Build the visual tree top-down 
                AddVisualChild(_localAdornerDecorator);
                _localAdornerDecorator.Child = inkPresenter; 
                inkPresenter.Child = InnerCanvas; 

                // Add the SelectionAdorner after Canvas is added. 
                _localAdornerDecorator.AdornerLayer.Add(SelectionAdorner);
            }
        }
 
        /// 
        /// Returns the Visual children count. 
        ///  
        protected override int VisualChildrenCount
        { 
            get { return (_localAdornerDecorator == null) ? 0 : 1; }
        }

        ///  
        /// Returns the child at the specified index.
        ///  
        protected override Visual GetVisualChild(int index) 
        {
            if (    (_localAdornerDecorator == null) 
                ||  (index != 0))
            {
                throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
            } 

            return _localAdornerDecorator; 
        } 

        ///  
        /// UIAutomation support
        /// 
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new InkCanvasAutomationPeer(this);
        } 
 
        #endregion Protected Overrides
 
        #region Public Properties

        /// 
        ///     The DependencyProperty for the Background property. 
        /// 
        public static readonly DependencyProperty BackgroundProperty = 
                Panel.BackgroundProperty.AddOwner( 
                        typeof(InkCanvas),
                        new FrameworkPropertyMetadata( 
                                null,
                                FrameworkPropertyMetadataOptions.AffectsRender));

        ///  
        ///     An object that describes the background.
        ///  
        [Bindable(true), Category("Appearance")] 
        public Brush Background
        { 
            get { return (Brush) GetValue(BackgroundProperty); }
            set { SetValue(BackgroundProperty, value); }
        }
 
        /// 
        /// Top DependencyProperty 
        ///  
        public static readonly DependencyProperty TopProperty =
                DependencyProperty.RegisterAttached("Top", typeof(double), typeof(InkCanvas), 
                    new FrameworkPropertyMetadata(Double.NaN, new PropertyChangedCallback(OnPositioningChanged)),
                    new ValidateValueCallback(System.Windows.Shapes.Shape.IsDoubleFiniteOrNaN));

        ///  
        /// Reads the attached property Top from the given element.
        ///  
        /// The element from which to read the Top attached property. 
        /// The property's value.
        ///  
        [TypeConverter("System.Windows.LengthConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")]
        [AttachedPropertyBrowsableForChildren()]
        public static double GetTop(UIElement element)
        { 
            if (element == null) { throw new ArgumentNullException("element"); }
            return (double)element.GetValue(TopProperty); 
        } 

        ///  
        /// Writes the attached property Top to the given element.
        /// 
        /// The element to which to write the Top attached property.
        /// The length to set 
        /// 
        public static void SetTop(UIElement element, double length) 
        { 
            if (element == null) { throw new ArgumentNullException("element"); }
            element.SetValue(TopProperty, length); 
        }

        /// 
        /// The Bottom DependencyProperty 
        /// 
        public static readonly DependencyProperty BottomProperty = 
                DependencyProperty.RegisterAttached("Bottom", typeof(double), typeof(InkCanvas), 
                    new FrameworkPropertyMetadata(Double.NaN, new PropertyChangedCallback(OnPositioningChanged)),
                    new ValidateValueCallback(System.Windows.Shapes.Shape.IsDoubleFiniteOrNaN)); 

        /// 
        /// Reads the attached property Bottom from the given element.
        ///  
        /// The element from which to read the Bottom attached property.
        /// The property's Length value. 
        ///  
        [TypeConverter("System.Windows.LengthConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")]
        [AttachedPropertyBrowsableForChildren()] 
        public static double GetBottom(UIElement element)
        {
            if (element == null) { throw new ArgumentNullException("element"); }
            return (double)element.GetValue(BottomProperty); 
        }
 
        ///  
        /// Writes the attached property Bottom to the given element.
        ///  
        /// The element to which to write the Bottom attached property.
        /// The Length to set
        /// 
        public static void SetBottom(UIElement element, double length) 
        {
            if (element == null) { throw new ArgumentNullException("element"); } 
            element.SetValue(BottomProperty, length); 
        }
 
        /// 
        /// The Left DependencyProperty
        /// 
        public static readonly DependencyProperty LeftProperty = 
                DependencyProperty.RegisterAttached("Left", typeof(double), typeof(InkCanvas),
                    new FrameworkPropertyMetadata(Double.NaN, new PropertyChangedCallback(OnPositioningChanged)), 
                    new ValidateValueCallback(System.Windows.Shapes.Shape.IsDoubleFiniteOrNaN)); 

        ///  
        /// Reads the attached property Left from the given element.
        /// 
        /// The element from which to read the Left attached property.
        /// The property's value. 
        /// 
        [TypeConverter("System.Windows.LengthConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")] 
        [AttachedPropertyBrowsableForChildren()] 
        public static double GetLeft(UIElement element)
        { 
            if (element == null) { throw new ArgumentNullException("element"); }
            return (double)element.GetValue(LeftProperty);
        }
 
        /// 
        /// Writes the attached property Left to the given element. 
        ///  
        /// The element to which to write the Left attached property.
        /// The length to set 
        /// 
        public static void SetLeft(UIElement element, double length)
        {
            if (element == null) { throw new ArgumentNullException("element"); } 
            element.SetValue(LeftProperty, length);
        } 
 
        /// 
        /// The Right DependencyProperty 
        /// 
        public static readonly DependencyProperty RightProperty =
                DependencyProperty.RegisterAttached("Right", typeof(double), typeof(InkCanvas),
                    new FrameworkPropertyMetadata(Double.NaN, new PropertyChangedCallback(OnPositioningChanged)), 
                    new ValidateValueCallback(System.Windows.Shapes.Shape.IsDoubleFiniteOrNaN));
 
        ///  
        /// Reads the attached property Right from the given element.
        ///  
        /// The element from which to read the Right attached property.
        /// The property's Length value.
        /// 
        [TypeConverter("System.Windows.LengthConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")] 
        [AttachedPropertyBrowsableForChildren()]
        public static double GetRight(UIElement element) 
        { 
            if (element == null) { throw new ArgumentNullException("element"); }
            return (double)element.GetValue(RightProperty); 
        }

        /// 
        /// Writes the attached property Right to the given element. 
        /// 
        /// The element to which to write the Right attached property. 
        /// The Length to set 
        /// 
        public static void SetRight(UIElement element, double length) 
        {
            if (element == null) { throw new ArgumentNullException("element"); }
            element.SetValue(RightProperty, length);
        } 

        ///  
        /// OnPositioningChanged 
        /// 
        ///  
        /// 
        private static void OnPositioningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement uie = d as UIElement; 
            if ( uie != null )
            { 
                // Make sure the UIElement is a child of InkCanvasInnerCanvas. 
                InkCanvasInnerCanvas p = VisualTreeHelper.GetParent(uie) as InkCanvasInnerCanvas;
                if ( p != null ) 
                {
                    if ( e.Property == InkCanvas.LeftProperty
                        || e.Property == InkCanvas.TopProperty )
                    { 
                        // Invalidate measure for Left and/or Top.
                        p.InvalidateMeasure(); 
                    } 
                    else
                    { 
                        Debug.Assert(e.Property == InkCanvas.RightProperty || e.Property == InkCanvas.BottomProperty,
                            string.Format(System.Globalization.CultureInfo.InvariantCulture, "Unknown dependency property detected - {0}.", e.Property));

                        // Invalidate arrange for Right and/or Bottom. 
                        p.InvalidateArrange();
                    } 
                } 
            }
        } 

        /// 
        ///     The DependencyProperty for the Strokes property.
        ///  
        public static readonly DependencyProperty StrokesProperty =
                InkPresenter.StrokesProperty.AddOwner( 
                        typeof(InkCanvas), 
                        new FrameworkPropertyMetadata(
                                new StrokeCollectionDefaultValueFactory(), 
                                new PropertyChangedCallback(OnStrokesChanged)));

        /// 
        /// Gets/Sets the Strokes property. 
        /// 
        public StrokeCollection Strokes 
        { 
            get { return (StrokeCollection)GetValue(StrokesProperty); }
            set { SetValue(StrokesProperty, value); } 
        }

        private static void OnStrokesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            InkCanvas inkCanvas = (InkCanvas)d;
            StrokeCollection oldValue = (StrokeCollection)e.OldValue; 
            StrokeCollection newValue = (StrokeCollection)e.NewValue; 

            // 
            // only change the prop if it's a different object.  We don't
            // want to be doing this for no reason
            //
            if ( !object.ReferenceEquals(oldValue, newValue) ) 
            {
                // Clear the selected strokes without raising event. 
                inkCanvas.CoreChangeSelection(new StrokeCollection(), inkCanvas.InkCanvasSelection.SelectedElements, false); 

                inkCanvas.InitializeInkObject(); 

                InkCanvasStrokesReplacedEventArgs args =
                    new InkCanvasStrokesReplacedEventArgs(newValue, oldValue); //new, previous
 
                //raise the StrokesChanged event through our protected virtual
                inkCanvas.OnStrokesReplaced(args); 
            } 

        } 

        /// 
        /// Returns the SelectionAdorner
        ///  
        internal InkCanvasSelectionAdorner SelectionAdorner
        { 
            get 
            {
                // We have to create our visual at this point. 
                if ( _selectionAdorner == null )
                {
                    // Create the selection Adorner.
                    _selectionAdorner = new InkCanvasSelectionAdorner(InnerCanvas); 

                    // Bind the InkCanvas.ActiveEditingModeProperty 
                    // to SelectionAdorner.VisibilityProperty. 
                    Binding activeEditingModeBinding = new Binding();
                    activeEditingModeBinding.Path = new PropertyPath(InkCanvas.ActiveEditingModeProperty); 
                    activeEditingModeBinding.Mode = BindingMode.OneWay;
                    activeEditingModeBinding.Source = this;
                    activeEditingModeBinding.Converter = new ActiveEditingMode2VisibilityConverter();
                    _selectionAdorner.SetBinding(UIElement.VisibilityProperty, activeEditingModeBinding); 
                }
 
                return _selectionAdorner; 
            }
        } 

        /// 
        /// Returns the FeedbackAdorner
        ///  
        internal InkCanvasFeedbackAdorner FeedbackAdorner
        { 
            get 
            {
                VerifyAccess(); 

                if ( _feedbackAdorner == null )
                {
                    _feedbackAdorner = new InkCanvasFeedbackAdorner(this); 
                }
 
                return _feedbackAdorner; 
            }
        } 

        /// 
        /// Read/Write access to the EraserShape property.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsGestureRecognizerAvailable 
        { 
            get
            { 
                //this property will verify access
                return this.GestureRecognizer.IsRecognizerAvailable;
            }
        } 

 
        ///  
        /// Emulate Panel's Children property.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public UIElementCollection Children
        {
            get 
            {
                // No need to invoke VerifyAccess since the call is forwarded. 
 
                return InnerCanvas.Children;
            } 
        }

        /// 
        /// The DependencyProperty for the DefaultDrawingAttributes property. 
        /// 
        public static readonly DependencyProperty DefaultDrawingAttributesProperty = 
                DependencyProperty.Register( 
                        "DefaultDrawingAttributes",
                        typeof(DrawingAttributes), 
                        typeof(InkCanvas),
                        new FrameworkPropertyMetadata(
                                new DrawingAttributesDefaultValueFactory(),
                                new PropertyChangedCallback(OnDefaultDrawingAttributesChanged)), 
                        (ValidateValueCallback)delegate(object value)
                            { return value != null; }); 
 
        /// 
        /// Gets/Sets the DefaultDrawingAttributes property. 
        /// 
        public DrawingAttributes DefaultDrawingAttributes
        {
            get { return (DrawingAttributes)GetValue(DefaultDrawingAttributesProperty); } 
            set { SetValue(DefaultDrawingAttributesProperty, value); }
        } 
 
        private static void OnDefaultDrawingAttributesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            InkCanvas inkCanvas = (InkCanvas)d;

            DrawingAttributes oldValue = (DrawingAttributes)e.OldValue;
            DrawingAttributes newValue = (DrawingAttributes)e.NewValue; 

            // This can throw, so call it first 
            inkCanvas.UpdateDynamicRenderer(newValue); 

            // We only fire Changed event when there is an instance change. 
            if ( !object.ReferenceEquals(oldValue, newValue) )
            {
                //we didn't throw, change our backing value
                oldValue.AttributeChanged -= new PropertyDataChangedEventHandler(inkCanvas.DefaultDrawingAttributes_Changed); 
                DrawingAttributesReplacedEventArgs args =
                    new DrawingAttributesReplacedEventArgs(newValue, oldValue); 
 
                newValue.AttributeChanged += new PropertyDataChangedEventHandler(inkCanvas.DefaultDrawingAttributes_Changed);
                inkCanvas.RaiseDefaultDrawingAttributeReplaced(args); 
            }
        }

        ///  
        /// Read/Write access to the EraserShape property.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public StylusShape EraserShape
        { 
            get
            {
                VerifyAccess();
                if (_eraserShape == null) 
                {
                    _eraserShape = new RectangleStylusShape(8f, 8f); 
                } 
                return _eraserShape;
 
            }
            set
            {
                VerifyAccess(); 
                if (value == null)
                { 
                    throw new ArgumentNullException("value"); 
                }
                else 
                {
                    // Invoke getter since this property is lazily created.
                    StylusShape oldShape = EraserShape;
 
                    _eraserShape = value;
 
 
                    if ( oldShape.Width != _eraserShape.Width || oldShape.Height != _eraserShape.Height
                        || oldShape.Rotation != _eraserShape.Rotation || oldShape.GetType() != _eraserShape.GetType()) 
                    {
                        EditingCoordinator.UpdatePointEraserCursor();
                    }
                } 
            }
        } 
 

        ///  
        /// ActiveEditingMode
        /// 
        internal static readonly DependencyPropertyKey ActiveEditingModePropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "ActiveEditingMode",
                        typeof(InkCanvasEditingMode), 
                        typeof(InkCanvas), 
                        new FrameworkPropertyMetadata(InkCanvasEditingMode.Ink));
 
        /// 
        /// ActiveEditingModeProperty Dependency Property
        /// 
        public static readonly DependencyProperty ActiveEditingModeProperty = ActiveEditingModePropertyKey.DependencyProperty; 

        ///  
        /// Gets the ActiveEditingMode 
        /// 
        public InkCanvasEditingMode ActiveEditingMode 
        {
            get { return (InkCanvasEditingMode)GetValue(ActiveEditingModeProperty); }
        }
 
        /// 
        /// The DependencyProperty for the EditingMode property. 
        ///  
        public static readonly DependencyProperty EditingModeProperty =
                DependencyProperty.Register( 
                        "EditingMode",
                        typeof(InkCanvasEditingMode),
                        typeof(InkCanvas),
                        new FrameworkPropertyMetadata( 
                                InkCanvasEditingMode.Ink,
                                new PropertyChangedCallback(OnEditingModeChanged)), 
                        new ValidateValueCallback(ValidateEditingMode)); 

 
        /// 
        /// Gets/Sets EditingMode
        /// 
        public InkCanvasEditingMode EditingMode 
        {
            get { return (InkCanvasEditingMode)GetValue(EditingModeProperty); } 
            set { SetValue(EditingModeProperty, value); } 
        }
 

        private static void OnEditingModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ( (InkCanvas)d ).RaiseEditingModeChanged( 
                                new RoutedEventArgs(InkCanvas.EditingModeChangedEvent, d));
        } 
 
        /// 
        /// The DependencyProperty for the EditingModeInverted property. 
        /// 
        public static readonly DependencyProperty EditingModeInvertedProperty =
                DependencyProperty.Register(
                        "EditingModeInverted", 
                        typeof(InkCanvasEditingMode),
                        typeof(InkCanvas), 
                        new FrameworkPropertyMetadata( 
                                InkCanvasEditingMode.EraseByStroke,
                                new PropertyChangedCallback(OnEditingModeInvertedChanged)), 
                        new ValidateValueCallback(ValidateEditingMode));

        /// 
        /// Gets/Sets EditingMode 
        /// 
        public InkCanvasEditingMode EditingModeInverted 
        { 
            get { return (InkCanvasEditingMode)GetValue(EditingModeInvertedProperty); }
            set { SetValue(EditingModeInvertedProperty, value); } 
        }

        private static void OnEditingModeInvertedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ( (InkCanvas)d ).RaiseEditingModeInvertedChanged(
                new RoutedEventArgs(InkCanvas.EditingModeInvertedChangedEvent, d)); 
        } 

        private static bool ValidateEditingMode(object value) 
        {
            return EditingModeHelper.IsDefined((InkCanvasEditingMode)value);
        }
 
        /// 
        /// This flag indicates whether the developer is using a custom mouse cursor. 
        /// 
        /// If this flag is true, we will never change the current cursor on them. Not
        /// on edit mode change. 
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool UseCustomCursor
        { 
            get
            { 
                VerifyAccess(); 
                return _useCustomCursor;
            } 
            set
            {
                VerifyAccess();
 
                if ( _useCustomCursor != value )
                { 
                    _useCustomCursor = value; 
                    UpdateCursor();
                } 
            }
        }

        ///  
        /// Gets or set if moving of selection is enabled
        ///  
        /// bool 
        public bool MoveEnabled
        { 
            get
            {
                VerifyAccess();
                return _editingCoordinator.MoveEnabled; 
            }
            set 
            { 
                VerifyAccess();
                bool oldValue = _editingCoordinator.MoveEnabled; 

                if (oldValue != value)
                {
                    _editingCoordinator.MoveEnabled = value; 
                }
            } 
        } 

        ///  
        /// Gets or set if resizing selection is enabled
        /// 
        /// bool
        public bool ResizeEnabled 
        {
            get 
            { 
                VerifyAccess();
                return _editingCoordinator.ResizeEnabled; 
            }
            set
            {
                VerifyAccess(); 
                bool oldValue = _editingCoordinator.ResizeEnabled;
 
                if (oldValue != value) 
                {
                    _editingCoordinator.ResizeEnabled = value; 
                }
            }
        }
 

        ///  
        /// Read/Write access to the DefaultPacketDescription property. 
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public StylusPointDescription DefaultStylusPointDescription
        {
            get
            { 
                VerifyAccess();
 
                return _defaultStylusPointDescription; 
            }
            set 
            {
                VerifyAccess();

                // 
                // no nulls allowed
                // 
                if ( value == null ) 
                {
                    throw new ArgumentNullException("value"); 
                }

                _defaultStylusPointDescription = value;
            } 
        }
 
        ///  
        /// Read/Write the enabled ClipboardFormats
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IEnumerable PreferredPasteFormats
        {
            get 
            {
                VerifyAccess(); 
 
                return ClipboardProcessor.PreferredFormats;
            } 
            set
            {
                VerifyAccess();
 
                // Cannot be null
                if ( value == null ) 
                { 
                    // Null is not allowed as the argument value
                    throw new ArgumentNullException("value"); 
                }

                ClipboardProcessor.PreferredFormats = value;
            } 
        }
 
        #endregion Public Properties 

        #region Public Events 

        /// 
        ///     The StrokeErased Routed Event
        ///  
        public static readonly RoutedEvent StrokeCollectedEvent =
            EventManager.RegisterRoutedEvent("StrokeCollected", RoutingStrategy.Bubble, typeof(InkCanvasStrokeCollectedEventHandler), typeof(InkCanvas)); 
 
        /// 
        ///     Add / Remove StrokeCollected handler 
        /// 
        [Category("Behavior")]
        public event InkCanvasStrokeCollectedEventHandler StrokeCollected
        { 
            add
            { 
                AddHandler(InkCanvas.StrokeCollectedEvent, value); 
            }
 
            remove
            {
                RemoveHandler(InkCanvas.StrokeCollectedEvent, value);
            } 
        }
 
        ///  
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// InkCanvasStrokeCollectedEventArgs to raise the event with
        protected virtual void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free.
 
            if ( e == null ) 
            {
                throw new ArgumentNullException("e"); 
            }

            RaiseEvent(e);
        } 

        ///  
        /// Allows the InkCollectionBehavior to raise the StrokeCollected event via the protected virtual 
        /// 
        /// InkCanvasStrokeCollectedEventArgs to raise the event with 
        /// true only if 100% of the stylusPoints that makes up the stroke
        /// came from eventargs with the UserInitiated flag set to true
        /// 
        ///     Critical: Calls critical method GestureRecognizer.CriticalRecognize.  It is important 
        ///         that this is only called if userInitiated is true.
        ///  
        [SecurityCritical] 
        internal void RaiseGestureOrStrokeCollected(InkCanvasStrokeCollectedEventArgs e, bool userInitiated)
        { 
            Debug.Assert(e != null, "EventArg can not be null");
            bool addStrokeToInkCanvas = true; // Initialize our flag.

            // The follow code raises Gesture event 
            // The out-side code could throw exception in the their handlers. We use try/finally block to protect our status.
            try 
            { 
                //
                // perform gesture reco before raising this event 
                // if we're in the right mode
                //
                //IMPORTANT: only call gesture recognition if userInitiated.  See SecurityNote.
                if (userInitiated) 
                {
                    if ((this.ActiveEditingMode == InkCanvasEditingMode.InkAndGesture || 
                          this.ActiveEditingMode == InkCanvasEditingMode.GestureOnly) && 
                          this.GestureRecognizer.IsRecognizerAvailable)
                    { 
                        StrokeCollection strokes = new StrokeCollection();
                        strokes.Add(e.Stroke);

                        // 
                        // GestureRecognizer.Recognize demands unmanaged code, we assert it here
                        // as this codepath is only called in response to user input 
                        // 
                        ReadOnlyCollection results =
                            this.GestureRecognizer.CriticalRecognize(strokes); 

                        if (results.Count > 0)
                        {
                            InkCanvasGestureEventArgs args = 
                                new InkCanvasGestureEventArgs(strokes, results);
 
                            if (results[0].ApplicationGesture == ApplicationGesture.NoGesture) 
                            {
                                // 
                                // we set Cancel=true if we didn't detect a gesture
                                //
                                args.Cancel = true;
                            } 
                            else
                            { 
                                args.Cancel = false; 
                            }
 
                            this.OnGesture(args);

                            //
                            // now that we've raised the Gesture event and the developer 
                            // has had a chance to change args.Cancel, see what their intent is.
                            // 
                            if (args.Cancel == false) 
                            {
                                //bail out and don't add 
                                //the stroke to InkCanvas.Strokes
                                addStrokeToInkCanvas = false; // Reset the flag.
                                return;
                            } 
                        }
                    } 
                } 

                // Reset the flag. 
                addStrokeToInkCanvas = false;

                //
                // only raise StrokeCollected if we're in InkCanvasEditingMode.Ink or InkCanvasEditingMode.InkAndGesture 
                //
                if ( this.ActiveEditingMode == InkCanvasEditingMode.Ink || 
                    this.ActiveEditingMode == InkCanvasEditingMode.InkAndGesture ) 
                {
                    //add the stroke to the StrokeCollection and raise this event 
                    this.Strokes.Add(e.Stroke);
                    this.OnStrokeCollected(e);
                }
            } 
            finally
            { 
                // If the gesture events are failed, we should still add Stroke to the InkCanvas so that the data won't be lost. 
                if ( addStrokeToInkCanvas )
                { 
                    this.Strokes.Add(e.Stroke);
                }
            }
        } 

        ///  
        ///     The Gesture Routed Event 
        /// 
        public static readonly RoutedEvent GestureEvent = 
            EventManager.RegisterRoutedEvent("Gesture", RoutingStrategy.Bubble, typeof(InkCanvasGestureEventHandler), typeof(InkCanvas));

        /// 
        ///     Add / Remove Gesture handler 
        /// 
        [Category("Behavior")] 
        public event InkCanvasGestureEventHandler Gesture 
        {
            add 
            {
                AddHandler(InkCanvas.GestureEvent, value);
            }
 
            remove
            { 
                RemoveHandler(InkCanvas.GestureEvent, value); 
            }
        } 

        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// InkCanvasGestureEventArgs to raise the event with 
        protected virtual void OnGesture(InkCanvasGestureEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null )
            {
                throw new ArgumentNullException("e"); 
            }
 
            RaiseEvent(e); 
        }
 
        /// 
        /// Raised when the InkCanvas.Strokes StrokeCollection has been replaced with another one
        /// 
        public event InkCanvasStrokesReplacedEventHandler StrokesReplaced; 

        ///  
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        ///  
        /// InkCanvasStrokesChangedEventArgs to raise the event with
        protected virtual void OnStrokesReplaced(InkCanvasStrokesReplacedEventArgs e)
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null ) 
            { 
                throw new ArgumentNullException("e");
            } 
            if (null != this.StrokesReplaced)
            {
                StrokesReplaced(this, e);
            } 
        }
 
        ///  
        /// Raised when the InkCanvas.DefaultDrawingAttributes has been replaced with another one
        ///  
        public event DrawingAttributesReplacedEventHandler DefaultDrawingAttributesReplaced;

        /// 
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        ///  
        /// DrawingAttributesReplacedEventArgs to raise the event with 
        protected virtual void OnDefaultDrawingAttributesReplaced(DrawingAttributesReplacedEventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free.

            if (e == null)
            { 
                throw new ArgumentNullException("e");
            } 
            if (null != this.DefaultDrawingAttributesReplaced) 
            {
                DefaultDrawingAttributesReplaced(this, e); 
            }
        }

        ///  
        /// Private helper for raising DDAReplaced.  Invalidates the inking cursor
        ///  
        ///  
        private void RaiseDefaultDrawingAttributeReplaced(DrawingAttributesReplacedEventArgs e)
        { 
            this.OnDefaultDrawingAttributesReplaced(e);

            // Invalidate the inking cursor
            _editingCoordinator.InvalidateBehaviorCursor(_editingCoordinator.InkCollectionBehavior); 
        }
 
        ///  
        ///     Event corresponds to ActiveEditingModeChanged
        ///  
        public static readonly RoutedEvent ActiveEditingModeChangedEvent =
            EventManager.RegisterRoutedEvent("ActiveEditingModeChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InkCanvas));

        ///  
        ///     Add / Remove ActiveEditingModeChanged handler
        ///  
        [Category("Behavior")] 
        public event RoutedEventHandler ActiveEditingModeChanged
        { 
            add
            {
                AddHandler(InkCanvas.ActiveEditingModeChangedEvent, value);
            } 
            remove
            { 
                RemoveHandler(InkCanvas.ActiveEditingModeChangedEvent, value); 
            }
        } 

        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// EventArgs to raise the event with 
        protected virtual void OnActiveEditingModeChanged(RoutedEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if (e == null)
            {
                throw new ArgumentNullException("e"); 
            }
 
            RaiseEvent(e); 
        }
 
        /// 
        /// Private helper that raises ActiveEditingModeChanged
        /// 
        /// EventArgs to raise the event with 
        internal void RaiseActiveEditingModeChanged(RoutedEventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null"); 

            InkCanvasEditingMode mode = this.ActiveEditingMode; 
            if (mode != _editingCoordinator.ActiveEditingMode)
            {
                //change our DP, then raise the event via our protected override
                SetValue(ActiveEditingModePropertyKey, _editingCoordinator.ActiveEditingMode); 

                this.OnActiveEditingModeChanged(e); 
            } 
        }
 


        /// 
        ///     Event corresponds to EditingModeChanged 
        /// 
        public static readonly RoutedEvent EditingModeChangedEvent = 
            EventManager.RegisterRoutedEvent("EditingModeChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InkCanvas)); 

        ///  
        ///     Add / Remove EditingModeChanged handler
        /// 
        [Category("Behavior")]
        public event RoutedEventHandler EditingModeChanged 
        {
            add 
            { 
                AddHandler(InkCanvas.EditingModeChangedEvent, value);
            } 

            remove
            {
                RemoveHandler(InkCanvas.EditingModeChangedEvent, value); 
            }
        } 
 
        /// 
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        /// 
        /// EventArgs to raise the event with
        protected virtual void OnEditingModeChanged(RoutedEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 
 
            if ( e == null )
            { 
                throw new ArgumentNullException("e");
            }

            RaiseEvent(e); 
        }
        ///  
        /// Private helper that raises EditingModeChanged but first 
        /// talks to the InkEditor about it
        ///  
        /// EventArgs to raise the event with
        private void RaiseEditingModeChanged(RoutedEventArgs e)
        {
            Debug.Assert(e != null, "EventArg can not be null"); 

            _editingCoordinator.UpdateEditingState(false /* EditingMode */); 
 
            this.OnEditingModeChanged(e);
        } 

        //note: there is no need for an internal RaiseEditingModeInvertedChanging
        //since this isn't a dynamic property and therefore can not be set
        //outside of this class 

        ///  
        ///     Event corresponds to EditingModeInvertedChanged 
        /// 
        public static readonly RoutedEvent EditingModeInvertedChangedEvent = 
            EventManager.RegisterRoutedEvent("EditingModeInvertedChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InkCanvas));

        /// 
        ///     Add / Remove EditingModeChanged handler 
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler EditingModeInvertedChanged 
        {
            add 
            {
                AddHandler(InkCanvas.EditingModeInvertedChangedEvent, value);
            }
 
            remove
            { 
                RemoveHandler(InkCanvas.EditingModeInvertedChangedEvent, value); 
            }
        } 

        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// EventArgs to raise the event with 
        protected virtual void OnEditingModeInvertedChanged(RoutedEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null )
            {
                throw new ArgumentNullException("e"); 
            }
 
            RaiseEvent(e); 
        }
        ///  
        /// Private helper that raises EditingModeInvertedChanged but first
        /// talks to the InkEditor about it
        /// 
        /// EventArgs to raise the event with 
        private void RaiseEditingModeInvertedChanged(RoutedEventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null"); 

            _editingCoordinator.UpdateEditingState(true /* EditingModeInverted */); 

            this.OnEditingModeInvertedChanged(e);
        }
 
        /// 
        /// Occurs when the user has moved the selection, after they lift their stylus to commit the change. 
        /// This event allows the developer to cancel the move. 
        /// 
        public event  InkCanvasSelectionEditingEventHandler SelectionMoving; 
        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event.
        ///  
        ///  InkCanvasSelectionEditingEventArgs to raise the event with
        protected virtual void OnSelectionMoving( InkCanvasSelectionEditingEventArgs e) 
        { 
            // No need to invoke VerifyAccess since this method is thread free.
 
            if ( e == null )
            {
                throw new ArgumentNullException("e");
            } 
            if (null != SelectionMoving)
            { 
                SelectionMoving(this, e); 
            }
        } 

        /// 
        /// Allows the EditingBehaviors to raise the SelectionMoving event via the protected virtual
        ///  
        ///  InkCanvasSelectionEditingEventArgs to raise the event with
        internal void RaiseSelectionMoving( InkCanvasSelectionEditingEventArgs e) 
        { 
            Debug.Assert(e != null, "EventArg can not be null");
            this.OnSelectionMoving(e); 
        }

        /// 
        /// Occurs when the user has moved the selection, after they lift their stylus to commit the change. 
        /// This event allows the developer to cancel the move.
        ///  
        public event EventHandler SelectionMoved; 
        /// 
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        /// 
        /// EventArgs to raise the event with
        protected virtual void OnSelectionMoved(EventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 
 
            if ( e == null )
            { 
                throw new ArgumentNullException("e");
            }
            if (null != SelectionMoved)
            { 
                SelectionMoved(this, e);
            } 
        } 

        ///  
        /// Allows the EditingBehaviors to raise the SelectionMoved event via the protected virtual
        /// 
        /// EventArgs to raise the event with
        internal void RaiseSelectionMoved(EventArgs e) 
        {
            Debug.Assert(e != null, "EventArg can not be null"); 
 
            this.OnSelectionMoved(e);
            // Update the cursor of SelectionEditor behavior. 
            EditingCoordinator.SelectionEditor.OnInkCanvasSelectionChanged();
        }

        ///  
        /// Occurs when the user has erased Strokes using the erase behavior
        /// 
        /// This event allows the developer to cancel the erase -- therefore, the Stroke should not disappear until 
        /// this event has finished.
        ///  
        public event InkCanvasStrokeErasingEventHandler StrokeErasing;
        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// InkCanvasStrokeErasingEventArgs to raise the event with 
        protected virtual void OnStrokeErasing(InkCanvasStrokeErasingEventArgs e) 
        {
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null )
            {
                throw new ArgumentNullException("e"); 
            }
            if (null != StrokeErasing) 
            { 
                StrokeErasing(this, e);
            } 
        }

        /// 
        /// Allows the EditingBehaviors to raise the InkErasing event via the protected virtual 
        /// 
        /// InkCanvasStrokeErasingEventArgs to raise the event with 
        internal void RaiseStrokeErasing(InkCanvasStrokeErasingEventArgs e) 
        {
            Debug.Assert(e != null, "EventArg can not be null"); 
            this.OnStrokeErasing(e);
        }

        ///  
        ///     The StrokeErased Routed Event
        ///  
        public static readonly RoutedEvent StrokeErasedEvent = 
            EventManager.RegisterRoutedEvent("StrokeErased", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InkCanvas));
 
        /// 
        ///     Add / Remove EditingModeChanged handler
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler StrokeErased
        { 
            add 
            {
                AddHandler(InkCanvas.StrokeErasedEvent, value); 
            }

            remove
            { 
                RemoveHandler(InkCanvas.StrokeErasedEvent, value);
            } 
        } 

        ///  
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event.
        /// 
        /// EventArgs to raise the event with 
        protected virtual void OnStrokeErased(RoutedEventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null ) 
            {
                throw new ArgumentNullException("e");
            }
            RaiseEvent(e); 
        }
 
        ///  
        /// Allows the EditingBehaviors to raise the InkErasing event via the protected virtual
        ///  
        internal void RaiseInkErased()
        {
            this.OnStrokeErased(
                new RoutedEventArgs(InkCanvas.StrokeErasedEvent, this)); 
        }
 
        ///  
        /// Occurs when the user has resized the selection, after they lift their stylus to commit the change.
        /// This event allows the developer to cancel the resize. 
        /// 
        public event  InkCanvasSelectionEditingEventHandler SelectionResizing;
        /// 
        /// Protected virtual version for developers deriving from InkCanvas. 
        /// This method is what actually throws the event.
        ///  
        ///  InkCanvasSelectionEditingEventArgs to raise the event with 
        protected virtual void OnSelectionResizing( InkCanvasSelectionEditingEventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free.

            if ( e == null )
            { 
                throw new ArgumentNullException("e");
            } 
            if (null != SelectionResizing) 
            {
                SelectionResizing(this, e); 
            }
        }

        ///  
        /// Allows the EditingBehaviors to raise the SelectionResizing event via the protected virtual
        ///  
        ///  InkCanvasSelectionEditingEventArgs to raise the event with 
        internal void RaiseSelectionResizing( InkCanvasSelectionEditingEventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null");
            this.OnSelectionResizing(e);
        }
 
        /// 
        /// Occurs when the selection has been resized via UI interaction. 
        ///  
        public event EventHandler SelectionResized;
        ///  
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event.
        /// 
        /// EventArgs to raise the event with 
        protected virtual void OnSelectionResized(EventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free. 

            if ( e == null ) 
            {
                throw new ArgumentNullException("e");
            }
            if (null != SelectionResized) 
            {
                SelectionResized(this, e); 
            } 
        }
 
        /// 
        /// Allows the EditingBehaviors to raise the SelectionResized event via the protected virtual
        /// 
        /// EventArgs to raise the event with 
        internal void RaiseSelectionResized(EventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null"); 

            this.OnSelectionResized(e); 
            // Update the cursor of SelectionEditor behavior.
            EditingCoordinator.SelectionEditor.OnInkCanvasSelectionChanged();
        }
 
        /// 
        /// Occurs when the selection has been changed, either using the lasso or programmatically. 
        /// This event allows the developer to cancel the change. 
        /// 
        public event InkCanvasSelectionChangingEventHandler SelectionChanging; 
        /// 
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event.
        ///  
        /// InkCanvasSelectionChangingEventArgs to raise the event with
        protected virtual void OnSelectionChanging(InkCanvasSelectionChangingEventArgs e) 
        { 
            // No need to invoke VerifyAccess since this method is thread free.
 
            if ( e == null )
            {
                throw new ArgumentNullException("e");
            } 
            if (null != SelectionChanging)
            { 
                SelectionChanging(this, e); 
            }
        } 

        /// 
        /// Allows the EditingBehaviors to raise the SelectionChanging event via the protected virtual
        ///  
        /// InkCanvasSelectionChangingEventArgs to raise the event with
        private void RaiseSelectionChanging(InkCanvasSelectionChangingEventArgs e) 
        { 
            Debug.Assert(e != null, "EventArg can not be null");
            this.OnSelectionChanging(e); 
        }

        /// 
        /// Occurs when the selection has been changed 
        /// 
        public event EventHandler SelectionChanged; 
        ///  
        /// Protected virtual version for developers deriving from InkCanvas.
        /// This method is what actually throws the event. 
        /// 
        /// EventArgs to raise the event with
        protected virtual void OnSelectionChanged(EventArgs e)
        { 
            // No need to invoke VerifyAccess since this method is thread free.
 
            if ( e == null ) 
            {
                throw new ArgumentNullException("e"); 
            }
            if (null != SelectionChanged)
            {
                SelectionChanged(this, e); 
            }
        } 
 
        /// 
        /// Allows the EditingBehaviors to raise the SelectionChanged event via the protected virtual 
        /// 
        /// EventArgs to raise the event with
        internal void RaiseSelectionChanged(EventArgs e)
        { 
            Debug.Assert(e != null, "EventArg can not be null");
 
            this.OnSelectionChanged(e); 
            // Update the cursor of SelectionEditor behavior.
            EditingCoordinator.SelectionEditor.OnInkCanvasSelectionChanged(); 
        }

        /// 
        /// The InkCanvas uses an inner Canvas to host children.  When the inner Canvas's children 
        /// are changed, we need to call the protected virtual OnVisualChildrenChanged on the InkCanvas
        /// so that subclasses can be notified 
        ///  
        internal void RaiseOnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
        { 
            this.OnVisualChildrenChanged(visualAdded, visualRemoved);
        }

        #endregion Public Events 

        #region Public Methods 
 
        /// 
        /// Returns the enabled gestures.  This method throws an exception if GestureRecognizerAvailable 
        /// is false
        /// 
        /// 
        public ReadOnlyCollection GetEnabledGestures() 
        {
            // No need to invoke VerifyAccess since it's checked in GestureRecognizer.GetEnabledGestures. 
 
            //gestureRecognizer throws appropriately if there is no gesture recognizer available
            return new ReadOnlyCollection(this.GestureRecognizer.GetEnabledGestures()); 
        }

        /// 
        /// Sets the enabled gestures.  This method throws an exception if GestureRecognizerAvailable 
        /// is false
        ///  
        ///  
        public void SetEnabledGestures(IEnumerable applicationGestures)
        { 
            // No need to invoke VerifyAccess since it's checked in GestureRecognizer.GetEnabledGestures.

            //gestureRecognizer throws appropriately if there is no gesture recognizer available
            this.GestureRecognizer.SetEnabledGestures(applicationGestures); 
        }
 
        ///  
        /// Get the selection bounds.
        ///  
        /// 
        public Rect GetSelectionBounds()
        {
            VerifyAccess(); 

            return InkCanvasSelection.SelectionBounds; 
        } 

        ///  
        /// provides access to the currently selected elements which are children of this InkCanvas
        /// 
        public ReadOnlyCollection GetSelectedElements()
        { 
            VerifyAccess();
            return InkCanvasSelection.SelectedElements; 
        } 

        ///  
        /// provides read access to the currently selected strokes
        /// 
        public StrokeCollection GetSelectedStrokes()
        { 
            VerifyAccess();
 
            StrokeCollection sc = new StrokeCollection(); 
            sc.Add(InkCanvasSelection.SelectedStrokes);
            return sc; 
        }

        /// 
        /// Overload which calls the more complex version, passing null for selectedElements 
        /// 
        /// The strokes to select 
        public void Select(StrokeCollection selectedStrokes) 
        {
            // No need to invoke VerifyAccess since this call is forwarded. 
            Select(selectedStrokes, null);
        }

        ///  
        /// Overload which calls the more complex version, passing null for selectedStrokes
        ///  
        /// The elements to select 
        public void Select(IEnumerable selectedElements)
        { 
            // No need to invoke VerifyAccess since this call is forwarded.
            Select(null, selectedElements);
        }
 
        /// 
        /// Overload which calls the more complex version, passing null for selectedStrokes 
        ///  
        /// The strokes to select
        /// The elements to select 
        public void Select(StrokeCollection selectedStrokes, IEnumerable selectedElements)
        {
            VerifyAccess();
 
            // NTRAID-WINDOWS#1134932-2005/12/01-WAYNEZEN
            // Try to switch to Select mode first. If we fail to change the mode, then just simply no-op. 
            if ( EnsureActiveEditingMode(InkCanvasEditingMode.Select) ) 
            {
                // 
                // validate
                //
                UIElement[] validElements = ValidateSelectedElements(selectedElements);
                StrokeCollection validStrokes = ValidateSelectedStrokes(selectedStrokes); 

                // 
                // this will raise the 'SelectionChanging' event ONLY if the selection 
                // is actually different
                // 
                ChangeInkCanvasSelection(validStrokes, validElements);
            }
        }
 
        /// 
        /// Hit test on the selection 
        ///  
        /// 
        ///  
        public InkCanvasSelectionHitResult HitTestSelection(Point point)
        {
            VerifyAccess();
 
            // Ensure the visual tree.
            if ( _localAdornerDecorator == null ) 
            { 
                ApplyTemplate();
            } 

            return InkCanvasSelection.HitTestSelection(point);
        }
 
        /// 
        /// Copy the current selection in the InkCanvas to the clipboard 
        ///  
        public void CopySelection()
        { 
            VerifyAccess();
            PrivateCopySelection();
        }
 
        /// 
        /// Copy the current selection in the InkCanvas to the clipboard and then delete it 
        ///  
        public void CutSelection()
        { 
            VerifyAccess();

            // Copy first
            InkCanvasClipboardDataFormats copiedDataFormats = PrivateCopySelection(); 

            // Don't even bother if we don't have a selection. 
            if ( copiedDataFormats != InkCanvasClipboardDataFormats.None ) 
            {
                // Then delete the current selection. Note the XAML format won't be avaliable under Partial 
                // Trust. So, the selected element shouldn't be copied or removed.
                DeleteCurrentSelection(
                    /* We want to delete the selected Strokes if there is ISF and/or XAML data being copied */
                    (copiedDataFormats & 
                        (InkCanvasClipboardDataFormats.ISF | InkCanvasClipboardDataFormats.XAML)) != 0,
                    /* We only want to delete the selected elements if there is XAML data being copied */ 
                    (copiedDataFormats & InkCanvasClipboardDataFormats.XAML) != 0); 
            }
        } 

        /// 
        /// Paste the contents of the clipboard into the InkCanvas
        ///  
        public void Paste()
        { 
            // No need to call VerifyAccess since this call is forwarded. 

            // We always paste the data to the default location which is (0,0). 
            Paste(new Point(c_pasteDefaultLocation, c_pasteDefaultLocation));
        }

        ///  
        /// Paste the contents of the clipboard to the specified location in the InkCanvas
        ///  
        public void Paste(Point point) 
        {
            VerifyAccess(); 

            if (DoubleUtil.IsNaN(point.X) ||
                DoubleUtil.IsNaN(point.Y) ||
                Double.IsInfinity(point.X)|| 
                Double.IsInfinity(point.Y) )
            { 
                    throw new ArgumentException(SR.Get(SRID.InvalidPoint), "point"); 
            }
 

            //
            // only do this if the user is not editing (input active)
            // or we will violate a dispatcher lock 
            //
            if (!_editingCoordinator.UserIsEditing) 
            { 
                IDataObject dataObj = null;
                try 
                {
                    dataObj = Clipboard.GetDataObject();
                }
                catch (ExternalException) 
                {
                    //harden against ExternalException 
                    return; 
                }
                if (dataObj != null) 
                {
                    PasteFromDataObject(dataObj, point);
                }
            } 
        }
 
        ///  
        /// Return true if clipboard contents can be pasted into the InkCanvas.
        ///  
        public bool CanPaste()
        {
            VerifyAccess();
 
            bool ret = false;
            // 
            // can't paste if the user is editing (input active) 
            // or we will violate a dispatcher lock
            // 
            if (_editingCoordinator.UserIsEditing)
            {
                return false;
            } 

            // Check whether the caller has the clipboard permission. 
            if ( !SecurityHelper.CallerHasAllClipboardPermission() ) 
            {
                return false; 
            }

            ret = PrivateCanPaste();
 
            return ret;
        } 
 
        #endregion Public Methods
 
        //-----------------------------------------------------
        //
        //  IAddChild Interface
        // 
        //-----------------------------------------------------
 
        #region IAddChild Interface 

        /// 
        /// Called to Add the object as a Child.
        ///
        ///
        /// Object to add as a child 
        ///
        void IAddChild.AddChild(Object value) 
        { 
            //             VerifyAccess();
 
            if ( value == null )
            {
                throw new ArgumentNullException("value");
            } 

            ( (IAddChild)InnerCanvas ).AddChild(value); 
        } 

        /// 
        /// Called when text appears under the tag in markup.
        ///
        ///
        /// Text to Add to the Canvas 
        ///
        void IAddChild.AddText(string textData) 
        { 
            //             VerifyAccess();
 
            ( (IAddChild)InnerCanvas ).AddText(textData);
        }

        #endregion IAddChild Interface 

        //------------------------------------------------------ 
        // 
        //  Protected Properties
        // 
        //-----------------------------------------------------

        #region Protected Properties
 
        /// 
        /// Returns enumerator to logical children. 
        ///  
        protected internal override IEnumerator LogicalChildren
        { 
            get
            {
                //        VerifyAccess( );
 
                // Return the private logical children of the InnerCanvas
                return ( (InkCanvasInnerCanvas)InnerCanvas).PrivateLogicalChildren; 
            } 
        }
 
        /// 
        /// Protected DynamicRenderer property.
        /// 
        protected DynamicRenderer DynamicRenderer 
        {
            get 
            { 
                VerifyAccess();
                return InternalDynamicRenderer; 
            }
            set
            {
                VerifyAccess(); 
                if (!object.ReferenceEquals(value, _dynamicRenderer))
                { 
                    int previousIndex = -1; 
                    //remove the existing plugin
                    if (_dynamicRenderer != null) 
                    {
                        //remove the plugin from the collection
                        previousIndex = this.StylusPlugIns.IndexOf(_dynamicRenderer);
                        if (-1 != previousIndex) 
                        {
                            this.StylusPlugIns.RemoveAt(previousIndex); 
                        } 

                        //remove the plugin's visual from the InkPresenter 
                        if (this.InkPresenter.ContainsAttachedVisual(_dynamicRenderer.RootVisual))
                        {
                            this.InkPresenter.DetachVisuals(_dynamicRenderer.RootVisual);
                        } 
                    }
 
                    _dynamicRenderer = value; 

                    if (_dynamicRenderer != null) //null is acceptable 
                    {
                        //remove the plugin from the collection
                        if (!this.StylusPlugIns.Contains(_dynamicRenderer))
                        { 
                            if (-1 != previousIndex)
                            { 
                                //insert the new DR in the same location as the old one 
                                this.StylusPlugIns.Insert(previousIndex, _dynamicRenderer);
                            } 
                            else
                            {
                                this.StylusPlugIns.Add(_dynamicRenderer);
                            } 
                        }
 
                        //refer to the same DrawingAttributes as the InkCanvas 
                        _dynamicRenderer.DrawingAttributes = this.DefaultDrawingAttributes;
 
                        //attach the DynamicRenderer if it is not already
                        if (!(this.InkPresenter.ContainsAttachedVisual(_dynamicRenderer.RootVisual)) &&
                            _dynamicRenderer.Enabled &&
                            _dynamicRenderer.RootVisual != null) 
                        {
                            this.InkPresenter.AttachVisuals(_dynamicRenderer.RootVisual, this.DefaultDrawingAttributes); 
                        } 
                    }
                } 
            }
        }

        ///  
        /// Protected read only access to the InkPresenter this InkCanvas uses
        ///  
        protected InkPresenter InkPresenter 
        {
            get 
            {
                VerifyAccess();
                if ( _inkPresenter == null )
                { 
                    _inkPresenter = new InkPresenter();
 
                    // Bind the InkPresenter.Strokes to InkCanvas.Strokes 
                    Binding strokes = new Binding();
                    strokes.Path = new PropertyPath(InkCanvas.StrokesProperty); 
                    strokes.Mode = BindingMode.OneWay;
                    strokes.Source = this;
                    _inkPresenter.SetBinding(InkPresenter.StrokesProperty, strokes);
 
                }
                return _inkPresenter; 
            } 
        }
 
        #endregion Protected Properties

        #region Internal Properties / Methods
 

        ///  
        /// Deselect the current selection 
        /// 
        internal static readonly RoutedCommand DeselectCommand = new RoutedCommand("Deselect", typeof(InkCanvas)); 

        /// 
        /// UserInitiatedCanPaste
        ///  
        /// 
        ///  
        ///     Critical -      Elevates the AllClipboard permission for checking the supported data in InkCanvas. 
        /// 
        [SecurityCritical] 
        private bool UserInitiatedCanPaste()
        {
            ( new UIPermission(UIPermissionClipboard.AllClipboard) ).Assert();//BlessedAssert
            try 
            {
                return PrivateCanPaste(); 
            } 
            finally
            { 
                UIPermission.RevertAssert();
            }

        } 

        ///  
        /// PrivateCanPaste 
        /// 
        ///  
        private bool PrivateCanPaste()
        {
            bool canPaste = false;
            IDataObject dataObj = null; 
            try
            { 
                dataObj = Clipboard.GetDataObject(); 
            }
            catch (ExternalException) 
            {
                //harden against ExternalException
                return false;
            } 
            if ( dataObj != null )
            { 
                canPaste = ClipboardProcessor.CheckDataFormats(dataObj); 
            }
 
            return canPaste;
        }

        ///  
        /// This method pastes data from an IDataObject object
        ///  
        internal void PasteFromDataObject(IDataObject dataObj, Point point) 
        {
            // Reset the current selection 
            ClearSelection(false);

            // Assume that there is nothing to be selected.
            StrokeCollection newStrokes = new StrokeCollection(); 
            List newElements = new List();
 
            // Paste the data from the data object. 
            if ( !ClipboardProcessor.PasteData(dataObj, ref newStrokes, ref newElements) )
            { 
                // Paste was failed.
                return;
            }
            else if ( newStrokes.Count == 0 && newElements.Count == 0 ) 
            {
                // Nothing has been received from the clipboard. 
                return; 
            }
 
            // We add elements here. Then we have to wait for the layout update.
            UIElementCollection children = Children;
            foreach ( UIElement element in newElements )
            { 
                children.Add(element);
            } 
 
            if ( newStrokes != null )
            { 
                Strokes.Add(newStrokes);
            }

            try 
            {
                // We should fire SelectionChanged event if the current editing mode is Select. 
                CoreChangeSelection(newStrokes, newElements.ToArray(), EditingMode == InkCanvasEditingMode.Select); 
            }
            finally 
            {
                // Now move the selection to the desired location.
                Rect bounds = GetSelectionBounds( );
                InkCanvasSelection.CommitChanges(Rect.Offset(bounds, -bounds.Left + point.X, -bounds.Top + point.Y), false); 

                if (EditingMode != InkCanvasEditingMode.Select) 
                { 
                    // Clear the selection without the event if the editing mode is not Select.
                    ClearSelection(false); 
                }
            }
        }
 
        /// 
        /// Copies the InkCanvas contents to a DataObject and returns it to the caller. 
        ///  Can return NULL for DataObject. 
        /// 
        ///  
        ///     Critical: Clipboard.SetDataObject will invoke DataObject.DataStore.GetFormats.
        ///                 The methods demands SerializationPermission. We perform the elevation before
        ///                 calling SetDataObject.
        ///     TreatAsSafe: There is no input here. The ISF data are safe to being put in the clipboard. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private InkCanvasClipboardDataFormats CopyToDataObject() 
        {
             DataObject dataObj; 
            (new UIPermission(UIPermissionClipboard.AllClipboard)).Assert();//BlessedAssert
            try
            {
                dataObj = new DataObject(); 
            }
            finally 
            { 
                UIPermission.RevertAssert();
            } 
            InkCanvasClipboardDataFormats copiedDataFormats = InkCanvasClipboardDataFormats.None;

            // Try to copy the data from the InkCanvas to the clipboard.
            copiedDataFormats = ClipboardProcessor.CopySelectedData(dataObj); 

            if ( copiedDataFormats != InkCanvasClipboardDataFormats.None ) 
            { 
                PermissionSet ps = new PermissionSet(PermissionState.None);
                ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter)); 
                ps.AddPermission(new UIPermission(UIPermissionClipboard.AllClipboard));
                ps.Assert(); // BlessedAssert
                try
                { 
                    // Put our data object into the clipboard.
                    Clipboard.SetDataObject(dataObj, true); 
                } 
                finally
                { 
                    SecurityPermission.RevertAssert();
                }
            }
 
            return copiedDataFormats;
        } 
 
        /// 
        /// Read-only property of the associated EditingCoordinator. 
        /// 
        internal EditingCoordinator EditingCoordinator
        {
            get 
            {
                return _editingCoordinator; 
            } 
        }
 
        /// 
        /// Internal access to the protected DynamicRenderer.  Can be null.
        /// 
        internal DynamicRenderer InternalDynamicRenderer 
        {
            get 
            { 
                return _dynamicRenderer;
            } 
        }

        /// 
        /// Return the inner Canvas. 
        /// 
        internal InkCanvasInnerCanvas InnerCanvas 
        { 
            get
            { 
                // We have to create our visual at this point.
                if (_innerCanvas == null)
                {
                    // Create our InnerCanvas to change the logical parent of Canvas' children. 
                    _innerCanvas = new InkCanvasInnerCanvas(this);
 
                    // Bind the inner Canvas' Background to InkCanvas' Background 
                    Binding background = new Binding();
                    background.Path = new PropertyPath(InkCanvas.BackgroundProperty); 
                    background.Mode = BindingMode.OneWay;
                    background.Source = this;
                    _innerCanvas.SetBinding(Panel.BackgroundProperty, background);
                } 

                return _innerCanvas; 
            } 
        }
 
        /// 
        /// Internal access to the current selection
        /// 
        internal InkCanvasSelection InkCanvasSelection 
        {
            get 
            { 
                if ( _selection == null )
                { 
                    _selection = new InkCanvasSelection(this);
                }

                return _selection; 
            }
        } 
 

        ///  
        /// Internal helper called by the LassoSelectionBehavior
        /// 
        internal void BeginDynamicSelection(Visual visual)
        { 
            EditingCoordinator.DebugCheckActiveBehavior(EditingCoordinator.LassoSelectionBehavior);
 
            _dynamicallySelectedStrokes = new StrokeCollection(); 

            InkPresenter.AttachVisuals(visual, new DrawingAttributes()); 
        }

        /// 
        /// Internal helper called by LassoSelectionBehavior to update the display 
        /// of dynamically added strokes
        ///  
        internal void UpdateDynamicSelection(   StrokeCollection strokesToDynamicallySelect, 
                                                StrokeCollection strokesToDynamicallyUnselect)
        { 
            EditingCoordinator.DebugCheckActiveBehavior(EditingCoordinator.LassoSelectionBehavior);

            //
            // update our internal stroke collections used by dynamic selection 
            //
            if (strokesToDynamicallySelect != null) 
            { 
                foreach (Stroke s in strokesToDynamicallySelect)
                { 
                    _dynamicallySelectedStrokes.Add(s);
                    s.IsSelected = true;
                }
            } 

            if (strokesToDynamicallyUnselect != null) 
            { 
                foreach (Stroke s in strokesToDynamicallyUnselect)
                { 
                    System.Diagnostics.Debug.Assert(_dynamicallySelectedStrokes.Contains(s));
                    _dynamicallySelectedStrokes.Remove(s);
                    s.IsSelected = false;
                } 
            }
        } 
 
        /// 
        /// Internal helper used by LassoSelectionBehavior 
        /// 
        internal StrokeCollection EndDynamicSelection(Visual visual)
        {
            EditingCoordinator.DebugCheckActiveBehavior(EditingCoordinator.LassoSelectionBehavior); 

            InkPresenter.DetachVisuals(visual); 
 
            StrokeCollection selectedStrokes = _dynamicallySelectedStrokes;
            _dynamicallySelectedStrokes = null; 

            return selectedStrokes;
        }
 
        /// 
        /// Clears the selection in the ink canvas 
        /// and returns a bool indicating if the selection was actually cleared 
        /// (developers can cancel selectionchanging)
        /// 
        /// If the InkCanvas has no selection, selectionchanging is not raised
        /// and this method returns true
        ///
        /// used by InkEditor during editing operations 
        /// 
        /// true if selection was cleared even after raising selectionchanging 
        internal bool ClearSelectionRaiseSelectionChanging() 
        {
            if ( !InkCanvasSelection.HasSelection ) 
            {
                return true;
            }
 
            //
            // attempt to clear selection 
            // 
            ChangeInkCanvasSelection(new StrokeCollection(), new UIElement[]{});
 
            return !InkCanvasSelection.HasSelection;
        }

        ///  
        /// ClearSelection
        ///     Called by: 
        ///         PasteFromDataObject 
        ///         EditingCoordinator.UpdateEditingState
        ///  
        internal void ClearSelection(bool raiseSelectionChangedEvent)
        {
            if ( InkCanvasSelection.HasSelection )
            { 
                // Reset the current selection
                CoreChangeSelection(new StrokeCollection(), new UIElement[] { }, raiseSelectionChangedEvent); 
            } 
        }
 

        /// 
        /// Helper that creates selection for an InkCanvas.  Used by the SelectedStrokes and
        /// SelectedElements properties 
        /// 
        internal void ChangeInkCanvasSelection(StrokeCollection strokes, UIElement[] elements) 
        { 
            //validate in debug only for this internal static
            Debug.Assert(strokes != null 
                        && elements != null,
                        "Invalid arguments in ChangeInkCanvasSelection");

            bool strokesAreDifferent; 
            bool elementsAreDifferent;
            InkCanvasSelection.SelectionIsDifferentThanCurrent(strokes, out strokesAreDifferent, elements, out elementsAreDifferent); 
            if ( strokesAreDifferent || elementsAreDifferent ) 
            {
                InkCanvasSelectionChangingEventArgs args = new InkCanvasSelectionChangingEventArgs(strokes, elements); 

                StrokeCollection validStrokes = strokes;
                UIElement[] validElements = elements;
 
                this.RaiseSelectionChanging(args);
 
                //now that the event has been raised and all of the delegates 
                //have had their way with it, process the result
                if ( !args.Cancel ) 
                {

                    //
                    // rock and roll, time to validate our arguments 
                    // note: these event args are visible outside the apis,
                    // so we need to validate them again 
                    // 

                    // PERF-2006/05/02-WAYNEZEN, 
                    // Check our internal flag. If the SelectedStrokes has been changed, we shouldn't do any extra work here.
                    if ( args.StrokesChanged )
                    {
                        validStrokes = ValidateSelectedStrokes(args.GetSelectedStrokes()); 
                        int countOldSelectedStrokes = strokes.Count;
                        for ( int i = 0; i < countOldSelectedStrokes; i++ ) 
                        { 
                            // PERF-2006/05/02-WAYNEZEN,
                            // We only have to reset IsSelected for the elements no longer exists in the new collection. 
                            if ( !validStrokes.Contains(strokes[i]) )
                            {
                                // NTRAID#WINDOWS-1045099-2006/05/02-waynezen,
                                // Make sure we reset the IsSelected property which could have been 
                                // set to true in the dynamic selection.
                                strokes[i].IsSelected = false; 
                            } 
                        }
                    } 


                    // PERF-2006/05/02-WAYNEZEN,
                    // Check our internal flag. If the SelectedElements has been changed, we shouldn't do any extra work here. 
                    if ( args.ElementsChanged )
                    { 
                        validElements = ValidateSelectedElements(args.GetSelectedElements()); 
                    }
 
                    CoreChangeSelection(validStrokes, validElements, true);
                }
                else
                { 
                    StrokeCollection currentSelectedStrokes = InkCanvasSelection.SelectedStrokes;
                    int countOldSelectedStrokes = strokes.Count; 
                    for ( int i = 0; i < countOldSelectedStrokes; i++ ) 
                    {
                        // Make sure we reset the IsSelected property which could have been 
                        // set to true in the dynamic selection but not being selected previously.
                        if ( !currentSelectedStrokes.Contains(strokes[i]) )
                        {
                            strokes[i].IsSelected = false; 
                        }
                    } 
                } 
            }
        } 


        /// 
        /// Helper method used by ChangeInkCanvasSelection and directly by ClearSelectionWithoutSelectionChanging 
        /// 
        /// validStrokes 
        /// validElements 
        /// raiseSelectionChanged
        private void CoreChangeSelection(StrokeCollection validStrokes, IList validElements, bool raiseSelectionChanged) 
        {
            InkCanvasSelection.Select(validStrokes, validElements, raiseSelectionChanged);
        }
 
#if DEBUG_LASSO_FEEDBACK
        internal ContainerVisual RendererRootContainer 
        { 
            get {return _inkContainerVisual;}
        } 
#endif


        ///  
        /// Private helper method used to retrieve a StrokeCollection which does AND operation on two input collections.
        ///  
        /// The possible subset 
        /// The container set
        /// True if subset is a subset of superset, false otherwise 
        internal static StrokeCollection GetValidStrokes(StrokeCollection subset, StrokeCollection superset)
        {
            StrokeCollection validStrokes = new StrokeCollection();
 
            int subsetCount = subset.Count;
 
            // special case an empty subset as a guaranteed subset 
            if ( subsetCount == 0 )
            { 
                return validStrokes;
            }

            for ( int i = 0; i < subsetCount; i++ ) 
            {
                Stroke stroke = subset[i]; 
                if ( superset.Contains(stroke) ) 
                {
                    validStrokes.Add(stroke); 
                }
            }

            return validStrokes; 
        }
 
        ///  
        /// Register the commanding handlers for the clipboard operations
        ///  
        /// 
        ///     Critical: Elevates to associate a protected command (paste) with keyboard
        ///     TreatAsSafe: We don't take user input here. Shift+Insert is the correct key binding,
        ///                  and therefore is expected by the user. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private static void _RegisterClipboardHandlers() 
        {
            Type ownerType = typeof(InkCanvas); 

            CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.Cut,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled),
                SRID.KeyShiftDelete, SRID.KeyShiftDeleteDisplayString); 
            CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.Copy,
                new ExecutedRoutedEventHandler(_OnCommandExecuted), new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled), 
                SRID.KeyCtrlInsert, SRID.KeyCtrlInsertDisplayString); 

            // Use temp variables to reduce code under elevation 
            ExecutedRoutedEventHandler pasteExecuteEventHandler = new ExecutedRoutedEventHandler(_OnCommandExecuted);
            CanExecuteRoutedEventHandler pasteQueryEnabledEventHandler = new CanExecuteRoutedEventHandler(_OnQueryCommandEnabled);
            InputGesture pasteInputGesture = KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyShiftInsert), SR.Get(SRID.KeyShiftInsertDisplayString));
 
            new UIPermission(UIPermissionClipboard.AllClipboard).Assert(); // BlessedAssert:
            try 
            { 
                CommandHelpers.RegisterCommandHandler(ownerType, ApplicationCommands.Paste,
                    pasteExecuteEventHandler, pasteQueryEnabledEventHandler, pasteInputGesture); 
            }
            finally
            {
                CodeAccessPermission.RevertAssert(); 
            }
        } 
 
        /// 
        /// Private helper used to ensure that any stroke collection 
        /// passed to the InkCanvas is valid.  Throws exceptions if the argument is invalid
        /// 
        private StrokeCollection ValidateSelectedStrokes(StrokeCollection strokes)
        { 
            //
            //  null is a valid input 
            // 
            if (strokes == null)
            { 
                return new StrokeCollection();
            }
            else
            { 
                return GetValidStrokes(strokes, this.Strokes);
            } 
        } 

        ///  
        /// Private helper used to ensure that a UIElement argument passed in
        /// is valid.
        /// 
        private UIElement[] ValidateSelectedElements(IEnumerable selectedElements) 
        {
            if (selectedElements == null) 
            { 
                return new UIElement[]{};
            } 

            List elements = new List();
            foreach (UIElement element in selectedElements)
            { 
                // NTRAID:WINDOWSOS#1621480-2006/04/26-WAYNEZEN,
                // Don't add the duplicated element. 
                if ( !elements.Contains(element) ) 
                {
                    // 
                    // check the common case first, e
                    //
                    if ( InkCanvasIsAncestorOf(element) )
                    { 
                        elements.Add(element);
                    } 
                } 
            }
 
            return elements.ToArray();
        }

        ///  
        /// Helper method used by DesignActivation to see if an element
        /// has this InkCanvas as an Ancestor 
        ///  
        private bool InkCanvasIsAncestorOf(UIElement element)
        { 
            if (this != element && this.IsAncestorOf(element))
            {
                return true;
            } 
            return false;
        } 
 
        /// 
        /// Handler called whenever changes are made to properties of the DefaultDrawingAttributes 
        /// 
        /// 
        /// 
        /// For example, when a developer changes the Color property on the DefaultDrawingAttributes, 
        /// this event will fire - allowing the InkCanvas a chance to notify the BasicRTI Service.
        /// Also - we do not currently call through the DefaultDrawingAttributes setter since 
        /// parameter validation in the setter may detect if the reference isn't changing, and ignore 
        /// the call. Also - there is no need for extra parameter validation.
        private void DefaultDrawingAttributes_Changed(object sender, PropertyDataChangedEventArgs args) 
        {
            // note that sender should be the same as _defaultDrawingAttributes
            // If a developer writes code to change the DefaultDrawingAttributes inside of the event
            //      handler before the InkCanvas receives the notification (multi-cast delegate scenario) - 
            //      The DefaultDrawingAttributes should still be updated, and in that case we would
            //      update the RTI DAC twice. Typically, however, this will just refresh the 
            //      attributes in the RTI thread. 
            System.Diagnostics.Debug.Assert(object.ReferenceEquals(sender, DefaultDrawingAttributes));
 
            InvalidateSubProperty(DefaultDrawingAttributesProperty);

            // Be sure to update the RealTimeInking PlugIn with the drawing attribute changes.
            UpdateDynamicRenderer(); 

            // Invalidate the inking cursor 
            _editingCoordinator.InvalidateBehaviorCursor(_editingCoordinator.InkCollectionBehavior); 
        }
 
        /// 
        /// Helper method used to set up the DynamicRenderer.
        /// 
        internal void UpdateDynamicRenderer() 
        {
            UpdateDynamicRenderer(DefaultDrawingAttributes); 
        } 
        /// 
        /// Helper method used to set up the DynamicRenderer. 
        /// 
        private void UpdateDynamicRenderer(DrawingAttributes newDrawingAttributes)
        {
            ApplyTemplate(); 

            if (this.DynamicRenderer != null) 
            { 
                this.DynamicRenderer.DrawingAttributes = newDrawingAttributes;
 
                if (!this.InkPresenter.AttachedVisualIsPositionedCorrectly(this.DynamicRenderer.RootVisual, newDrawingAttributes))
                {
                    if (this.InkPresenter.ContainsAttachedVisual(this.DynamicRenderer.RootVisual))
                    { 
                        this.InkPresenter.DetachVisuals(this.DynamicRenderer.RootVisual);
                    } 
 
                    // Only hook up if we are enabled.  As we change editing modes this routine will be called
                    // to clean up things. 
                    if (this.DynamicRenderer.Enabled && this.DynamicRenderer.RootVisual != null)
                    {
                        this.InkPresenter.AttachVisuals(this.DynamicRenderer.RootVisual, newDrawingAttributes);
                    } 
                }
            } 
        } 

        private bool EnsureActiveEditingMode(InkCanvasEditingMode newEditingMode) 
        {
            bool ret = true;

            if ( ActiveEditingMode != newEditingMode ) 
            {
                if ( EditingCoordinator.IsStylusInverted ) 
                { 
                    EditingModeInverted = newEditingMode;
                } 
                else
                {
                    EditingMode = newEditingMode;
                } 

                // Verify whether user has cancelled the change in EditingModeChanging event. 
                ret = ( ActiveEditingMode == newEditingMode ); 
            }
 
            return ret;
        }

        // The ClipboardProcessor instance which deals with the operations relevant to the clipboard. 
        private ClipboardProcessor ClipboardProcessor
        { 
            get 
            {
                if ( _clipboardProcessor == null ) 
                {
                    _clipboardProcessor = new ClipboardProcessor(this);
                }
 
                return _clipboardProcessor;
            } 
        } 

        //lazy instance the gesture recognizer 
        private GestureRecognizer GestureRecognizer
        {
            get
            { 
                if (_gestureRecognizer == null)
                { 
                    _gestureRecognizer = new GestureRecognizer(); 
                }
                return _gestureRecognizer; 
            }
        }

        ///  
        /// Delete the current selection
        ///  
        private void DeleteCurrentSelection(bool removeSelectedStrokes, bool removeSelectedElements) 
        {
            Debug.Assert(removeSelectedStrokes || removeSelectedElements, "At least either Strokes or Elements should be removed!"); 

            // Now delete the current selection.
            StrokeCollection strokes = GetSelectedStrokes();
            IList elements = GetSelectedElements(); 

            // Clear the selection first. 
            CoreChangeSelection( 
                removeSelectedStrokes ? new StrokeCollection() : strokes,
                removeSelectedElements ? new List() : elements, 
                true);

            // Remove the ink.
            if ( removeSelectedStrokes && strokes != null && strokes.Count != 0 ) 
            {
                Strokes.Remove(strokes); 
            } 

            // Remove the elements. 
            if ( removeSelectedElements )
            {
                UIElementCollection children = Children;
                foreach ( UIElement element in elements ) 
                {
                    children.Remove(element); 
                } 
            }
        } 

        /// 
        /// A class handler of the Commands
        ///  
        /// 
        ///  
        private static void _OnCommandExecuted(object sender, ExecutedRoutedEventArgs args) 
        {
            ICommand command = args.Command; 
            InkCanvas inkCanvas = sender as InkCanvas;

            Debug.Assert(inkCanvas != null);
 
            if ( inkCanvas.IsEnabled && !inkCanvas.EditingCoordinator.UserIsEditing )
            { 
                if ( command == ApplicationCommands.Delete ) 
                {
                    inkCanvas.DeleteCurrentSelection(true, true); 
                }
                else if ( command == ApplicationCommands.Cut )
                {
                    inkCanvas.CutSelection(); 
                }
                else if ( command == ApplicationCommands.Copy ) 
                { 
                    inkCanvas.CopySelection();
                } 
                else if ( command == ApplicationCommands.SelectAll )
                {
                    if ( inkCanvas.ActiveEditingMode == InkCanvasEditingMode.Select )
                    { 
                        IEnumerable children = null;
                        UIElementCollection uiElementCollection = inkCanvas.Children; 
                        if ( uiElementCollection.Count > 0 ) 
                        {
                            //UIElementCollection doesn't implement IEnumerable 
                            //for some reason
                            UIElement[] uiElementArray = new UIElement[uiElementCollection.Count];
                            for ( int i = 0; i < uiElementCollection.Count; i++ )
                            { 
                                uiElementArray[i] = uiElementCollection[i];
                            } 
                            children = uiElementArray; 
                        }
                        inkCanvas.Select(inkCanvas.Strokes, children); 
                    }
                }
                else if ( command == ApplicationCommands.Paste )
                { 
                    try
                    { 
                        inkCanvas.Paste(); 
                    }
                    // Eat it and do nothing if one of the following exceptions is caught. 
                    catch ( System.Runtime.InteropServices.COMException )
                    {
                        // The window may be destroyed which could cause the opening failed..
                    } 
                    catch ( XamlParseException )
                    { 
                        // The Xaml parser fails 
                    }
                    catch ( ArgumentException ) 
                    {
                        // The ISF decoder fails
                    }
                } 
                else if ( command == InkCanvas.DeselectCommand )
                { 
                    inkCanvas.ClearSelectionRaiseSelectionChanging(); 
                }
            } 
        }

        /// 
        /// A class handler for querying the enabled status of the commands. 
        /// 
        ///  
        ///  
        /// 
        ///     Critical -      Call into UserInitiatedCanPaste which is SecurityCritical. 
        ///     TreatAsSafe -   We check whether QueryCanPaste is initiated by user or not
        ///                     before invoking the critical method.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private static void _OnQueryCommandEnabled(object sender, CanExecuteRoutedEventArgs args)
        { 
            RoutedCommand command = (RoutedCommand)(args.Command); 
            InkCanvas inkCanvas = sender as InkCanvas;
 
            Debug.Assert(inkCanvas != null);

            if ( inkCanvas.IsEnabled
                // NTRAID-WINDOWSOS#1578484-2006/04/14-WAYNEZEN, 
                // If user is editing, we should disable all commands.
                && !inkCanvas.EditingCoordinator.UserIsEditing ) 
            { 
                if ( command == ApplicationCommands.Delete
                    || command == ApplicationCommands.Cut 
                    || command == ApplicationCommands.Copy
                    || command == InkCanvas.DeselectCommand )
                {
                    args.CanExecute = inkCanvas.InkCanvasSelection.HasSelection; 
                }
                else if ( command == ApplicationCommands.Paste ) 
                { 
                    try
                    { 
                        args.CanExecute = args.UserInitiated
                                            ? inkCanvas.UserInitiatedCanPaste() /* Call UserInitiatedCanPaste when the query is initiated by user */
                                            : inkCanvas.CanPaste() /* Call the public CanPaste if not */;
                    } 
                    catch ( System.Runtime.InteropServices.COMException )
                    { 
                        // The window may be destroyed which could cause the opening failed.. 
                        // Eat the exception and do nothing.
                        args.CanExecute = false; 
                    }
                }
                else if ( command == ApplicationCommands.SelectAll )
                { 
                    //anything to select?
                    args.CanExecute = ( inkCanvas.ActiveEditingMode == InkCanvasEditingMode.Select 
                                            && (inkCanvas.Strokes.Count > 0 || inkCanvas.Children.Count > 0)); 
                }
            } 
            else
            {
                // NTRAID:WINDOWSOS#1564508-2006/03/20-WAYNEZEN,
                // Return false for CanExecute if InkCanvas is disabled. 
                args.CanExecute = false;
            } 
 
            // NTRAID#WINDOWS-1371659-2005/11/08-waynezen,
            // Mark Handled as true so that the clipboard commands stops routing to InkCanvas' ancestors. 
            if ( command == ApplicationCommands.Cut || command == ApplicationCommands.Copy
                || command == ApplicationCommands.Paste )
            {
                args.Handled = true; 
            }
 
        } 

        private InkCanvasClipboardDataFormats PrivateCopySelection() 
        {
            InkCanvasClipboardDataFormats copiedDataFormats = InkCanvasClipboardDataFormats.None;

            // Don't even bother if we don't have a selection or UserIsEditing has been set. 
            if ( InkCanvasSelection.HasSelection && !_editingCoordinator.UserIsEditing)
            { 
                copiedDataFormats = CopyToDataObject(); 
            }
 
            return copiedDataFormats;
        }

 
        /// 
        /// _OnDeviceDown 
        ///  
        /// 
        ///  
        /// 
        private static void _OnDeviceDown(object sender, TEventArgs e)
            where TEventArgs : InputEventArgs
        { 
            ( (InkCanvas)sender ).EditingCoordinator.OnInkCanvasDeviceDown(sender, e);
        } 
 
        /// 
        /// _OnDeviceUp 
        /// 
        /// 
        /// 
        ///  
        private static void _OnDeviceUp(object sender, TEventArgs e)
            where TEventArgs : InputEventArgs 
        { 
            ((InkCanvas)sender).EditingCoordinator.OnInkCanvasDeviceUp(sender, e);
        } 

        /// 
        /// _OnQueryCursor
        ///  
        /// 
        ///  
        private static void _OnQueryCursor(object sender, QueryCursorEventArgs e) 
        {
            InkCanvas inkCanvas = (InkCanvas)sender; 

            if ( inkCanvas.UseCustomCursor )
            {
                // If UseCustomCursor is set, we bail out. Let the base class (FrameworkElement) to do the rest. 
                return;
            } 
 
            // We should behave like our base - honor ForceCursor property.
            if ( !e.Handled || inkCanvas.ForceCursor ) 
            {
                Cursor cursor = inkCanvas.EditingCoordinator.GetActiveBehaviorCursor();

                // If cursor is null, we don't handle the event and leave it as whatever the default is. 
                if ( cursor != null )
                { 
                    e.Cursor = cursor; 
                    e.Handled = true;
                } 
            }
        }

        ///  
        /// Update the current cursor if mouse is over InkCanvas. Called by
        ///     EditingCoordinator.InvalidateBehaviorCursor 
        ///     EditingCoordinator.UpdateEditingState 
        ///     InkCanvas.set_UseCustomCursor
        ///  
        internal void UpdateCursor()
        {
            if ( IsMouseOver )
            { 
                Mouse.UpdateCursor();
            } 
        } 

        #endregion Private Properties / Methods 

        //------------------------------------------------------
        //
        //  Private Classes 
        //
        //------------------------------------------------------ 
 
        #region Private Classes
 

        /// 
        /// A helper class for RTI high contrast support
        ///  
        private class RTIHighContrastCallback : HighContrastCallback
        { 
            //----------------------------------------------------- 
            //
            //  Cnostructors 
            //
            //------------------------------------------------------

            #region Constructors 

            internal RTIHighContrastCallback(InkCanvas inkCanvas) 
            { 
                _thisInkCanvas = inkCanvas;
            } 

            private RTIHighContrastCallback() { }

            #endregion Constructors 

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

            #region Internal Methods
 
            /// 
            /// TurnHighContrastOn 
            ///  
            /// 
            internal override void TurnHighContrastOn(Color highContrastColor) 
            {
                // The static strokes already have been taken care of by InkPresenter.
                // We only update the RTI renderer here.
                DrawingAttributes highContrastDa = _thisInkCanvas.DefaultDrawingAttributes.Clone(); 
                highContrastDa.Color = highContrastColor;
                _thisInkCanvas.UpdateDynamicRenderer(highContrastDa); 
            } 

            ///  
            /// TurnHighContrastOff
            /// 
            internal override void TurnHighContrastOff()
            { 
                // The static strokes already have been taken care of by InkPresenter.
                // We only update the RTI renderer here. 
                _thisInkCanvas.UpdateDynamicRenderer(_thisInkCanvas.DefaultDrawingAttributes); 
            }
 
            #endregion Internal Methods

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

            #region Internal Properties 

            /// 
            /// Returns the dispatcher if the object is associated to a UIContext.
            ///  
            internal override Dispatcher Dispatcher
            { 
                get 
                {
                    return _thisInkCanvas.Dispatcher; 
                }
            }

            #endregion Internal Properties 

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

            #region Private Fields
 
            private InkCanvas _thisInkCanvas;
 
            #endregion Private Fields 
        }
 
        /// 
        /// This is a binding converter which translates the InkCanvas.ActiveEditingMode to UIElement.Visibility.
        /// 
        private class ActiveEditingMode2VisibilityConverter : IValueConverter 
        {
            public object Convert(object o, Type type, object parameter, System.Globalization.CultureInfo culture) 
            { 
                InkCanvasEditingMode activeMode = (InkCanvasEditingMode)o;
 
                // If the current EditingMode is the mode which menuitem is expecting, return true for IsChecked.
                if ( activeMode != InkCanvasEditingMode.None )
                {
                    return Visibility.Visible; 
                }
                else 
                { 
                    return Visibility.Collapsed;
                } 
            }

            public object ConvertBack(object o, Type type, object parameter, System.Globalization.CultureInfo culture)
            { 
                // Non-reversed convertion
                return null; 
            } 
        }
 
        #endregion Private Classes

        #region Private Members
 
        /// 
        /// The element that represents the selected ink strokes, if any exist.  Will frequently be null. 
        ///  
        private InkCanvasSelection          _selection = null;
        private InkCanvasSelectionAdorner   _selectionAdorner = null; 
        private InkCanvasFeedbackAdorner    _feedbackAdorner = null;

        /// 
        /// The internal Canvas used to hold elements 
        /// 
        private InkCanvasInnerCanvas        _innerCanvas = null; 
 
        /// 
        /// The internal private AdornerDecorator 
        /// 
        private AdornerDecorator            _localAdornerDecorator = null;

        ///  
        /// Runtime Selection StrokeCollection
        ///  
        private StrokeCollection            _dynamicallySelectedStrokes; 

        ///  
        /// Our editing logic
        /// 
        private EditingCoordinator          _editingCoordinator;
 
        /// 
        /// Defines the default StylusPointDescription 
        ///  
        private StylusPointDescription     _defaultStylusPointDescription;
 

        /// 
        /// Defines the shape of the eraser tip
        ///  
        private StylusShape                 _eraserShape;
 
        ///  
        /// Determines if EditingBehaviors should use their own cursor or a custom one specified.
        ///  
        private bool                        _useCustomCursor = false;


        // 
        // Rendering support.
        // 
        private InkPresenter                _inkPresenter; 

        // 
        // The RealTimeInking PlugIn that handles our off UIContext rendering.
        //
        private DynamicRenderer             _dynamicRenderer;
 
        //
        // Clipboard Helper 
        // 
        private ClipboardProcessor          _clipboardProcessor;
 
        //
        // Gesture support
        //
        private GestureRecognizer           _gestureRecognizer; 

        // 
        // HighContrast support 
        //
        private RTIHighContrastCallback     _rtiHighContrastCallback; 

        private const double                    c_pasteDefaultLocation = 0.0;

        #endregion Private Members 
    }
} 
 


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