EditingCoordinator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / MS / Internal / Ink / EditingCoordinator.cs / 1 / EditingCoordinator.cs

                            //---------------------------------------------------------------------------- 
//
// File: EditingCoordinator.cs
//
// Description: 
// Coordinates editing for InkCanvas
// Features: 
// 
// History:
//  4/29/2003 waynezen:     Rewrote for mid-stroke support 
//  3/15/2003 samgeo:       Created
//
// Copyright (C) 2003 by Microsoft Corporation.  All rights reserved.
// 
//---------------------------------------------------------------------------
using System; 
using System.ComponentModel; 
using System.ComponentModel.Design;
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions; 
using System.Windows.Ink;
using System.Windows.Input; 
using System.Windows; 
using System.Windows.Controls;
using System.Windows.Controls.Primitives; 
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Navigation; 
using System.Windows.Media;
using MS.Utility; 
 
namespace MS.Internal.Ink
{ 
    /// 
    /// Internal class that represents the editing stack of InkCanvas
    /// Please see the design detain at http://tabletpc/longhorn/Specs/Mid-Stroke%20and%20Pen%20Cursor%20Dev%20Design.mht
    ///  
    internal class EditingCoordinator
    { 
        //------------------------------------------------------------------------------- 
        //
        // Constructors 
        //
        //-------------------------------------------------------------------------------

        #region Constructors 

        ///  
        /// Constructors 
        /// 
        /// InkCanvas instance 
        internal EditingCoordinator(InkCanvas inkCanvas)
        {
            if (inkCanvas == null)
            { 
                throw new ArgumentNullException("inkCanvas");
            } 
 
            _inkCanvas = inkCanvas;
 
            // Create a stack for tracking the behavior
            _activationStack = new Stack(2);

            // NTRAID#WINDOWS-1104477-2005/02/26-waynezen, 
            // listen to in-air move so that we could get notified when Stylus is inverted.
            // 
            _inkCanvas.AddHandler(Stylus.StylusInRangeEvent, new StylusEventHandler(OnInkCanvasStylusInAirOrInRangeMove)); 
            _inkCanvas.AddHandler(Stylus.StylusInAirMoveEvent, new StylusEventHandler(OnInkCanvasStylusInAirOrInRangeMove));
            _inkCanvas.AddHandler(Stylus.StylusOutOfRangeEvent, new StylusEventHandler(OnInkCanvasStylusOutOfRange)); 
        }

        #endregion Constructors
 
        //--------------------------------------------------------------------------------
        // 
        // Internal Methods 
        //
        //------------------------------------------------------------------------------- 

        #region Internal Methods

        ///  
        /// Activate a dynamic behavior
        /// Called from: 
        ///     SelectionEditor.OnCanvasMouseMove 
        /// 
        ///  
        /// 
        /// 
        ///     Critical: Calls critical methods AddStylusPoints and InitializeCapture
        ///  
        [SecurityCritical]
        internal void ActivateDynamicBehavior(EditingBehavior dynamicBehavior, InputDevice inputDevice) 
        { 
            // Only SelectionEditor should be enable to initiate dynamic behavior
            Debug.Assert(ActiveEditingBehavior == SelectionEditor, 
                            "Only SelectionEditor should be able to initiate dynamic behavior");

            DebugCheckDynamicBehavior(dynamicBehavior);
 
            // Push the dynamic behavior.
            PushEditingBehavior(dynamicBehavior); 
 
            // If this is LassoSelectionBehavior, we should capture the current stylus and feed the cached
            if ( dynamicBehavior == LassoSelectionBehavior ) 
            {
                bool fSucceeded = false;

                // The below code might call out StrokeErasing or StrokeErased event. 
                // The out-side code could throw exception.
                // We use try/finally block to protect our status. 
                try 
                {
                    //we pass true for userInitiated because we've simply consulted the InputDevice 
                    //(and only StylusDevice or MouseDevice) for the current position of the device
                    InitializeCapture(inputDevice, (IStylusEditing)dynamicBehavior,
                        true /*userInitiated*/, false/*Don't reset the RTI*/);
                    fSucceeded = true; 
                }
                finally 
                { 
                    if ( !fSucceeded )
                    { 
                        // Abort the current editing.
                        ActiveEditingBehavior.Commit(false);

                        // Release capture and do clean-up. 
                        ReleaseCapture(true);
                    } 
                } 
            }
 
            _inkCanvas.RaiseActiveEditingModeChanged(new RoutedEventArgs(InkCanvas.ActiveEditingModeChangedEvent, _inkCanvas));
        }

        ///  
        /// Deactivate a dynamic behavior
        /// Called from: 
        ///     EditingBehavior.Commit 
        /// 
        internal void DeactivateDynamicBehavior() 
        {
            // Make sure we are under correct state:
            // ActiveEditingBehavior has to be either LassoSelectionBehavior or SelectionEditingBehavior.
            DebugCheckDynamicBehavior(ActiveEditingBehavior); 

            // Pop the dynamic behavior. 
            PopEditingBehavior(); 
        }
 
        /// 
        /// Update the current active EditingMode
        /// Called from:
        ///     EditingCoordinator.UpdateInvertedState 
        ///     InkCanvas.Initialize()
        ///  
        internal void UpdateActiveEditingState() 
        {
            UpdateEditingState(_stylusIsInverted); 
        }

        /// 
        /// Update the EditingMode 
        /// Called from:
        ///     InkCanvas.RaiseEditingModeChanged 
        ///     InkCanvas.RaiseEditingModeInvertedChanged 
        /// 
        /// A flage which indicates whether the new mode is for the Inverted state 
        internal void UpdateEditingState(bool inverted)
        {
            // If the mode is inactive currently, we should skip the update.
            if ( inverted != _stylusIsInverted ) 
            {
                return; 
            } 

            // Get the current behavior and the new behavior. 
            EditingBehavior currentBehavior = ActiveEditingBehavior;
            EditingBehavior newBehavior = GetBehavior(ActiveEditingMode);

            // Check whether the user is editing. 
            if ( UserIsEditing )
            { 
                // Check if we are in the mid-stroke. 
                if ( IsInMidStroke )
                { 
                    // We are in mid-stroke now.

                    Debug.Assert(currentBehavior is StylusEditingBehavior,
                                    "The current behavoir has to be one of StylusEditingBehaviors"); 
                    ( (StylusEditingBehavior)currentBehavior ).SwitchToMode(ActiveEditingMode);
                } 
                else 
                {
                    if ( currentBehavior == SelectionEditingBehavior ) 
                    {
                        // Commit the current moving/resizing behavior
                        currentBehavior.Commit(true);
                    } 

                    ChangeEditingBehavior(newBehavior); 
                } 
            }
            else 
            {
                // Check if we are in the mid-stroke.
                if ( IsInMidStroke )
                { 
                    // We are in mid-stroke now.
 
                    Debug.Assert(currentBehavior is StylusEditingBehavior, 
                                    "The current behavoir has to be one of StylusEditingBehaviors");
                    ( (StylusEditingBehavior)currentBehavior ).SwitchToMode(ActiveEditingMode); 
                }
                else
                {
                    // Make sure we are under correct state: 
                    // currentBehavior cannot be any of Dynamic Behavior.
                    DebugCheckNonDynamicBehavior(currentBehavior); 
                    ChangeEditingBehavior(newBehavior); 
                }
            } 

            _inkCanvas.UpdateCursor();
        }
 
        /// 
        /// Update the PointEraerCursor 
        /// Called from: 
        ///     InkCanvas.set_EraserShape
        ///  
        internal void UpdatePointEraserCursor()
        {
            // We only have to update the point eraser when the active mode is EraseByPoint
            // In other case, EraseBehavior will update cursor properly in its OnActivate routine. 
            if ( ActiveEditingMode == InkCanvasEditingMode.EraseByPoint )
            { 
                InvalidateBehaviorCursor(EraserBehavior); 
            }
        } 

        /// 
        /// InvalidateTransform
        ///     Called by: InkCanvas.OnPropertyChanged 
        /// 
        internal void InvalidateTransform() 
        { 
            // We only have to invalidate transform flags for InkCollectionBehavior and EraserBehavior for now.
            SetTransformValid(InkCollectionBehavior, false); 
            SetTransformValid(EraserBehavior, false);
        }

        ///  
        /// Invalidate the behavior cursor
        /// Call from: 
        ///     EditingCoordinator.UpdatePointEraserCursor 
        ///     EraserBehavior.OnActivate
        ///     InkCollectionBehavior.OnInkCanvasDefaultDrawingAttributesReplaced 
        ///     InkCollectionBehavior.OnInkCanvasDefaultDrawingAttributesChanged
        ///     SelectionEditingBehavior.OnActivate
        ///     SelectionEditor.UpdateCursor(InkCanvasSelectionHandle handle)
        ///  
        /// the behavior which its cursor needs to be updated.
        internal void InvalidateBehaviorCursor(EditingBehavior behavior) 
        { 
            // Should never be null
            Debug.Assert(behavior != null); 

            // InvalidateCursor first
            SetCursorValid(behavior, false);
 
            if ( !GetTransformValid(behavior) )
            { 
                behavior.UpdateTransform(); 
                SetTransformValid(behavior, true);
            } 

            // If the behavior is active, we have to update cursor right now.
            if ( behavior == ActiveEditingBehavior )
            { 
                _inkCanvas.UpdateCursor();
            } 
        } 

        ///  
        /// Check whether the cursor of the specified behavior is valid
        /// 
        /// EditingBehavior
        /// True if the cursor doesn't need to be updated 
        internal bool IsCursorValid(EditingBehavior behavior)
        { 
            return GetCursorValid(behavior); 
        }
 
        /// 
        /// Check whether the cursor of the specified behavior is valid
        /// 
        /// EditingBehavior 
        /// True if the cursor doesn't need to be updated
        internal bool IsTransformValid(EditingBehavior behavior) 
        { 
            return GetTransformValid(behavior);
        } 

        /// 
        /// Change to another StylusEditing mode or None mode.
        ///  
        /// 
        ///  
        ///  
        internal IStylusEditing ChangeStylusEditingMode(StylusEditingBehavior sourceBehavior, InkCanvasEditingMode newMode)
        { 
            // NOTICE-2006/04/27-WAYNEZEN,
            // Before the caller invokes the method, the external event could have been fired.
            // The user code may interrupt the Mid-Stroke by releasing capture or switching to another mode.
            // So we should check if we still is under mid-stroke and the source behavior still is active. 
            // If not, we just no-op.
            if ( IsInMidStroke && 
                ( ( // We expect that either InkCollectionBehavior or EraseBehavior is active. 
                    sourceBehavior != LassoSelectionBehavior && sourceBehavior == ActiveEditingBehavior )
                    // Or We expect SelectionEditor is active here since 
                    // LassoSelectionBehavior will be deactivated once it gets committed.
                    || ( sourceBehavior == LassoSelectionBehavior && SelectionEditor == ActiveEditingBehavior ) ) )
            {
                Debug.Assert(_activationStack.Count == 1, "The behavior stack has to contain one behavior."); 

                // Pop up the old behavior 
                PopEditingBehavior(); 

                // Get the new behavior 
                EditingBehavior newBehavior = GetBehavior(ActiveEditingMode);

                if ( newBehavior != null )
                { 
                    // Push the new behavior
                    PushEditingBehavior(newBehavior); 
 
                    // If the new mode is Select, we should push the LassoSelectionBehavior now.
                    if ( newMode == InkCanvasEditingMode.Select 
                        // NOTICE-2006/04/27-WAYNEZEN,
                        // Make sure the newBehavior is SelectionEditor since it could be changed by the user event handling code.
                        && newBehavior == SelectionEditor )
                    { 
                        PushEditingBehavior(LassoSelectionBehavior);
                    } 
                } 
                else
                { 
                    // None-mode now. We stop collecting the packets.
                    ReleaseCapture(true);
                }
 
                _inkCanvas.RaiseActiveEditingModeChanged(new RoutedEventArgs(InkCanvas.ActiveEditingModeChangedEvent, _inkCanvas));
 
                return ActiveEditingBehavior as IStylusEditing; 
            }
            else 
            {
                // No-op
                return null;
            } 
        }
 
        ///  
        /// Debug Checker
        ///  
        /// 
        [Conditional("DEBUG")]
        internal void DebugCheckActiveBehavior(EditingBehavior behavior)
        { 
            Debug.Assert(behavior == ActiveEditingBehavior);
        } 
 
        /// 
        /// Debug check for the dynamic behavior 
        /// 
        /// 
        [Conditional("DEBUG")]
        private void DebugCheckDynamicBehavior(EditingBehavior behavior) 
        {
            Debug.Assert(behavior == LassoSelectionBehavior || behavior == SelectionEditingBehavior, 
                "Only LassoSelectionBehavior or SelectionEditingBehavior is dynamic behavior"); 
        }
 
        /// 
        /// Debug check for the non dynamic behavior
        /// 
        ///  
        [Conditional("DEBUG")]
        private void DebugCheckNonDynamicBehavior(EditingBehavior behavior) 
        { 
            Debug.Assert(behavior != LassoSelectionBehavior && behavior != SelectionEditingBehavior,
                "behavior cannot be LassoSelectionBehavior or SelectionEditingBehavior"); 
        }

        #endregion Internal Methods
 
        //--------------------------------------------------------------------------------
        // 
        // Internal Properties 
        //
        //-------------------------------------------------------------------------------- 

        #region Internal Properties

        ///  
        /// Gets / sets whether move is enabled or note
        ///  
        internal bool MoveEnabled 
        {
            get { return _moveEnabled; } 
            set { _moveEnabled = value; }
        }

        ///  
        /// The property that indicates if the user is interacting with the current InkCanvas
        ///  
        internal bool UserIsEditing 
        {
            get 
            {
                return _userIsEditing;
            }
            set 
            {
                _userIsEditing = value; 
            } 
        }
 
        /// 
        /// Helper flag that tells if we're between a preview down and an up.
        /// 
        internal bool StylusOrMouseIsDown 
        {
            get 
            { 
                bool stylusDown = false;
                StylusDevice stylusDevice = Stylus.CurrentStylusDevice; 
                if (stylusDevice != null && _inkCanvas.IsStylusOver && !stylusDevice.InAir)
                {
                    stylusDown = true;
                } 

                bool mouseDown = (_inkCanvas.IsMouseOver && Mouse.PrimaryDevice.LeftButton == MouseButtonState.Pressed); 
                if (stylusDown || mouseDown) 
                {
                    return true; 
                }
                return false;
            }
        } 

        ///  
        /// Returns the StylusDevice to call DynamicRenderer.Reset with.  Stylus or Mouse 
        /// must be in a down state.  If the down device is a Mouse, null is returned, since
        /// that is what DynamicRenderer.Reset expects for the Mouse. 
        /// 
        /// 
        internal InputDevice GetInputDeviceForReset()
        { 
            Debug.Assert((_capturedStylus != null && _capturedMouse == null)
                            || (_capturedStylus == null && _capturedMouse != null), 
                            "There must be one and at most one device being captured."); 

            if ( _capturedStylus != null && !_capturedStylus.InAir ) 
            {
                return _capturedStylus;
            }
            else if ( _capturedMouse != null && _capturedMouse.LeftButton == MouseButtonState.Pressed ) 
            {
                return _capturedMouse; 
            } 

            return null; 
        }
        /// 
        /// Gets / sets whether resize is enabled or note
        ///  
        internal bool ResizeEnabled
        { 
            get { return _resizeEnabled; } 
            set { _resizeEnabled = value; }
        } 

        /// 
        /// Lazy init access to the LassoSelectionBehavior
        ///  
        /// 
        internal LassoSelectionBehavior LassoSelectionBehavior 
        { 
            get
            { 
                if ( _lassoSelectionBehavior == null )
                {
                    _lassoSelectionBehavior = new LassoSelectionBehavior(this, _inkCanvas);
                } 
                return _lassoSelectionBehavior;
            } 
        } 

        ///  
        /// Lazy init access to the SelectionEditingBehavior
        /// 
        /// 
        internal SelectionEditingBehavior SelectionEditingBehavior 
        {
            get 
            { 
                if ( _selectionEditingBehavior == null )
                { 
                    _selectionEditingBehavior = new SelectionEditingBehavior(this, _inkCanvas);
                }
                return _selectionEditingBehavior;
            } 
        }
 
        ///  
        /// Internal helper prop to indicate the active editing mode
        ///  
        internal InkCanvasEditingMode ActiveEditingMode
        {
            get
            { 
                if ( _stylusIsInverted )
                { 
                    return _inkCanvas.EditingModeInverted; 
                }
                return _inkCanvas.EditingMode; 
            }
        }

        ///  
        /// Lazy init access to the SelectionEditor
        ///  
        ///  
        internal SelectionEditor SelectionEditor
        { 
            get
            {
                if ( _selectionEditor == null )
                { 
                    _selectionEditor = new SelectionEditor(this, _inkCanvas);
                } 
                return _selectionEditor; 
            }
        } 

        /// 
        /// Gets the mid-stroke state
        ///  
        internal bool IsInMidStroke
        { 
            get 
            {
                return _capturedStylus != null || _capturedMouse != null; 
            }
        }

        ///  
        /// Returns Stylus Inverted state
        ///  
        internal bool IsStylusInverted 
        {
            get 
            {
                return _stylusIsInverted;
            }
        } 

        #endregion Internal Properties 
 
        //-------------------------------------------------------------------------------
        // 
        // Private Methods
        //
        //--------------------------------------------------------------------------------
 
        #region Private Methods
 
        ///  
        /// Retrieve the behavior instance based on the EditingMode
        ///  
        /// EditingMode
        /// 
        private EditingBehavior GetBehavior(InkCanvasEditingMode editingMode)
        { 
            EditingBehavior newBehavior;
 
            switch ( editingMode ) 
            {
                case InkCanvasEditingMode.Ink: 
                case InkCanvasEditingMode.GestureOnly:
                case InkCanvasEditingMode.InkAndGesture:
                    newBehavior = InkCollectionBehavior;
                    break; 
                case InkCanvasEditingMode.Select:
                    newBehavior = SelectionEditor; 
                    break; 
                case InkCanvasEditingMode.EraseByPoint:
                case InkCanvasEditingMode.EraseByStroke: 
                    newBehavior = EraserBehavior;
                    break;
                default:
                    // Treat as InkCanvasEditingMode.None. Return null value 
                    newBehavior = null;
                    break; 
 
            }
 
            return newBehavior;
        }

 
        /// 
        /// Pushes an EditingBehavior onto our stack, disables any current ones 
        ///  
        /// The EditingBehavior to activate
        private void PushEditingBehavior(EditingBehavior newEditingBehavior) 
        {
            Debug.Assert(newEditingBehavior != null);

            EditingBehavior behavior = ActiveEditingBehavior; 

            // Deactivate the previous behavior 
            if ( behavior != null ) 
            {
                behavior.Deactivate(); 
            }

            // Activate the new behavior.
            _activationStack.Push(newEditingBehavior); 
            newEditingBehavior.Activate();
        } 
 
        /// 
        /// Pops an EditingBehavior onto our stack, disables any current ones 
        /// 
        private void PopEditingBehavior()
        {
            EditingBehavior behavior = ActiveEditingBehavior; 

            if ( behavior != null ) 
            { 
                behavior.Deactivate();
                _activationStack.Pop(); 

                behavior = ActiveEditingBehavior;
                if ( ActiveEditingBehavior != null )
                { 
                    behavior.Activate();
                } 
            } 

            return; 
        }

        /// 
        /// Handles in-air stylus movements 
        /// 
        private void OnInkCanvasStylusInAirOrInRangeMove(object sender, StylusEventArgs args) 
        { 
            // If the current capture is mouse, we should reset the capture.
            if ( _capturedMouse != null ) 
            {
                if (ActiveEditingBehavior == InkCollectionBehavior && _inkCanvas.InternalDynamicRenderer != null)
                {
                    // NTRAID#WINDOWS-1378904-2005/11/17-WAYNEZEN 
                    // When InkCanvas loses the current capture, we should stop the RTI since the App thread are no longer collecting ink.
                    // By flipping the Enabled property, the RTI will be reset. 
                    _inkCanvas.InternalDynamicRenderer.Enabled = false; 
                    _inkCanvas.InternalDynamicRenderer.Enabled = true;
                } 

                // Call ActiveEditingBehavior.Commit at the end of the routine. The method will cause an external event fired.
                // So it should be invoked after we set up our states.
                ActiveEditingBehavior.Commit(true); 

                // Release capture and do clean-up. 
                ReleaseCapture(true); 
            }
 
            UpdateInvertedState(args.StylusDevice, args.Inverted);
        }

        ///  
        /// Handle StylusOutofRange event
        ///  
        ///  
        /// 
        private void OnInkCanvasStylusOutOfRange(object sender, StylusEventArgs args) 
        {
            // Reset the inverted state once OutOfRange has been received.
            UpdateInvertedState(args.StylusDevice, false);
        } 

        ///  
        /// InkCanvas.StylusDown handler 
        /// 
        ///  
        /// 
        /// 
        ///     Critical:
        ///             Calls SecurityCritcal method: InitializeCapture and AddStylusPoints 
        ///             Eventually calls SecurityCritical method InkCanvas.RaiseGestureOrStrokeCollected
        /// 
        ///     TreatAsSafe: This method is called by the input system, from security transparent 
        ///                 code, so it can not be marked critical.  We check the eventArgs.UserInitiated
        ///                 to verify that the input was user initiated and pass this flag to 
        ///                 InkCanvas.RaiseGestureOrStrokeCollected and use it to decide if we should
        ///                 perform gesture recognition
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void OnInkCanvasDeviceDown(object sender, InputEventArgs args)
        { 
            MouseButtonEventArgs mouseButtonEventArgs = args as MouseButtonEventArgs; 
            bool resetDynamicRenderer = false;
            if ( mouseButtonEventArgs != null ) 
            {
                // NTRADI:WINDOWSOS#1563896-2006/03/20-WAYNEZEN,
                // Note we don't mark Handled for the None EditingMode.
                // Set focus to InkCanvas. 
                if ( _inkCanvas.Focus() && ActiveEditingMode != InkCanvasEditingMode.None )
                { 
                    mouseButtonEventArgs.Handled = true; 
                }
 
                // ISSUE-2005/09/20-WAYNEZEN,
                // We will reevaluate whether we should allow the right-button down for the modes other than the Ink mode.
                // Skip collecting for the non-left buttons.
                if ( mouseButtonEventArgs.ChangedButton != MouseButton.Left ) 
                {
                    return; 
                } 

                // NTRAID-WINDOWS#1607286-2006/04/14-WAYNEZEN, 
                // If the mouse down event is from a Stylus, make sure we have a correct inverted state.
                if ( mouseButtonEventArgs.StylusDevice != null )
                {
                    UpdateInvertedState(mouseButtonEventArgs.StylusDevice, mouseButtonEventArgs.StylusDevice.Inverted); 
                }
            } 
            else 
            {
                // NTRAID-WINDOWS#1395155-2005/12/15-WAYNEZEN, 
                // When StylusDown is received, We should check the Invert state again.
                // If there is any change, the ActiveEditingMode will be updated.
                // The dynamic renderer will be reset in InkCollectionBehavior.OnActivated since the device is under down state.
                StylusEventArgs stylusEventArgs = args as StylusEventArgs; 
                UpdateInvertedState(stylusEventArgs.StylusDevice, stylusEventArgs.Inverted);
            } 
 
            // If the active behavior is not one of StylusEditingBehavior, don't even bother here.
            IStylusEditing stylusEditingBehavior = ActiveEditingBehavior as IStylusEditing; 

            // We might receive StylusDown from a different device meanwhile we have already captured one.
            // Make sure that we are starting from a fresh state.
            if ( !IsInMidStroke && stylusEditingBehavior != null ) 
            {
 
                bool fSucceeded = false; 

                try 
                {
                    InputDevice capturedDevice = null;
                    // Capture the stylus (if mouse event make sure to use stylus if generated by a stylus)
                    if ( mouseButtonEventArgs != null && mouseButtonEventArgs.StylusDevice != null ) 
                    {
                        capturedDevice = mouseButtonEventArgs.StylusDevice; 
                        resetDynamicRenderer = true; 
                    }
                    else 
                    {
                        capturedDevice = args.Device;
                    }
 
                    InitializeCapture(capturedDevice, stylusEditingBehavior, args.UserInitiated, resetDynamicRenderer);
 
                    // The below code might call out StrokeErasing or StrokeErased event. 
                    // The out-side code could throw exception.
                    // We use try/finally block to protect our status. 
                    fSucceeded = true;
                }
                finally
                { 
                    if ( !fSucceeded )
                    { 
                        // Abort the current editing. 
                        ActiveEditingBehavior.Commit(false);
 
                        // Release capture and do clean-up.
                        ReleaseCapture(IsInMidStroke);
                    }
                } 
            }
        } 
 
        /// 
        /// InkCanvas.StylusMove handler 
        /// 
        /// 
        /// 
        ///  
        ///     Critical:
        ///             Calls SecurityCritcal method: 
        ///             Eventually calls SecurityCritical method InkCanvas.RaiseGestureOrStrokeCollected 
        ///
        ///     TreatAsSafe: This method is called by the input system, from security transparent 
        ///                 code, so it can not be marked critical.  We check the eventArgs.UserInitiated
        ///                 to verify that the input was user initiated and pass this flag to
        ///                 InkCanvas.RaiseGestureOrStrokeCollected and use it to decide if we should
        ///                 perform gesture recognition 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void OnInkCanvasDeviceMove(object sender, TEventArgs args) 
            where TEventArgs : InputEventArgs
        { 
            // Make sure that the stylus is the one we captured previously.
            if ( IsInputDeviceCaptured(args.Device) )
            {
                IStylusEditing stylusEditingBehavior = ActiveEditingBehavior as IStylusEditing; 
                Debug.Assert(stylusEditingBehavior != null || ActiveEditingBehavior == null,
                    "The ActiveEditingBehavior should be either null (The None mode) or type of IStylusEditing."); 
 
                if ( stylusEditingBehavior != null )
                { 
                    StylusPointCollection stylusPoints;
                    if ( _capturedStylus != null )
                    {
                        stylusPoints = _capturedStylus.GetStylusPoints(_inkCanvas, _commonDescription); 
                    }
                    else 
                    { 
                        // Make sure we ignore stylus generated mouse events.
                        MouseEventArgs mouseEventArgs = args as MouseEventArgs; 
                        if ( mouseEventArgs != null && mouseEventArgs.StylusDevice != null )
                        {
                            return;
                        } 

                        stylusPoints = new StylusPointCollection(new Point[] { _capturedMouse.GetPosition(_inkCanvas) }); 
                    } 

                    bool fSucceeded = false; 

                    // The below code might call out StrokeErasing or StrokeErased event.
                    // The out-side code could throw exception.
                    // We use try/finally block to protect our status. 
                    try
                    { 
                        stylusEditingBehavior.AddStylusPoints(stylusPoints, args.UserInitiated); 
                        fSucceeded = true;
                    } 
                    finally
                    {
                        if ( !fSucceeded )
                        { 
                            // Abort the current editing.
                            ActiveEditingBehavior.Commit(false); 
 
                            // Release capture and do clean-up.
                            ReleaseCapture(true); 
                        }
                    }
                }
            } 
        }
 
        ///  
        /// InkCanvas.StylusUp handler
        ///  
        /// 
        /// 
        internal void OnInkCanvasDeviceUp(object sender, InputEventArgs args)
        { 
            // Make sure that the stylus is the one we captured previously.
            if ( IsInputDeviceCaptured(args.Device) ) 
            { 
                Debug.Assert(ActiveEditingBehavior == null || ActiveEditingBehavior is IStylusEditing,
                    "The ActiveEditingBehavior should be either null (The None mode) or type of IStylusEditing."); 

                // Make sure we only look at mouse left button events if watching mouse events.
                if ( _capturedMouse != null )
                { 
                    MouseButtonEventArgs mouseButtonEventArgs = args as MouseButtonEventArgs;
                    if ( mouseButtonEventArgs != null ) 
                    { 
                        if ( mouseButtonEventArgs.ChangedButton != MouseButton.Left )
                        { 
                            return;
                        }
                    }
                } 

                try 
                { 
                    // The follow code raises variety editing events.
                    // The out-side code could throw exception in the their handlers. We use try/finally block to protect our status. 
                    if ( ActiveEditingBehavior != null )
                    {
                        // Commit the current editing.
                        ActiveEditingBehavior.Commit(true); 
                    }
                } 
                finally 
                {
                    // Call ReleaseCapture(true) at the end of the routine. The method will cause an external event fired. 
                    // So it should be invoked after we set up our states.
                    ReleaseCapture(true);
                }
 
            }
        } 
 
        /// 
        /// InkCanvas.LostStylusCapture handler 
        /// 
        /// 
        /// 
        private void OnInkCanvasLostDeviceCapture(object sender, TEventArgs args) 
            where TEventArgs : InputEventArgs
        { 
            // If user is editing, we have to commit the current operation and reset our state. 
            if ( UserIsEditing )
            { 
                // Note ReleaseCapture(false) won't raise any external events. It only reset the internal states.
                ReleaseCapture(false);

                if ( ActiveEditingBehavior == InkCollectionBehavior && _inkCanvas.InternalDynamicRenderer != null ) 
                {
                    // NTRAID#WINDOWS-1378904-2005/11/17-WAYNEZEN 
                    // When InkCanvas loses the current capture, we should stop the RTI since the App thread are no longer collecting ink. 
                    // By flipping the Enabled property, the RTI will be reset.
                    _inkCanvas.InternalDynamicRenderer.Enabled = false; 
                    _inkCanvas.InternalDynamicRenderer.Enabled = true;
                }

                // Call ActiveEditingBehavior.Commit at the end of the routine. The method will cause an external event fired. 
                // So it should be invoked after we set up our states.
                ActiveEditingBehavior.Commit(true); 
            } 
        }
 
        /// 
        /// Initialize the capture state
        /// 
        ///  
        /// 
        ///  
        ///  
        /// 
        ///     Critical: Returns critical data from the inputDevice, StylusPointCollection. 
        /// 
        [SecurityCritical]
        private void InitializeCapture(InputDevice inputDevice, IStylusEditing stylusEditingBehavior, bool userInitiated, bool resetDynamicRenderer)
        { 
            Debug.Assert(inputDevice != null, "A null device is passed in.");
            Debug.Assert(stylusEditingBehavior != null, "stylusEditingBehavior cannot be null."); 
            Debug.Assert(!IsInMidStroke, "The previous device hasn't been released yet."); 

            StylusPointCollection stylusPoints; 

            _capturedStylus = inputDevice as StylusDevice;
            _capturedMouse = inputDevice as MouseDevice;
 
            // NOTICE-2005/09/15-WAYNEZEN,
            // We assume that the StylusDown always happens before the MouseDown. So, we could safely add the listeners of 
            // XXXMove and XXXUp as the below which branchs out the coming mouse or stylus events. 
            if ( _capturedStylus != null )
            { 

                StylusPointCollection newPoints = _capturedStylus.GetStylusPoints(_inkCanvas);

                _commonDescription = 
                    StylusPointDescription.GetCommonDescription(_inkCanvas.DefaultStylusPointDescription,
                        newPoints.Description); 
                stylusPoints = newPoints.Reformat(_commonDescription); 

                if ( resetDynamicRenderer ) 
                {
                    // Reset the dynamic renderer for InkCollectionBehavior
                    InkCollectionBehavior inkCollectionBehavior = stylusEditingBehavior as InkCollectionBehavior;
                    if ( inkCollectionBehavior != null ) 
                    {
                        inkCollectionBehavior.ResetDynamicRenderer(); 
                    } 
                }
 
                stylusEditingBehavior.AddStylusPoints(stylusPoints, userInitiated);

                // If the current down device is stylus, we should only listen to StylusMove, StylusUp and LostStylusCapture
                // events. 

                _inkCanvas.CaptureStylus(); 
 
                if ( _inkCanvas.IsStylusCaptured && ActiveEditingMode != InkCanvasEditingMode.None )
                { 
                    _inkCanvas.AddHandler(Stylus.StylusMoveEvent, new StylusEventHandler(OnInkCanvasDeviceMove));
                    _inkCanvas.AddHandler(UIElement.LostStylusCaptureEvent, new StylusEventHandler(OnInkCanvasLostDeviceCapture));
                }
                else 
                {
                    _capturedStylus = null; 
                } 

            } 
            else
            {
                Debug.Assert(!resetDynamicRenderer, "The dynamic renderer shouldn't be reset for Mouse");
 
                _commonDescription = null;
 
                Point[] points = new Point[] { _capturedMouse.GetPosition(_inkCanvas) }; 
                stylusPoints = new StylusPointCollection(points);
                stylusEditingBehavior.AddStylusPoints(stylusPoints, userInitiated); 

                // NTRAID:WINDOWSOS#1536974-2006/03/02-WAYNEZEN,
                // CaptureMouse triggers MouseDevice.Synchronize which sends a simulated MouseMove event.
                // So we have to call CaptureMouse after at the end of the initialization. 
                // Otherwise, the MouseMove handlers will be executed in the middle of the initialization.
                _inkCanvas.CaptureMouse(); 
 
                // The user code could change mode or call release capture when the simulated Move event is received.
                // So we have to check the capture still is on and the mode is correct before hooking up our handlers. 
                // If the current down device is mouse, we should only listen to MouseMove, MouseUp and LostMouseCapture
                // events.
                if ( _inkCanvas.IsMouseCaptured && ActiveEditingMode != InkCanvasEditingMode.None )
                { 
                    _inkCanvas.AddHandler(Mouse.MouseMoveEvent, new MouseEventHandler(OnInkCanvasDeviceMove));
                    _inkCanvas.AddHandler(UIElement.LostMouseCaptureEvent, new MouseEventHandler(OnInkCanvasLostDeviceCapture)); 
                } 
                else
                { 
                    _capturedMouse = null;
                }
            }
        } 

        ///  
        /// Clean up the capture state 
        /// 
        ///  
        private void ReleaseCapture(bool releaseDevice)
        {
            Debug.Assert(IsInMidStroke || !releaseDevice, "The captured device has been release unexpectly.");
 
            if ( _capturedStylus != null )
            { 
                // The Stylus was captured. Remove the stylus listeners. 
                _commonDescription = null;
 
                _inkCanvas.RemoveHandler(Stylus.StylusMoveEvent, new StylusEventHandler(OnInkCanvasDeviceMove));
                _inkCanvas.RemoveHandler(UIElement.LostStylusCaptureEvent, new StylusEventHandler(OnInkCanvasLostDeviceCapture));

                _capturedStylus = null; 

                if ( releaseDevice ) 
                { 
                    // Call ReleaseStylusCapture at the end of the routine. The method will cause an external event fired.
                    // So it should be invoked after we set up our states. 
                    _inkCanvas.ReleaseStylusCapture();
                }
            }
            else if ( _capturedMouse != null ) 
            {
                // The Mouse was captured. Remove the mouse listeners. 
                _inkCanvas.RemoveHandler(Mouse.MouseMoveEvent, new MouseEventHandler(OnInkCanvasDeviceMove)); 
                _inkCanvas.RemoveHandler(UIElement.LostMouseCaptureEvent, new MouseEventHandler(OnInkCanvasLostDeviceCapture));
 
                _capturedMouse = null;
                if ( releaseDevice )
                {
                    // Call ReleaseMouseCapture at the end of the routine. The method will cause an external event fired. 
                    // So it should be invoked after we set up our states.
                    _inkCanvas.ReleaseMouseCapture(); 
                } 
            }
        } 

        /// 
        /// Retrieve whether a specified device is captured by us.
        ///  
        /// 
        ///  
        private bool IsInputDeviceCaptured(InputDevice inputDevice) 
        {
            Debug.Assert(_capturedStylus == null || _capturedMouse == null, "InkCanvas cannot capture both stylus and mouse at the same time."); 
            return (inputDevice == _capturedStylus && ((StylusDevice)inputDevice).Captured == _inkCanvas)
                || (inputDevice == _capturedMouse && ( (MouseDevice)inputDevice).Captured == _inkCanvas);
        }
 
        /// 
        /// Return the cursor of the active behavior 
        ///  
        /// 
        internal Cursor GetActiveBehaviorCursor() 
        {
            EditingBehavior behavior = ActiveEditingBehavior;

            if ( behavior == null ) 
            {
                // Return the default Arrow cursor for the None mode. 
                return Cursors.Arrow; 
            }
 
            // Retrieve the cursor.
            Cursor cursor = behavior.Cursor;

            // Clean up the dirty flag when it's done. 
            if ( !GetCursorValid(behavior) )
            { 
                SetCursorValid(behavior, true); 
            }
 
            return cursor;
        }

        ///  
        /// A private method which returns the valid flag of behaviors' cursor.
        ///  
        ///  
        /// 
        private bool GetCursorValid(EditingBehavior behavior) 
        {
            BehaviorValidFlag flag = GetBehaviorCursorFlag(behavior);
            return GetBitFlag(flag);
        } 

        ///  
        /// A private method which sets/resets the valid flag of behaviors' cursor 
        /// 
        ///  
        /// 
        private void SetCursorValid(EditingBehavior behavior, bool isValid)
        {
            BehaviorValidFlag flag = GetBehaviorCursorFlag(behavior); 
            SetBitFlag(flag, isValid);
        } 
 
        /// 
        /// A private method which returns the valid flag of behaviors' cursor. 
        /// 
        /// 
        /// 
        private bool GetTransformValid(EditingBehavior behavior) 
        {
            BehaviorValidFlag flag = GetBehaviorTransformFlag(behavior); 
            return GetBitFlag(flag); 
        }
 
        /// 
        /// A private method which sets/resets the valid flag of behaviors' cursor
        /// 
        ///  
        /// 
        private void SetTransformValid(EditingBehavior behavior, bool isValid) 
        { 
            BehaviorValidFlag flag = GetBehaviorTransformFlag(behavior);
            SetBitFlag(flag, isValid); 
        }

        /// 
        /// GetBitFlag 
        /// 
        ///  
        ///  
        private bool GetBitFlag(BehaviorValidFlag flag)
        { 
            return (_behaviorValidFlag & flag) != 0;
        }

        ///  
        /// SetBitFlag
        ///  
        ///  
        /// 
        private void SetBitFlag(BehaviorValidFlag flag, bool value) 
        {
            if ( value )
            {
                _behaviorValidFlag |= flag; 
            }
            else 
            { 
                _behaviorValidFlag &= (~flag);
            } 

        }

        ///  
        /// A helper returns behavior cursor flag from a behavior instance
        ///  
        ///  
        /// 
        private BehaviorValidFlag GetBehaviorCursorFlag(EditingBehavior behavior) 
        {
            BehaviorValidFlag flag = 0;

            if ( behavior == InkCollectionBehavior ) 
            {
                flag = BehaviorValidFlag.InkCollectionBehaviorCursorValid; 
            } 
            else if ( behavior == EraserBehavior )
            { 
                flag = BehaviorValidFlag.EraserBehaviorCursorValid;
            }
            else if ( behavior == LassoSelectionBehavior )
            { 
                flag = BehaviorValidFlag.LassoSelectionBehaviorCursorValid;
            } 
            else if ( behavior == SelectionEditingBehavior ) 
            {
                flag = BehaviorValidFlag.SelectionEditingBehaviorCursorValid; 
            }
            else if ( behavior == SelectionEditor )
            {
                flag = BehaviorValidFlag.SelectionEditorCursorValid; 
            }
            else 
            { 
                Debug.Assert(false, "Unknown behavior");
            } 

            return flag;
        }
 
        /// 
        /// A helper returns behavior transform flag from a behavior instance 
        ///  
        /// 
        ///  
        private BehaviorValidFlag GetBehaviorTransformFlag(EditingBehavior behavior)
        {
            BehaviorValidFlag flag = 0;
 
            if ( behavior == InkCollectionBehavior )
            { 
                flag = BehaviorValidFlag.InkCollectionBehaviorTransformValid; 
            }
            else if ( behavior == EraserBehavior ) 
            {
                flag = BehaviorValidFlag.EraserBehaviorTransformValid;
            }
            else if ( behavior == LassoSelectionBehavior ) 
            {
                flag = BehaviorValidFlag.LassoSelectionBehaviorTransformValid; 
            } 
            else if ( behavior == SelectionEditingBehavior )
            { 
                flag = BehaviorValidFlag.SelectionEditingBehaviorTransformValid;
            }
            else if ( behavior == SelectionEditor )
            { 
                flag = BehaviorValidFlag.SelectionEditorTransformValid;
            } 
            else 
            {
                Debug.Assert(false, "Unknown behavior"); 
            }

            return flag;
        } 

        private void ChangeEditingBehavior(EditingBehavior newBehavior) 
        { 
            Debug.Assert(!IsInMidStroke, "ChangeEditingBehavior cannot be called in a mid-stroke");
            Debug.Assert(_activationStack.Count <= 1, "The behavior stack has to contain at most one behavior when user is not editing."); 

            try
            {
                _inkCanvas.ClearSelection(true); 
            }
            finally 
            { 
                if ( ActiveEditingBehavior != null )
                { 
                    // Pop the old behavior.
                    PopEditingBehavior();
                }
 
                // Push the new behavior
                if ( newBehavior != null ) 
                { 
                    PushEditingBehavior(newBehavior);
                } 

                _inkCanvas.RaiseActiveEditingModeChanged(new RoutedEventArgs(InkCanvas.ActiveEditingModeChangedEvent, _inkCanvas));
            }
        } 

        ///  
        /// Update the Inverted state 
        /// 
        ///  
        /// 
        /// true if the behavior is updated
        private bool UpdateInvertedState(StylusDevice stylusDevice, bool stylusIsInverted)
        { 
            if ( !IsInMidStroke ||
                ( IsInMidStroke && IsInputDeviceCaptured(stylusDevice) )) 
            { 
                if ( stylusIsInverted != _stylusIsInverted )
                { 
                    _stylusIsInverted = stylusIsInverted;

                    //
                    // this can change editing state 
                    //
                    UpdateActiveEditingState(); 
 
                    return true;
                } 
            }

            return false;
        } 

        #endregion Private Methods 
 
        //-------------------------------------------------------------------------------
        // 
        // Private Properties
        //
        //-------------------------------------------------------------------------------
 
        #region Private Properties
 
        ///  
        /// Gets the top level active EditingBehavior
        ///  
        /// 
        private EditingBehavior ActiveEditingBehavior
        {
            get 
            {
                EditingBehavior EditingBehavior = null; 
                if ( _activationStack.Count > 0 ) 
                {
                    EditingBehavior = _activationStack.Peek(); 
                }
                return EditingBehavior;
            }
        } 

        ///  
        /// Lazy init access to the InkCollectionBehavior 
        /// 
        ///  
        internal InkCollectionBehavior InkCollectionBehavior
        {
            get
            { 
                if ( _inkCollectionBehavior == null )
                { 
                    _inkCollectionBehavior = new InkCollectionBehavior(this, _inkCanvas); 
                }
                return _inkCollectionBehavior; 
            }
        }

        ///  
        /// Lazy init access to the EraserBehavior
        ///  
        ///  
        private EraserBehavior EraserBehavior
        { 
            get
            {
                if ( _eraserBehavior == null )
                { 
                    _eraserBehavior = new EraserBehavior(this, _inkCanvas);
                } 
                return _eraserBehavior; 
            }
        } 

        #endregion Private Properties

        //------------------------------------------------------------------------------- 
        //
        // Private Enum 
        // 
        //--------------------------------------------------------------------------------
 
        #region Private Enum

        /// 
        /// Enum values which represent the cursor valid flag for each EditingBehavior. 
        /// 
        [Flags] 
        private enum BehaviorValidFlag 
        {
            InkCollectionBehaviorCursorValid      = 0x00000001, 
            EraserBehaviorCursorValid             = 0x00000002,
            LassoSelectionBehaviorCursorValid     = 0x00000004,
            SelectionEditingBehaviorCursorValid   = 0x00000008,
            SelectionEditorCursorValid            = 0x00000010, 
            InkCollectionBehaviorTransformValid   = 0x00000020,
            EraserBehaviorTransformValid          = 0x00000040, 
            LassoSelectionBehaviorTransformValid  = 0x00000080, 
            SelectionEditingBehaviorTransformValid= 0x00000100,
            SelectionEditorTransformValid         = 0x00000200, 
        }

        #endregion Private Enum
 
        //-------------------------------------------------------------------------------
        // 
        // Private Fields 
        //
        //-------------------------------------------------------------------------------- 

        #region Private Fields

        ///  
        /// The InkCanvas this EditingStack is being used in
        ///  
        private InkCanvas _inkCanvas; 
        private Stack _activationStack;
        private InkCollectionBehavior _inkCollectionBehavior; 
        private EraserBehavior _eraserBehavior;
        private LassoSelectionBehavior _lassoSelectionBehavior;
        private SelectionEditingBehavior _selectionEditingBehavior;
        private SelectionEditor _selectionEditor; 
        private bool _moveEnabled = true;
        private bool _resizeEnabled = true; 
        private bool _userIsEditing = false; 

        ///  
        /// Flag that indicates if the stylus is inverted
        /// 
        private bool _stylusIsInverted = false;
 
        private StylusPointDescription  _commonDescription;
        private StylusDevice            _capturedStylus; 
        private MouseDevice             _capturedMouse; 

        // Fields related to cursor and transform. 
        private BehaviorValidFlag       _behaviorValidFlag;

        #endregion Private Fields
 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// File: EditingCoordinator.cs
//
// Description: 
// Coordinates editing for InkCanvas
// Features: 
// 
// History:
//  4/29/2003 waynezen:     Rewrote for mid-stroke support 
//  3/15/2003 samgeo:       Created
//
// Copyright (C) 2003 by Microsoft Corporation.  All rights reserved.
// 
//---------------------------------------------------------------------------
using System; 
using System.ComponentModel; 
using System.ComponentModel.Design;
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions; 
using System.Windows.Ink;
using System.Windows.Input; 
using System.Windows; 
using System.Windows.Controls;
using System.Windows.Controls.Primitives; 
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Navigation; 
using System.Windows.Media;
using MS.Utility; 
 
namespace MS.Internal.Ink
{ 
    /// 
    /// Internal class that represents the editing stack of InkCanvas
    /// Please see the design detain at http://tabletpc/longhorn/Specs/Mid-Stroke%20and%20Pen%20Cursor%20Dev%20Design.mht
    ///  
    internal class EditingCoordinator
    { 
        //------------------------------------------------------------------------------- 
        //
        // Constructors 
        //
        //-------------------------------------------------------------------------------

        #region Constructors 

        ///  
        /// Constructors 
        /// 
        /// InkCanvas instance 
        internal EditingCoordinator(InkCanvas inkCanvas)
        {
            if (inkCanvas == null)
            { 
                throw new ArgumentNullException("inkCanvas");
            } 
 
            _inkCanvas = inkCanvas;
 
            // Create a stack for tracking the behavior
            _activationStack = new Stack(2);

            // NTRAID#WINDOWS-1104477-2005/02/26-waynezen, 
            // listen to in-air move so that we could get notified when Stylus is inverted.
            // 
            _inkCanvas.AddHandler(Stylus.StylusInRangeEvent, new StylusEventHandler(OnInkCanvasStylusInAirOrInRangeMove)); 
            _inkCanvas.AddHandler(Stylus.StylusInAirMoveEvent, new StylusEventHandler(OnInkCanvasStylusInAirOrInRangeMove));
            _inkCanvas.AddHandler(Stylus.StylusOutOfRangeEvent, new StylusEventHandler(OnInkCanvasStylusOutOfRange)); 
        }

        #endregion Constructors
 
        //--------------------------------------------------------------------------------
        // 
        // Internal Methods 
        //
        //------------------------------------------------------------------------------- 

        #region Internal Methods

        ///  
        /// Activate a dynamic behavior
        /// Called from: 
        ///     SelectionEditor.OnCanvasMouseMove 
        /// 
        ///  
        /// 
        /// 
        ///     Critical: Calls critical methods AddStylusPoints and InitializeCapture
        ///  
        [SecurityCritical]
        internal void ActivateDynamicBehavior(EditingBehavior dynamicBehavior, InputDevice inputDevice) 
        { 
            // Only SelectionEditor should be enable to initiate dynamic behavior
            Debug.Assert(ActiveEditingBehavior == SelectionEditor, 
                            "Only SelectionEditor should be able to initiate dynamic behavior");

            DebugCheckDynamicBehavior(dynamicBehavior);
 
            // Push the dynamic behavior.
            PushEditingBehavior(dynamicBehavior); 
 
            // If this is LassoSelectionBehavior, we should capture the current stylus and feed the cached
            if ( dynamicBehavior == LassoSelectionBehavior ) 
            {
                bool fSucceeded = false;

                // The below code might call out StrokeErasing or StrokeErased event. 
                // The out-side code could throw exception.
                // We use try/finally block to protect our status. 
                try 
                {
                    //we pass true for userInitiated because we've simply consulted the InputDevice 
                    //(and only StylusDevice or MouseDevice) for the current position of the device
                    InitializeCapture(inputDevice, (IStylusEditing)dynamicBehavior,
                        true /*userInitiated*/, false/*Don't reset the RTI*/);
                    fSucceeded = true; 
                }
                finally 
                { 
                    if ( !fSucceeded )
                    { 
                        // Abort the current editing.
                        ActiveEditingBehavior.Commit(false);

                        // Release capture and do clean-up. 
                        ReleaseCapture(true);
                    } 
                } 
            }
 
            _inkCanvas.RaiseActiveEditingModeChanged(new RoutedEventArgs(InkCanvas.ActiveEditingModeChangedEvent, _inkCanvas));
        }

        ///  
        /// Deactivate a dynamic behavior
        /// Called from: 
        ///     EditingBehavior.Commit 
        /// 
        internal void DeactivateDynamicBehavior() 
        {
            // Make sure we are under correct state:
            // ActiveEditingBehavior has to be either LassoSelectionBehavior or SelectionEditingBehavior.
            DebugCheckDynamicBehavior(ActiveEditingBehavior); 

            // Pop the dynamic behavior. 
            PopEditingBehavior(); 
        }
 
        /// 
        /// Update the current active EditingMode
        /// Called from:
        ///     EditingCoordinator.UpdateInvertedState 
        ///     InkCanvas.Initialize()
        ///  
        internal void UpdateActiveEditingState() 
        {
            UpdateEditingState(_stylusIsInverted); 
        }

        /// 
        /// Update the EditingMode 
        /// Called from:
        ///     InkCanvas.RaiseEditingModeChanged 
        ///     InkCanvas.RaiseEditingModeInvertedChanged 
        /// 
        /// A flage which indicates whether the new mode is for the Inverted state 
        internal void UpdateEditingState(bool inverted)
        {
            // If the mode is inactive currently, we should skip the update.
            if ( inverted != _stylusIsInverted ) 
            {
                return; 
            } 

            // Get the current behavior and the new behavior. 
            EditingBehavior currentBehavior = ActiveEditingBehavior;
            EditingBehavior newBehavior = GetBehavior(ActiveEditingMode);

            // Check whether the user is editing. 
            if ( UserIsEditing )
            { 
                // Check if we are in the mid-stroke. 
                if ( IsInMidStroke )
                { 
                    // We are in mid-stroke now.

                    Debug.Assert(currentBehavior is StylusEditingBehavior,
                                    "The current behavoir has to be one of StylusEditingBehaviors"); 
                    ( (StylusEditingBehavior)currentBehavior ).SwitchToMode(ActiveEditingMode);
                } 
                else 
                {
                    if ( currentBehavior == SelectionEditingBehavior ) 
                    {
                        // Commit the current moving/resizing behavior
                        currentBehavior.Commit(true);
                    } 

                    ChangeEditingBehavior(newBehavior); 
                } 
            }
            else 
            {
                // Check if we are in the mid-stroke.
                if ( IsInMidStroke )
                { 
                    // We are in mid-stroke now.
 
                    Debug.Assert(currentBehavior is StylusEditingBehavior, 
                                    "The current behavoir has to be one of StylusEditingBehaviors");
                    ( (StylusEditingBehavior)currentBehavior ).SwitchToMode(ActiveEditingMode); 
                }
                else
                {
                    // Make sure we are under correct state: 
                    // currentBehavior cannot be any of Dynamic Behavior.
                    DebugCheckNonDynamicBehavior(currentBehavior); 
                    ChangeEditingBehavior(newBehavior); 
                }
            } 

            _inkCanvas.UpdateCursor();
        }
 
        /// 
        /// Update the PointEraerCursor 
        /// Called from: 
        ///     InkCanvas.set_EraserShape
        ///  
        internal void UpdatePointEraserCursor()
        {
            // We only have to update the point eraser when the active mode is EraseByPoint
            // In other case, EraseBehavior will update cursor properly in its OnActivate routine. 
            if ( ActiveEditingMode == InkCanvasEditingMode.EraseByPoint )
            { 
                InvalidateBehaviorCursor(EraserBehavior); 
            }
        } 

        /// 
        /// InvalidateTransform
        ///     Called by: InkCanvas.OnPropertyChanged 
        /// 
        internal void InvalidateTransform() 
        { 
            // We only have to invalidate transform flags for InkCollectionBehavior and EraserBehavior for now.
            SetTransformValid(InkCollectionBehavior, false); 
            SetTransformValid(EraserBehavior, false);
        }

        ///  
        /// Invalidate the behavior cursor
        /// Call from: 
        ///     EditingCoordinator.UpdatePointEraserCursor 
        ///     EraserBehavior.OnActivate
        ///     InkCollectionBehavior.OnInkCanvasDefaultDrawingAttributesReplaced 
        ///     InkCollectionBehavior.OnInkCanvasDefaultDrawingAttributesChanged
        ///     SelectionEditingBehavior.OnActivate
        ///     SelectionEditor.UpdateCursor(InkCanvasSelectionHandle handle)
        ///  
        /// the behavior which its cursor needs to be updated.
        internal void InvalidateBehaviorCursor(EditingBehavior behavior) 
        { 
            // Should never be null
            Debug.Assert(behavior != null); 

            // InvalidateCursor first
            SetCursorValid(behavior, false);
 
            if ( !GetTransformValid(behavior) )
            { 
                behavior.UpdateTransform(); 
                SetTransformValid(behavior, true);
            } 

            // If the behavior is active, we have to update cursor right now.
            if ( behavior == ActiveEditingBehavior )
            { 
                _inkCanvas.UpdateCursor();
            } 
        } 

        ///  
        /// Check whether the cursor of the specified behavior is valid
        /// 
        /// EditingBehavior
        /// True if the cursor doesn't need to be updated 
        internal bool IsCursorValid(EditingBehavior behavior)
        { 
            return GetCursorValid(behavior); 
        }
 
        /// 
        /// Check whether the cursor of the specified behavior is valid
        /// 
        /// EditingBehavior 
        /// True if the cursor doesn't need to be updated
        internal bool IsTransformValid(EditingBehavior behavior) 
        { 
            return GetTransformValid(behavior);
        } 

        /// 
        /// Change to another StylusEditing mode or None mode.
        ///  
        /// 
        ///  
        ///  
        internal IStylusEditing ChangeStylusEditingMode(StylusEditingBehavior sourceBehavior, InkCanvasEditingMode newMode)
        { 
            // NOTICE-2006/04/27-WAYNEZEN,
            // Before the caller invokes the method, the external event could have been fired.
            // The user code may interrupt the Mid-Stroke by releasing capture or switching to another mode.
            // So we should check if we still is under mid-stroke and the source behavior still is active. 
            // If not, we just no-op.
            if ( IsInMidStroke && 
                ( ( // We expect that either InkCollectionBehavior or EraseBehavior is active. 
                    sourceBehavior != LassoSelectionBehavior && sourceBehavior == ActiveEditingBehavior )
                    // Or We expect SelectionEditor is active here since 
                    // LassoSelectionBehavior will be deactivated once it gets committed.
                    || ( sourceBehavior == LassoSelectionBehavior && SelectionEditor == ActiveEditingBehavior ) ) )
            {
                Debug.Assert(_activationStack.Count == 1, "The behavior stack has to contain one behavior."); 

                // Pop up the old behavior 
                PopEditingBehavior(); 

                // Get the new behavior 
                EditingBehavior newBehavior = GetBehavior(ActiveEditingMode);

                if ( newBehavior != null )
                { 
                    // Push the new behavior
                    PushEditingBehavior(newBehavior); 
 
                    // If the new mode is Select, we should push the LassoSelectionBehavior now.
                    if ( newMode == InkCanvasEditingMode.Select 
                        // NOTICE-2006/04/27-WAYNEZEN,
                        // Make sure the newBehavior is SelectionEditor since it could be changed by the user event handling code.
                        && newBehavior == SelectionEditor )
                    { 
                        PushEditingBehavior(LassoSelectionBehavior);
                    } 
                } 
                else
                { 
                    // None-mode now. We stop collecting the packets.
                    ReleaseCapture(true);
                }
 
                _inkCanvas.RaiseActiveEditingModeChanged(new RoutedEventArgs(InkCanvas.ActiveEditingModeChangedEvent, _inkCanvas));
 
                return ActiveEditingBehavior as IStylusEditing; 
            }
            else 
            {
                // No-op
                return null;
            } 
        }
 
        ///  
        /// Debug Checker
        ///  
        /// 
        [Conditional("DEBUG")]
        internal void DebugCheckActiveBehavior(EditingBehavior behavior)
        { 
            Debug.Assert(behavior == ActiveEditingBehavior);
        } 
 
        /// 
        /// Debug check for the dynamic behavior 
        /// 
        /// 
        [Conditional("DEBUG")]
        private void DebugCheckDynamicBehavior(EditingBehavior behavior) 
        {
            Debug.Assert(behavior == LassoSelectionBehavior || behavior == SelectionEditingBehavior, 
                "Only LassoSelectionBehavior or SelectionEditingBehavior is dynamic behavior"); 
        }
 
        /// 
        /// Debug check for the non dynamic behavior
        /// 
        ///  
        [Conditional("DEBUG")]
        private void DebugCheckNonDynamicBehavior(EditingBehavior behavior) 
        { 
            Debug.Assert(behavior != LassoSelectionBehavior && behavior != SelectionEditingBehavior,
                "behavior cannot be LassoSelectionBehavior or SelectionEditingBehavior"); 
        }

        #endregion Internal Methods
 
        //--------------------------------------------------------------------------------
        // 
        // Internal Properties 
        //
        //-------------------------------------------------------------------------------- 

        #region Internal Properties

        ///  
        /// Gets / sets whether move is enabled or note
        ///  
        internal bool MoveEnabled 
        {
            get { return _moveEnabled; } 
            set { _moveEnabled = value; }
        }

        ///  
        /// The property that indicates if the user is interacting with the current InkCanvas
        ///  
        internal bool UserIsEditing 
        {
            get 
            {
                return _userIsEditing;
            }
            set 
            {
                _userIsEditing = value; 
            } 
        }
 
        /// 
        /// Helper flag that tells if we're between a preview down and an up.
        /// 
        internal bool StylusOrMouseIsDown 
        {
            get 
            { 
                bool stylusDown = false;
                StylusDevice stylusDevice = Stylus.CurrentStylusDevice; 
                if (stylusDevice != null && _inkCanvas.IsStylusOver && !stylusDevice.InAir)
                {
                    stylusDown = true;
                } 

                bool mouseDown = (_inkCanvas.IsMouseOver && Mouse.PrimaryDevice.LeftButton == MouseButtonState.Pressed); 
                if (stylusDown || mouseDown) 
                {
                    return true; 
                }
                return false;
            }
        } 

        ///  
        /// Returns the StylusDevice to call DynamicRenderer.Reset with.  Stylus or Mouse 
        /// must be in a down state.  If the down device is a Mouse, null is returned, since
        /// that is what DynamicRenderer.Reset expects for the Mouse. 
        /// 
        /// 
        internal InputDevice GetInputDeviceForReset()
        { 
            Debug.Assert((_capturedStylus != null && _capturedMouse == null)
                            || (_capturedStylus == null && _capturedMouse != null), 
                            "There must be one and at most one device being captured."); 

            if ( _capturedStylus != null && !_capturedStylus.InAir ) 
            {
                return _capturedStylus;
            }
            else if ( _capturedMouse != null && _capturedMouse.LeftButton == MouseButtonState.Pressed ) 
            {
                return _capturedMouse; 
            } 

            return null; 
        }
        /// 
        /// Gets / sets whether resize is enabled or note
        ///  
        internal bool ResizeEnabled
        { 
            get { return _resizeEnabled; } 
            set { _resizeEnabled = value; }
        } 

        /// 
        /// Lazy init access to the LassoSelectionBehavior
        ///  
        /// 
        internal LassoSelectionBehavior LassoSelectionBehavior 
        { 
            get
            { 
                if ( _lassoSelectionBehavior == null )
                {
                    _lassoSelectionBehavior = new LassoSelectionBehavior(this, _inkCanvas);
                } 
                return _lassoSelectionBehavior;
            } 
        } 

        ///  
        /// Lazy init access to the SelectionEditingBehavior
        /// 
        /// 
        internal SelectionEditingBehavior SelectionEditingBehavior 
        {
            get 
            { 
                if ( _selectionEditingBehavior == null )
                { 
                    _selectionEditingBehavior = new SelectionEditingBehavior(this, _inkCanvas);
                }
                return _selectionEditingBehavior;
            } 
        }
 
        ///  
        /// Internal helper prop to indicate the active editing mode
        ///  
        internal InkCanvasEditingMode ActiveEditingMode
        {
            get
            { 
                if ( _stylusIsInverted )
                { 
                    return _inkCanvas.EditingModeInverted; 
                }
                return _inkCanvas.EditingMode; 
            }
        }

        ///  
        /// Lazy init access to the SelectionEditor
        ///  
        ///  
        internal SelectionEditor SelectionEditor
        { 
            get
            {
                if ( _selectionEditor == null )
                { 
                    _selectionEditor = new SelectionEditor(this, _inkCanvas);
                } 
                return _selectionEditor; 
            }
        } 

        /// 
        /// Gets the mid-stroke state
        ///  
        internal bool IsInMidStroke
        { 
            get 
            {
                return _capturedStylus != null || _capturedMouse != null; 
            }
        }

        ///  
        /// Returns Stylus Inverted state
        ///  
        internal bool IsStylusInverted 
        {
            get 
            {
                return _stylusIsInverted;
            }
        } 

        #endregion Internal Properties 
 
        //-------------------------------------------------------------------------------
        // 
        // Private Methods
        //
        //--------------------------------------------------------------------------------
 
        #region Private Methods
 
        ///  
        /// Retrieve the behavior instance based on the EditingMode
        ///  
        /// EditingMode
        /// 
        private EditingBehavior GetBehavior(InkCanvasEditingMode editingMode)
        { 
            EditingBehavior newBehavior;
 
            switch ( editingMode ) 
            {
                case InkCanvasEditingMode.Ink: 
                case InkCanvasEditingMode.GestureOnly:
                case InkCanvasEditingMode.InkAndGesture:
                    newBehavior = InkCollectionBehavior;
                    break; 
                case InkCanvasEditingMode.Select:
                    newBehavior = SelectionEditor; 
                    break; 
                case InkCanvasEditingMode.EraseByPoint:
                case InkCanvasEditingMode.EraseByStroke: 
                    newBehavior = EraserBehavior;
                    break;
                default:
                    // Treat as InkCanvasEditingMode.None. Return null value 
                    newBehavior = null;
                    break; 
 
            }
 
            return newBehavior;
        }

 
        /// 
        /// Pushes an EditingBehavior onto our stack, disables any current ones 
        ///  
        /// The EditingBehavior to activate
        private void PushEditingBehavior(EditingBehavior newEditingBehavior) 
        {
            Debug.Assert(newEditingBehavior != null);

            EditingBehavior behavior = ActiveEditingBehavior; 

            // Deactivate the previous behavior 
            if ( behavior != null ) 
            {
                behavior.Deactivate(); 
            }

            // Activate the new behavior.
            _activationStack.Push(newEditingBehavior); 
            newEditingBehavior.Activate();
        } 
 
        /// 
        /// Pops an EditingBehavior onto our stack, disables any current ones 
        /// 
        private void PopEditingBehavior()
        {
            EditingBehavior behavior = ActiveEditingBehavior; 

            if ( behavior != null ) 
            { 
                behavior.Deactivate();
                _activationStack.Pop(); 

                behavior = ActiveEditingBehavior;
                if ( ActiveEditingBehavior != null )
                { 
                    behavior.Activate();
                } 
            } 

            return; 
        }

        /// 
        /// Handles in-air stylus movements 
        /// 
        private void OnInkCanvasStylusInAirOrInRangeMove(object sender, StylusEventArgs args) 
        { 
            // If the current capture is mouse, we should reset the capture.
            if ( _capturedMouse != null ) 
            {
                if (ActiveEditingBehavior == InkCollectionBehavior && _inkCanvas.InternalDynamicRenderer != null)
                {
                    // NTRAID#WINDOWS-1378904-2005/11/17-WAYNEZEN 
                    // When InkCanvas loses the current capture, we should stop the RTI since the App thread are no longer collecting ink.
                    // By flipping the Enabled property, the RTI will be reset. 
                    _inkCanvas.InternalDynamicRenderer.Enabled = false; 
                    _inkCanvas.InternalDynamicRenderer.Enabled = true;
                } 

                // Call ActiveEditingBehavior.Commit at the end of the routine. The method will cause an external event fired.
                // So it should be invoked after we set up our states.
                ActiveEditingBehavior.Commit(true); 

                // Release capture and do clean-up. 
                ReleaseCapture(true); 
            }
 
            UpdateInvertedState(args.StylusDevice, args.Inverted);
        }

        ///  
        /// Handle StylusOutofRange event
        ///  
        ///  
        /// 
        private void OnInkCanvasStylusOutOfRange(object sender, StylusEventArgs args) 
        {
            // Reset the inverted state once OutOfRange has been received.
            UpdateInvertedState(args.StylusDevice, false);
        } 

        ///  
        /// InkCanvas.StylusDown handler 
        /// 
        ///  
        /// 
        /// 
        ///     Critical:
        ///             Calls SecurityCritcal method: InitializeCapture and AddStylusPoints 
        ///             Eventually calls SecurityCritical method InkCanvas.RaiseGestureOrStrokeCollected
        /// 
        ///     TreatAsSafe: This method is called by the input system, from security transparent 
        ///                 code, so it can not be marked critical.  We check the eventArgs.UserInitiated
        ///                 to verify that the input was user initiated and pass this flag to 
        ///                 InkCanvas.RaiseGestureOrStrokeCollected and use it to decide if we should
        ///                 perform gesture recognition
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void OnInkCanvasDeviceDown(object sender, InputEventArgs args)
        { 
            MouseButtonEventArgs mouseButtonEventArgs = args as MouseButtonEventArgs; 
            bool resetDynamicRenderer = false;
            if ( mouseButtonEventArgs != null ) 
            {
                // NTRADI:WINDOWSOS#1563896-2006/03/20-WAYNEZEN,
                // Note we don't mark Handled for the None EditingMode.
                // Set focus to InkCanvas. 
                if ( _inkCanvas.Focus() && ActiveEditingMode != InkCanvasEditingMode.None )
                { 
                    mouseButtonEventArgs.Handled = true; 
                }
 
                // ISSUE-2005/09/20-WAYNEZEN,
                // We will reevaluate whether we should allow the right-button down for the modes other than the Ink mode.
                // Skip collecting for the non-left buttons.
                if ( mouseButtonEventArgs.ChangedButton != MouseButton.Left ) 
                {
                    return; 
                } 

                // NTRAID-WINDOWS#1607286-2006/04/14-WAYNEZEN, 
                // If the mouse down event is from a Stylus, make sure we have a correct inverted state.
                if ( mouseButtonEventArgs.StylusDevice != null )
                {
                    UpdateInvertedState(mouseButtonEventArgs.StylusDevice, mouseButtonEventArgs.StylusDevice.Inverted); 
                }
            } 
            else 
            {
                // NTRAID-WINDOWS#1395155-2005/12/15-WAYNEZEN, 
                // When StylusDown is received, We should check the Invert state again.
                // If there is any change, the ActiveEditingMode will be updated.
                // The dynamic renderer will be reset in InkCollectionBehavior.OnActivated since the device is under down state.
                StylusEventArgs stylusEventArgs = args as StylusEventArgs; 
                UpdateInvertedState(stylusEventArgs.StylusDevice, stylusEventArgs.Inverted);
            } 
 
            // If the active behavior is not one of StylusEditingBehavior, don't even bother here.
            IStylusEditing stylusEditingBehavior = ActiveEditingBehavior as IStylusEditing; 

            // We might receive StylusDown from a different device meanwhile we have already captured one.
            // Make sure that we are starting from a fresh state.
            if ( !IsInMidStroke && stylusEditingBehavior != null ) 
            {
 
                bool fSucceeded = false; 

                try 
                {
                    InputDevice capturedDevice = null;
                    // Capture the stylus (if mouse event make sure to use stylus if generated by a stylus)
                    if ( mouseButtonEventArgs != null && mouseButtonEventArgs.StylusDevice != null ) 
                    {
                        capturedDevice = mouseButtonEventArgs.StylusDevice; 
                        resetDynamicRenderer = true; 
                    }
                    else 
                    {
                        capturedDevice = args.Device;
                    }
 
                    InitializeCapture(capturedDevice, stylusEditingBehavior, args.UserInitiated, resetDynamicRenderer);
 
                    // The below code might call out StrokeErasing or StrokeErased event. 
                    // The out-side code could throw exception.
                    // We use try/finally block to protect our status. 
                    fSucceeded = true;
                }
                finally
                { 
                    if ( !fSucceeded )
                    { 
                        // Abort the current editing. 
                        ActiveEditingBehavior.Commit(false);
 
                        // Release capture and do clean-up.
                        ReleaseCapture(IsInMidStroke);
                    }
                } 
            }
        } 
 
        /// 
        /// InkCanvas.StylusMove handler 
        /// 
        /// 
        /// 
        ///  
        ///     Critical:
        ///             Calls SecurityCritcal method: 
        ///             Eventually calls SecurityCritical method InkCanvas.RaiseGestureOrStrokeCollected 
        ///
        ///     TreatAsSafe: This method is called by the input system, from security transparent 
        ///                 code, so it can not be marked critical.  We check the eventArgs.UserInitiated
        ///                 to verify that the input was user initiated and pass this flag to
        ///                 InkCanvas.RaiseGestureOrStrokeCollected and use it to decide if we should
        ///                 perform gesture recognition 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void OnInkCanvasDeviceMove(object sender, TEventArgs args) 
            where TEventArgs : InputEventArgs
        { 
            // Make sure that the stylus is the one we captured previously.
            if ( IsInputDeviceCaptured(args.Device) )
            {
                IStylusEditing stylusEditingBehavior = ActiveEditingBehavior as IStylusEditing; 
                Debug.Assert(stylusEditingBehavior != null || ActiveEditingBehavior == null,
                    "The ActiveEditingBehavior should be either null (The None mode) or type of IStylusEditing."); 
 
                if ( stylusEditingBehavior != null )
                { 
                    StylusPointCollection stylusPoints;
                    if ( _capturedStylus != null )
                    {
                        stylusPoints = _capturedStylus.GetStylusPoints(_inkCanvas, _commonDescription); 
                    }
                    else 
                    { 
                        // Make sure we ignore stylus generated mouse events.
                        MouseEventArgs mouseEventArgs = args as MouseEventArgs; 
                        if ( mouseEventArgs != null && mouseEventArgs.StylusDevice != null )
                        {
                            return;
                        } 

                        stylusPoints = new StylusPointCollection(new Point[] { _capturedMouse.GetPosition(_inkCanvas) }); 
                    } 

                    bool fSucceeded = false; 

                    // The below code might call out StrokeErasing or StrokeErased event.
                    // The out-side code could throw exception.
                    // We use try/finally block to protect our status. 
                    try
                    { 
                        stylusEditingBehavior.AddStylusPoints(stylusPoints, args.UserInitiated); 
                        fSucceeded = true;
                    } 
                    finally
                    {
                        if ( !fSucceeded )
                        { 
                            // Abort the current editing.
                            ActiveEditingBehavior.Commit(false); 
 
                            // Release capture and do clean-up.
                            ReleaseCapture(true); 
                        }
                    }
                }
            } 
        }
 
        ///  
        /// InkCanvas.StylusUp handler
        ///  
        /// 
        /// 
        internal void OnInkCanvasDeviceUp(object sender, InputEventArgs args)
        { 
            // Make sure that the stylus is the one we captured previously.
            if ( IsInputDeviceCaptured(args.Device) ) 
            { 
                Debug.Assert(ActiveEditingBehavior == null || ActiveEditingBehavior is IStylusEditing,
                    "The ActiveEditingBehavior should be either null (The None mode) or type of IStylusEditing."); 

                // Make sure we only look at mouse left button events if watching mouse events.
                if ( _capturedMouse != null )
                { 
                    MouseButtonEventArgs mouseButtonEventArgs = args as MouseButtonEventArgs;
                    if ( mouseButtonEventArgs != null ) 
                    { 
                        if ( mouseButtonEventArgs.ChangedButton != MouseButton.Left )
                        { 
                            return;
                        }
                    }
                } 

                try 
                { 
                    // The follow code raises variety editing events.
                    // The out-side code could throw exception in the their handlers. We use try/finally block to protect our status. 
                    if ( ActiveEditingBehavior != null )
                    {
                        // Commit the current editing.
                        ActiveEditingBehavior.Commit(true); 
                    }
                } 
                finally 
                {
                    // Call ReleaseCapture(true) at the end of the routine. The method will cause an external event fired. 
                    // So it should be invoked after we set up our states.
                    ReleaseCapture(true);
                }
 
            }
        } 
 
        /// 
        /// InkCanvas.LostStylusCapture handler 
        /// 
        /// 
        /// 
        private void OnInkCanvasLostDeviceCapture(object sender, TEventArgs args) 
            where TEventArgs : InputEventArgs
        { 
            // If user is editing, we have to commit the current operation and reset our state. 
            if ( UserIsEditing )
            { 
                // Note ReleaseCapture(false) won't raise any external events. It only reset the internal states.
                ReleaseCapture(false);

                if ( ActiveEditingBehavior == InkCollectionBehavior && _inkCanvas.InternalDynamicRenderer != null ) 
                {
                    // NTRAID#WINDOWS-1378904-2005/11/17-WAYNEZEN 
                    // When InkCanvas loses the current capture, we should stop the RTI since the App thread are no longer collecting ink. 
                    // By flipping the Enabled property, the RTI will be reset.
                    _inkCanvas.InternalDynamicRenderer.Enabled = false; 
                    _inkCanvas.InternalDynamicRenderer.Enabled = true;
                }

                // Call ActiveEditingBehavior.Commit at the end of the routine. The method will cause an external event fired. 
                // So it should be invoked after we set up our states.
                ActiveEditingBehavior.Commit(true); 
            } 
        }
 
        /// 
        /// Initialize the capture state
        /// 
        ///  
        /// 
        ///  
        ///  
        /// 
        ///     Critical: Returns critical data from the inputDevice, StylusPointCollection. 
        /// 
        [SecurityCritical]
        private void InitializeCapture(InputDevice inputDevice, IStylusEditing stylusEditingBehavior, bool userInitiated, bool resetDynamicRenderer)
        { 
            Debug.Assert(inputDevice != null, "A null device is passed in.");
            Debug.Assert(stylusEditingBehavior != null, "stylusEditingBehavior cannot be null."); 
            Debug.Assert(!IsInMidStroke, "The previous device hasn't been released yet."); 

            StylusPointCollection stylusPoints; 

            _capturedStylus = inputDevice as StylusDevice;
            _capturedMouse = inputDevice as MouseDevice;
 
            // NOTICE-2005/09/15-WAYNEZEN,
            // We assume that the StylusDown always happens before the MouseDown. So, we could safely add the listeners of 
            // XXXMove and XXXUp as the below which branchs out the coming mouse or stylus events. 
            if ( _capturedStylus != null )
            { 

                StylusPointCollection newPoints = _capturedStylus.GetStylusPoints(_inkCanvas);

                _commonDescription = 
                    StylusPointDescription.GetCommonDescription(_inkCanvas.DefaultStylusPointDescription,
                        newPoints.Description); 
                stylusPoints = newPoints.Reformat(_commonDescription); 

                if ( resetDynamicRenderer ) 
                {
                    // Reset the dynamic renderer for InkCollectionBehavior
                    InkCollectionBehavior inkCollectionBehavior = stylusEditingBehavior as InkCollectionBehavior;
                    if ( inkCollectionBehavior != null ) 
                    {
                        inkCollectionBehavior.ResetDynamicRenderer(); 
                    } 
                }
 
                stylusEditingBehavior.AddStylusPoints(stylusPoints, userInitiated);

                // If the current down device is stylus, we should only listen to StylusMove, StylusUp and LostStylusCapture
                // events. 

                _inkCanvas.CaptureStylus(); 
 
                if ( _inkCanvas.IsStylusCaptured && ActiveEditingMode != InkCanvasEditingMode.None )
                { 
                    _inkCanvas.AddHandler(Stylus.StylusMoveEvent, new StylusEventHandler(OnInkCanvasDeviceMove));
                    _inkCanvas.AddHandler(UIElement.LostStylusCaptureEvent, new StylusEventHandler(OnInkCanvasLostDeviceCapture));
                }
                else 
                {
                    _capturedStylus = null; 
                } 

            } 
            else
            {
                Debug.Assert(!resetDynamicRenderer, "The dynamic renderer shouldn't be reset for Mouse");
 
                _commonDescription = null;
 
                Point[] points = new Point[] { _capturedMouse.GetPosition(_inkCanvas) }; 
                stylusPoints = new StylusPointCollection(points);
                stylusEditingBehavior.AddStylusPoints(stylusPoints, userInitiated); 

                // NTRAID:WINDOWSOS#1536974-2006/03/02-WAYNEZEN,
                // CaptureMouse triggers MouseDevice.Synchronize which sends a simulated MouseMove event.
                // So we have to call CaptureMouse after at the end of the initialization. 
                // Otherwise, the MouseMove handlers will be executed in the middle of the initialization.
                _inkCanvas.CaptureMouse(); 
 
                // The user code could change mode or call release capture when the simulated Move event is received.
                // So we have to check the capture still is on and the mode is correct before hooking up our handlers. 
                // If the current down device is mouse, we should only listen to MouseMove, MouseUp and LostMouseCapture
                // events.
                if ( _inkCanvas.IsMouseCaptured && ActiveEditingMode != InkCanvasEditingMode.None )
                { 
                    _inkCanvas.AddHandler(Mouse.MouseMoveEvent, new MouseEventHandler(OnInkCanvasDeviceMove));
                    _inkCanvas.AddHandler(UIElement.LostMouseCaptureEvent, new MouseEventHandler(OnInkCanvasLostDeviceCapture)); 
                } 
                else
                { 
                    _capturedMouse = null;
                }
            }
        } 

        ///  
        /// Clean up the capture state 
        /// 
        ///  
        private void ReleaseCapture(bool releaseDevice)
        {
            Debug.Assert(IsInMidStroke || !releaseDevice, "The captured device has been release unexpectly.");
 
            if ( _capturedStylus != null )
            { 
                // The Stylus was captured. Remove the stylus listeners. 
                _commonDescription = null;
 
                _inkCanvas.RemoveHandler(Stylus.StylusMoveEvent, new StylusEventHandler(OnInkCanvasDeviceMove));
                _inkCanvas.RemoveHandler(UIElement.LostStylusCaptureEvent, new StylusEventHandler(OnInkCanvasLostDeviceCapture));

                _capturedStylus = null; 

                if ( releaseDevice ) 
                { 
                    // Call ReleaseStylusCapture at the end of the routine. The method will cause an external event fired.
                    // So it should be invoked after we set up our states. 
                    _inkCanvas.ReleaseStylusCapture();
                }
            }
            else if ( _capturedMouse != null ) 
            {
                // The Mouse was captured. Remove the mouse listeners. 
                _inkCanvas.RemoveHandler(Mouse.MouseMoveEvent, new MouseEventHandler(OnInkCanvasDeviceMove)); 
                _inkCanvas.RemoveHandler(UIElement.LostMouseCaptureEvent, new MouseEventHandler(OnInkCanvasLostDeviceCapture));
 
                _capturedMouse = null;
                if ( releaseDevice )
                {
                    // Call ReleaseMouseCapture at the end of the routine. The method will cause an external event fired. 
                    // So it should be invoked after we set up our states.
                    _inkCanvas.ReleaseMouseCapture(); 
                } 
            }
        } 

        /// 
        /// Retrieve whether a specified device is captured by us.
        ///  
        /// 
        ///  
        private bool IsInputDeviceCaptured(InputDevice inputDevice) 
        {
            Debug.Assert(_capturedStylus == null || _capturedMouse == null, "InkCanvas cannot capture both stylus and mouse at the same time."); 
            return (inputDevice == _capturedStylus && ((StylusDevice)inputDevice).Captured == _inkCanvas)
                || (inputDevice == _capturedMouse && ( (MouseDevice)inputDevice).Captured == _inkCanvas);
        }
 
        /// 
        /// Return the cursor of the active behavior 
        ///  
        /// 
        internal Cursor GetActiveBehaviorCursor() 
        {
            EditingBehavior behavior = ActiveEditingBehavior;

            if ( behavior == null ) 
            {
                // Return the default Arrow cursor for the None mode. 
                return Cursors.Arrow; 
            }
 
            // Retrieve the cursor.
            Cursor cursor = behavior.Cursor;

            // Clean up the dirty flag when it's done. 
            if ( !GetCursorValid(behavior) )
            { 
                SetCursorValid(behavior, true); 
            }
 
            return cursor;
        }

        ///  
        /// A private method which returns the valid flag of behaviors' cursor.
        ///  
        ///  
        /// 
        private bool GetCursorValid(EditingBehavior behavior) 
        {
            BehaviorValidFlag flag = GetBehaviorCursorFlag(behavior);
            return GetBitFlag(flag);
        } 

        ///  
        /// A private method which sets/resets the valid flag of behaviors' cursor 
        /// 
        ///  
        /// 
        private void SetCursorValid(EditingBehavior behavior, bool isValid)
        {
            BehaviorValidFlag flag = GetBehaviorCursorFlag(behavior); 
            SetBitFlag(flag, isValid);
        } 
 
        /// 
        /// A private method which returns the valid flag of behaviors' cursor. 
        /// 
        /// 
        /// 
        private bool GetTransformValid(EditingBehavior behavior) 
        {
            BehaviorValidFlag flag = GetBehaviorTransformFlag(behavior); 
            return GetBitFlag(flag); 
        }
 
        /// 
        /// A private method which sets/resets the valid flag of behaviors' cursor
        /// 
        ///  
        /// 
        private void SetTransformValid(EditingBehavior behavior, bool isValid) 
        { 
            BehaviorValidFlag flag = GetBehaviorTransformFlag(behavior);
            SetBitFlag(flag, isValid); 
        }

        /// 
        /// GetBitFlag 
        /// 
        ///  
        ///  
        private bool GetBitFlag(BehaviorValidFlag flag)
        { 
            return (_behaviorValidFlag & flag) != 0;
        }

        ///  
        /// SetBitFlag
        ///  
        ///  
        /// 
        private void SetBitFlag(BehaviorValidFlag flag, bool value) 
        {
            if ( value )
            {
                _behaviorValidFlag |= flag; 
            }
            else 
            { 
                _behaviorValidFlag &= (~flag);
            } 

        }

        ///  
        /// A helper returns behavior cursor flag from a behavior instance
        ///  
        ///  
        /// 
        private BehaviorValidFlag GetBehaviorCursorFlag(EditingBehavior behavior) 
        {
            BehaviorValidFlag flag = 0;

            if ( behavior == InkCollectionBehavior ) 
            {
                flag = BehaviorValidFlag.InkCollectionBehaviorCursorValid; 
            } 
            else if ( behavior == EraserBehavior )
            { 
                flag = BehaviorValidFlag.EraserBehaviorCursorValid;
            }
            else if ( behavior == LassoSelectionBehavior )
            { 
                flag = BehaviorValidFlag.LassoSelectionBehaviorCursorValid;
            } 
            else if ( behavior == SelectionEditingBehavior ) 
            {
                flag = BehaviorValidFlag.SelectionEditingBehaviorCursorValid; 
            }
            else if ( behavior == SelectionEditor )
            {
                flag = BehaviorValidFlag.SelectionEditorCursorValid; 
            }
            else 
            { 
                Debug.Assert(false, "Unknown behavior");
            } 

            return flag;
        }
 
        /// 
        /// A helper returns behavior transform flag from a behavior instance 
        ///  
        /// 
        ///  
        private BehaviorValidFlag GetBehaviorTransformFlag(EditingBehavior behavior)
        {
            BehaviorValidFlag flag = 0;
 
            if ( behavior == InkCollectionBehavior )
            { 
                flag = BehaviorValidFlag.InkCollectionBehaviorTransformValid; 
            }
            else if ( behavior == EraserBehavior ) 
            {
                flag = BehaviorValidFlag.EraserBehaviorTransformValid;
            }
            else if ( behavior == LassoSelectionBehavior ) 
            {
                flag = BehaviorValidFlag.LassoSelectionBehaviorTransformValid; 
            } 
            else if ( behavior == SelectionEditingBehavior )
            { 
                flag = BehaviorValidFlag.SelectionEditingBehaviorTransformValid;
            }
            else if ( behavior == SelectionEditor )
            { 
                flag = BehaviorValidFlag.SelectionEditorTransformValid;
            } 
            else 
            {
                Debug.Assert(false, "Unknown behavior"); 
            }

            return flag;
        } 

        private void ChangeEditingBehavior(EditingBehavior newBehavior) 
        { 
            Debug.Assert(!IsInMidStroke, "ChangeEditingBehavior cannot be called in a mid-stroke");
            Debug.Assert(_activationStack.Count <= 1, "The behavior stack has to contain at most one behavior when user is not editing."); 

            try
            {
                _inkCanvas.ClearSelection(true); 
            }
            finally 
            { 
                if ( ActiveEditingBehavior != null )
                { 
                    // Pop the old behavior.
                    PopEditingBehavior();
                }
 
                // Push the new behavior
                if ( newBehavior != null ) 
                { 
                    PushEditingBehavior(newBehavior);
                } 

                _inkCanvas.RaiseActiveEditingModeChanged(new RoutedEventArgs(InkCanvas.ActiveEditingModeChangedEvent, _inkCanvas));
            }
        } 

        ///  
        /// Update the Inverted state 
        /// 
        ///  
        /// 
        /// true if the behavior is updated
        private bool UpdateInvertedState(StylusDevice stylusDevice, bool stylusIsInverted)
        { 
            if ( !IsInMidStroke ||
                ( IsInMidStroke && IsInputDeviceCaptured(stylusDevice) )) 
            { 
                if ( stylusIsInverted != _stylusIsInverted )
                { 
                    _stylusIsInverted = stylusIsInverted;

                    //
                    // this can change editing state 
                    //
                    UpdateActiveEditingState(); 
 
                    return true;
                } 
            }

            return false;
        } 

        #endregion Private Methods 
 
        //-------------------------------------------------------------------------------
        // 
        // Private Properties
        //
        //-------------------------------------------------------------------------------
 
        #region Private Properties
 
        ///  
        /// Gets the top level active EditingBehavior
        ///  
        /// 
        private EditingBehavior ActiveEditingBehavior
        {
            get 
            {
                EditingBehavior EditingBehavior = null; 
                if ( _activationStack.Count > 0 ) 
                {
                    EditingBehavior = _activationStack.Peek(); 
                }
                return EditingBehavior;
            }
        } 

        ///  
        /// Lazy init access to the InkCollectionBehavior 
        /// 
        ///  
        internal InkCollectionBehavior InkCollectionBehavior
        {
            get
            { 
                if ( _inkCollectionBehavior == null )
                { 
                    _inkCollectionBehavior = new InkCollectionBehavior(this, _inkCanvas); 
                }
                return _inkCollectionBehavior; 
            }
        }

        ///  
        /// Lazy init access to the EraserBehavior
        ///  
        ///  
        private EraserBehavior EraserBehavior
        { 
            get
            {
                if ( _eraserBehavior == null )
                { 
                    _eraserBehavior = new EraserBehavior(this, _inkCanvas);
                } 
                return _eraserBehavior; 
            }
        } 

        #endregion Private Properties

        //------------------------------------------------------------------------------- 
        //
        // Private Enum 
        // 
        //--------------------------------------------------------------------------------
 
        #region Private Enum

        /// 
        /// Enum values which represent the cursor valid flag for each EditingBehavior. 
        /// 
        [Flags] 
        private enum BehaviorValidFlag 
        {
            InkCollectionBehaviorCursorValid      = 0x00000001, 
            EraserBehaviorCursorValid             = 0x00000002,
            LassoSelectionBehaviorCursorValid     = 0x00000004,
            SelectionEditingBehaviorCursorValid   = 0x00000008,
            SelectionEditorCursorValid            = 0x00000010, 
            InkCollectionBehaviorTransformValid   = 0x00000020,
            EraserBehaviorTransformValid          = 0x00000040, 
            LassoSelectionBehaviorTransformValid  = 0x00000080, 
            SelectionEditingBehaviorTransformValid= 0x00000100,
            SelectionEditorTransformValid         = 0x00000200, 
        }

        #endregion Private Enum
 
        //-------------------------------------------------------------------------------
        // 
        // Private Fields 
        //
        //-------------------------------------------------------------------------------- 

        #region Private Fields

        ///  
        /// The InkCanvas this EditingStack is being used in
        ///  
        private InkCanvas _inkCanvas; 
        private Stack _activationStack;
        private InkCollectionBehavior _inkCollectionBehavior; 
        private EraserBehavior _eraserBehavior;
        private LassoSelectionBehavior _lassoSelectionBehavior;
        private SelectionEditingBehavior _selectionEditingBehavior;
        private SelectionEditor _selectionEditor; 
        private bool _moveEnabled = true;
        private bool _resizeEnabled = true; 
        private bool _userIsEditing = false; 

        ///  
        /// Flag that indicates if the stylus is inverted
        /// 
        private bool _stylusIsInverted = false;
 
        private StylusPointDescription  _commonDescription;
        private StylusDevice            _capturedStylus; 
        private MouseDevice             _capturedMouse; 

        // Fields related to cursor and transform. 
        private BehaviorValidFlag       _behaviorValidFlag;

        #endregion Private Fields
 
    }
} 

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

Link Menu

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