TextEditorSelection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Documents / TextEditorSelection.cs / 1 / TextEditorSelection.cs

                            //---------------------------------------------------------------------------- 
//
// File: TextEditorSelection.cs
//
// Copyright (C) Microsoft Corporation.  All rights reserved. 
//
// Description: A component of TextEditor supporting selection and navigation 
// 
//---------------------------------------------------------------------------
 
namespace System.Windows.Documents
{
    using MS.Internal;
    using System.Globalization; 
    using System.Threading;
    using System.ComponentModel; 
    using System.Text; 
    using System.Collections; // ArrayList
    using System.Runtime.InteropServices; 
    using System.Security; // SecurityCritical attribute.

    using System.Windows.Threading;
    using System.Windows.Input; 
    using System.Windows.Controls; // ScrollChangedEventArgs
    using System.Windows.Controls.Primitives;  // CharacterCasing, TextBoxBase 
    using System.Windows.Media; 
    using System.Windows.Markup;
 
    using MS.Utility;
    using MS.Win32;
    using MS.Internal.Documents;
    using MS.Internal.Commands; // CommandHelpers 

    ///  
    /// Text editing service for controls. 
    /// 
    internal static class TextEditorSelection 
    {
        //-----------------------------------------------------
        //
        //  Class Internal Methods 
        //
        //----------------------------------------------------- 
 
        #region Class Internal Methods
 
        // Registers all text editing command handlers for a given control type

        ///
        ///     Critical - critical - calls a method that performs a link demand. CommandBinding ctor. 
        ///     TreatAsSafe - command bindings have link demands to prevent "hijacking" of built-in avalon commands.
        ///                           however registering our own internal commands is safe. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal static void _RegisterClassHandlers(Type controlType, bool registerEventListeners) 
        {
            // Standard Commands: Select All
            // -----------------------------
            CommandHelpers.RegisterCommandHandler(controlType, ApplicationCommands.SelectAll, Key.A, ModifierKeys.Control, new ExecutedRoutedEventHandler(OnSelectAll), null); 

            // Editing Commands : Caret Navigation 
            // ----------------------------------- 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveRightByCharacter, new ExecutedRoutedEventHandler(OnMoveRightByCharacter), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveRightByCharacter), SR.Get(SRID.KeyMoveRightByCharacterDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveLeftByCharacter, new ExecutedRoutedEventHandler(OnMoveLeftByCharacter), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveLeftByCharacter), SR.Get(SRID.KeyMoveLeftByCharacterDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveRightByWord, new ExecutedRoutedEventHandler(OnMoveRightByWord), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveRightByWord), SR.Get(SRID.KeyMoveRightByWordDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveLeftByWord, new ExecutedRoutedEventHandler(OnMoveLeftByWord), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveLeftByWord), SR.Get(SRID.KeyMoveLeftByWordDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveDownByLine, new ExecutedRoutedEventHandler(OnMoveDownByLine), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveDownByLine), SR.Get(SRID.KeyMoveDownByLineDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveUpByLine, new ExecutedRoutedEventHandler(OnMoveUpByLine), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveUpByLine), SR.Get(SRID.KeyMoveUpByLineDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveDownByParagraph, new ExecutedRoutedEventHandler(OnMoveDownByParagraph), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveDownByParagraph), SR.Get(SRID.KeyMoveDownByParagraphDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveUpByParagraph, new ExecutedRoutedEventHandler(OnMoveUpByParagraph), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveUpByParagraph), SR.Get(SRID.KeyMoveUpByParagraphDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveDownByPage, new ExecutedRoutedEventHandler(OnMoveDownByPage), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveDownByPage), SR.Get(SRID.KeyMoveDownByPageDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveUpByPage, new ExecutedRoutedEventHandler(OnMoveUpByPage), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveUpByPage), SR.Get(SRID.KeyMoveUpByPageDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveToLineStart, new ExecutedRoutedEventHandler(OnMoveToLineStart), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveToLineStart), SR.Get(SRID.KeyMoveToLineStartDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveToLineEnd, new ExecutedRoutedEventHandler(OnMoveToLineEnd), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveToLineEnd), SR.Get(SRID.KeyMoveToLineEndDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveToColumnStart, new ExecutedRoutedEventHandler(OnNYICommand), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveToColumnStart), SR.Get(SRID.KeyMoveToColumnStartDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveToColumnEnd, new ExecutedRoutedEventHandler(OnNYICommand), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveToColumnEnd), SR.Get(SRID.KeyMoveToColumnEndDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveToWindowTop, new ExecutedRoutedEventHandler(OnNYICommand), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveToWindowTop), SR.Get(SRID.KeyMoveToWindowTopDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveToWindowBottom, new ExecutedRoutedEventHandler(OnNYICommand), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveToWindowBottom), SR.Get(SRID.KeyMoveToWindowBottomDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveToDocumentStart, new ExecutedRoutedEventHandler(OnMoveToDocumentStart), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveToDocumentStart), SR.Get(SRID.KeyMoveToDocumentStartDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.MoveToDocumentEnd, new ExecutedRoutedEventHandler(OnMoveToDocumentEnd), new CanExecuteRoutedEventHandler(OnQueryStatusCaretNavigation), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeyMoveToDocumentEnd), SR.Get(SRID.KeyMoveToDocumentEndDisplayString))); 

            // Editing Commands: Selection Building 
            // ------------------------------------
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectRightByCharacter, new ExecutedRoutedEventHandler(OnSelectRightByCharacter), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectRightByCharacter), SR.Get(SRID.KeySelectRightByCharacterDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectLeftByCharacter, new ExecutedRoutedEventHandler(OnSelectLeftByCharacter), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectLeftByCharacter), SR.Get(SRID.KeySelectLeftByCharacterDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectRightByWord, new ExecutedRoutedEventHandler(OnSelectRightByWord), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectRightByWord), SR.Get(SRID.KeySelectRightByWordDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectLeftByWord, new ExecutedRoutedEventHandler(OnSelectLeftByWord), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectLeftByWord), SR.Get(SRID.KeySelectLeftByWordDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectDownByLine, new ExecutedRoutedEventHandler(OnSelectDownByLine), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectDownByLine), SR.Get(SRID.KeySelectDownByLineDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectUpByLine, new ExecutedRoutedEventHandler(OnSelectUpByLine), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectUpByLine), SR.Get(SRID.KeySelectUpByLineDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectDownByParagraph, new ExecutedRoutedEventHandler(OnSelectDownByParagraph), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectDownByParagraph), SR.Get(SRID.KeySelectDownByParagraphDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectUpByParagraph, new ExecutedRoutedEventHandler(OnSelectUpByParagraph), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectUpByParagraph), SR.Get(SRID.KeySelectUpByParagraphDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectDownByPage, new ExecutedRoutedEventHandler(OnSelectDownByPage), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectDownByPage), SR.Get(SRID.KeySelectDownByPageDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectUpByPage, new ExecutedRoutedEventHandler(OnSelectUpByPage), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectUpByPage), SR.Get(SRID.KeySelectUpByPageDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectToLineStart, new ExecutedRoutedEventHandler(OnSelectToLineStart), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectToLineStart), SR.Get(SRID.KeySelectToLineStartDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectToLineEnd, new ExecutedRoutedEventHandler(OnSelectToLineEnd), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectToLineEnd), SR.Get(SRID.KeySelectToLineEndDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectToColumnStart, new ExecutedRoutedEventHandler(OnNYICommand), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectToColumnStart), SR.Get(SRID.KeySelectToColumnStartDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectToColumnEnd, new ExecutedRoutedEventHandler(OnNYICommand), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectToColumnEnd), SR.Get(SRID.KeySelectToColumnEndDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectToWindowTop, new ExecutedRoutedEventHandler(OnNYICommand), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectToWindowTop), SR.Get(SRID.KeySelectToWindowTopDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectToWindowBottom, new ExecutedRoutedEventHandler(OnNYICommand), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectToWindowBottom), SR.Get(SRID.KeySelectToWindowBottomDisplayString)));
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectToDocumentStart, new ExecutedRoutedEventHandler(OnSelectToDocumentStart), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectToDocumentStart), SR.Get(SRID.KeySelectToDocumentStartDisplayString))); 
            CommandHelpers.RegisterCommandHandler(controlType, EditingCommands.SelectToDocumentEnd, new ExecutedRoutedEventHandler(OnSelectToDocumentEnd), new CanExecuteRoutedEventHandler(OnQueryStatusKeyboardSelection), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.KeySelectToDocumentEnd), SR.Get(SRID.KeySelectToDocumentEndDisplayString)));
        }

        ///  
        /// Clears the suggestedX variable of passed TextEditor.
        ///  
        /// TextEditor 
        internal static void _ClearSuggestedX(TextEditor This)
        { 
            // Discard stored horizontal position.
            // By setting to NaN, we indicate that the first following vertical movement
            // must define suggestedX from the current moving position.
            This._suggestedX = Double.NaN; 

            This._NextLineAdvanceMovingPosition = null; 
        } 

        // Returns a normalized line range from TextView for a given position. 
        // Note: In current contract, line range returned by TextView.GetLineRange() is not guaranteed to be normalized.
        // This helper does appropriate correction and returns a normalized line range.
        internal static TextSegment GetNormalizedLineRange(ITextView textView, ITextPointer position)
        { 
            TextSegment lineRange = textView.GetLineRange(position);
            if (lineRange.IsNull) 
            { 
                if (!typeof(BlockUIContainer).IsAssignableFrom(position.ParentType))
                { 
                    return lineRange;
                }

                ITextPointer lineStart = position.CreatePointer(LogicalDirection.Forward); 
                lineStart.MoveToElementEdge(ElementEdge.AfterStart);
                ITextPointer lineEnd = position.CreatePointer(LogicalDirection.Backward); 
                lineEnd.MoveToElementEdge(ElementEdge.BeforeEnd); 
                lineRange = new TextSegment(lineStart, lineEnd);
                return lineRange; 
            }

            // Normalize line range
            ITextRange textRange = new TextRange(lineRange.Start, lineRange.End); 
            return new TextSegment(textRange.Start, textRange.End);
        } 
 
        // Returns true if a textview is potentially paginated.
        internal static bool IsPaginated(ITextView textview) 
        {
            return !(textview is TextBoxView);
        }
 
        #endregion Class Internal Methods
 
        //------------------------------------------------------ 
        //
        //  Private Methods 
        //
        //-----------------------------------------------------

        #region Private Methods 

        ///  
        ///  
        private static void OnSelectAll(object target, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(target);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return;
            } 
 
            TextEditorTyping._FlushPendingInputItems(This);
 
            using (This.Selection.DeclareChangeBlock(true /* disableScroll */))
            {
                This.Selection.Select(This.TextContainer.Start, This.TextContainer.End);
 
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This); 
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This); 

                // Clear springload formatting
                ClearSpringloadFormatting(This);
            } 
        }
 
        // ................................................................ 
        //
        // Editing Commands: Caret Navigation 
        //
        // ................................................................

        ///  
        /// MoveRightByCharacter command event handler.
        ///  
        private static void OnMoveRightByCharacter(object target, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(target); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            {
                return; 
            }
 
            LogicalDirection movementDirection = IsFlowDirectionRightToLeftThenTopToBottom(This) ? LogicalDirection.Backward : LogicalDirection.Forward; 
            MoveToCharacterLogicalDirection(This, movementDirection, /*extend:*/false);
        } 

        /// 
        /// MoveLeftByCharacter command event handler.
        ///  
        private static void OnMoveLeftByCharacter(object target, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(target); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return;
            }
 
            LogicalDirection movementDirection = IsFlowDirectionRightToLeftThenTopToBottom(This) ? LogicalDirection.Forward : LogicalDirection.Backward;
            MoveToCharacterLogicalDirection(This, movementDirection, /*extend:*/false); 
        } 

 
        /// 
        /// 
        private static void OnMoveRightByWord(object target, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(target);
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return; 
            }

            // Navigate word to the logical forward.
            LogicalDirection movementDirection = IsFlowDirectionRightToLeftThenTopToBottom(This) ? LogicalDirection.Backward : LogicalDirection.Forward; 
            NavigateWordLogicalDirection(This, movementDirection);
        } 
 
        /// 
        ///  
        private static void OnMoveLeftByWord(object target, ExecutedRoutedEventArgs args)
        {
            TextEditor This = TextEditor._GetTextEditor(target);
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return; 
            }
 
            // Navigate word to the logical backward.
            LogicalDirection movementDirection = IsFlowDirectionRightToLeftThenTopToBottom(This) ? LogicalDirection.Forward : LogicalDirection.Backward;
            NavigateWordLogicalDirection(This, movementDirection);
        } 

        private static void OnMoveDownByLine(object sender, ExecutedRoutedEventArgs args) 
        { 
            TextEditor This = TextEditor._GetTextEditor(sender);
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            {
                return;
            } 

            TextEditorTyping._FlushPendingInputItems(This); 
 
            // We need a non-dirty layout to walk lines.
            if (!This.Selection.End.ValidateLayout()) 
            {
                return;
            }
 
            using (This.Selection.DeclareChangeBlock())
            { 
                if (!This.Selection.IsEmpty) 
                {
                    // If the selection is non-empty, collapse it. 
                    // Collapsing must happen to selection END - not to its moving position.
                    // It is Word behavior for setting a cratet on moving down from nonempty selection.

                    // When Selection.End is moving position we must adjust it 
                    // for LineEnd condition - choose inner position within a line.
                    ITextPointer position = TextEditorSelection.GetEndInner(This); 
 
                    This.Selection.SetCaretToPosition(position, position.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
                    TextEditorSelection._ClearSuggestedX(This); // So that when we will request suggestedX below it will take it from the new moving position 
                }
                Invariant.Assert(This.Selection.IsEmpty);

                // When the caret is at RowEnd position, we start by moving it into the last cell of this row. 
                AdjustCaretAtTableRowEnd(This);
 
                ITextPointer originalMovingPosition; 
                double suggestedX = TextEditorSelection.GetSuggestedX(This, out originalMovingPosition);
 
                // Continue only if we have a moving position with valid layout
                if (originalMovingPosition == null)
                {
                    return; 
                }
 
                // Extend the selection edge. 
                double newSuggestedX;
                int linesMoved; 
                ITextPointer newMovingPosition = This.TextView.GetPositionAtNextLine(This.Selection.MovingPosition, suggestedX, +1, out newSuggestedX, out linesMoved);
                Invariant.Assert(newMovingPosition != null);

                if (linesMoved != 0) 
                {
                    // Update suggestedX 
                    TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, newSuggestedX); 

                    // Move insertion point to next or previous line 
                    This.Selection.SetCaretToPosition(newMovingPosition, newMovingPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
                }
                else
                { 
                    if (TextPointerBase.IsInAnchoredBlock(originalMovingPosition))
                    { 
                        // TextView treats AnchoredBlock elements as hard structural boundaries. 
                        // As a result GetPositionAtNextLine() does not work from the first/last line within an AnchoredBlock.
 
                        // If line move wasn't successful because our moving position is at the end of an AnchoredBlock,
                        // move insertion point so that it crosses AnchoredBlock boundary.
                        // If there is no next position after the AnchoredBlock, move to current line end.
 
                        ITextPointer lineEndPosition = GetPositionAtLineEnd(originalMovingPosition);
                        ITextPointer nextPosition = lineEndPosition.GetNextInsertionPosition(LogicalDirection.Forward); 
                        This.Selection.SetCaretToPosition(nextPosition != null ? nextPosition : lineEndPosition, 
                            originalMovingPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
                    } 
                    else if (IsPaginated(This.TextView))
                    {
                        // If line move wasn't successful because it is not in the view, bring the next line into view.
                        This.TextView.BringLineIntoViewCompleted += new BringLineIntoViewCompletedEventHandler(HandleMoveByLineCompleted); 
                        This.TextView.BringLineIntoViewAsync(newMovingPosition, newSuggestedX, +1, This);
                    } 
                } 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This);

                // Clear springload formatting
                ClearSpringloadFormatting(This); 
            }
        } 
 
        private static void OnMoveUpByLine(object sender, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return;
            } 
 
            TextEditorTyping._FlushPendingInputItems(This);
 
            // We need a non-dirty layout to walk lines.
            if (!This.Selection.Start.ValidateLayout())
            {
                return; 
            }
 
            using (This.Selection.DeclareChangeBlock()) 
            {
                if (!This.Selection.IsEmpty) 
                {
                    // If the selection is non-empty, collapse it.
                    // Collapsing must happen to selection START - not to its moving position.
                    // It is Word behavior for setting a cratet on moving down from nonempty selection. 
                    ITextPointer position = TextEditorSelection.GetStartInner(This);
 
                    This.Selection.SetCaretToPosition(position, position.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true); 
                    TextEditorSelection._ClearSuggestedX(This); // So that when we will request suggestedX below it will take it from the new moving position
                } 
                Invariant.Assert(This.Selection.IsEmpty);

                // When the caret is at RowEnd position, we start by moving it into the last cell of this row.
                AdjustCaretAtTableRowEnd(This); 

                ITextPointer originalMovingPosition; 
                double suggestedX = TextEditorSelection.GetSuggestedX(This, out originalMovingPosition); 

                // Continue only if we have a moving position with valid layout 
                if (originalMovingPosition == null)
                {
                    return;
                } 

                // Extend the selection edge. 
                double newSuggestedX; 
                int linesMoved;
                ITextPointer newMovingPosition = This.TextView.GetPositionAtNextLine(This.Selection.MovingPosition, suggestedX, -1, out newSuggestedX, out linesMoved); 
                Invariant.Assert(newMovingPosition != null);

                if (linesMoved != 0)
                { 
                    // Update suggestedX
                    TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, newSuggestedX); 
 
                    // Move insertion point to next or previous line
                    // 
                    This.Selection.SetCaretToPosition(newMovingPosition, newMovingPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
                }
                else
                { 
                    if (TextPointerBase.IsInAnchoredBlock(originalMovingPosition))
                    { 
                        // TextView treats AnchoredBlock elements as hard structural boundaries. 
                        // As a result GetPositionAtNextLine() does not work from the first/last line within an AnchoredBlock.
 
                        // If line move wasn't successful because our moving position is at the end of an AnchoredBlock,
                        // move insertion point to a position before the AnchoredBlock boundary.
                        // If there is no previous position before the AnchoredBlock, move to current line start.
 
                        ITextPointer lineStartPosition = GetPositionAtLineStart(originalMovingPosition);
                        ITextPointer previousPosition = lineStartPosition.GetNextInsertionPosition(LogicalDirection.Backward); 
                        This.Selection.SetCaretToPosition(previousPosition != null ? previousPosition : lineStartPosition, 
                            originalMovingPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
                    } 
                    else if (IsPaginated(This.TextView))
                    {
                        // If line move wasn't successful because it is not in the view, bring the previous line into view.
                        This.TextView.BringLineIntoViewCompleted += new BringLineIntoViewCompletedEventHandler(HandleMoveByLineCompleted); 
                        This.TextView.BringLineIntoViewAsync(newMovingPosition, newSuggestedX, -1, This);
                    } 
                } 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This);

                // Clear springload formatting
                ClearSpringloadFormatting(This); 
            }
        } 
 
        private static void OnMoveDownByParagraph(object sender, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return;
            } 
 
            TextEditorTyping._FlushPendingInputItems(This);
 
            using (This.Selection.DeclareChangeBlock())
            {
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This); 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This); 

                // Clear springload formatting 
                ClearSpringloadFormatting(This);

                // Move/extend selection in requested direction
                if (!This.Selection.IsEmpty) 
                {
                    // If the selection is non-empty and ends on a word boundary, collapse it to that boundary. 
                    // Collapsing must happen to selection END - not to its moving position. 
                    // It is Word behavior for setting a cratet on moving down from nonempty selection.
 
                    // When Selection.End is moving position we must adjust it
                    // for LineEnd condition - choose inner position within a line.
                    ITextPointer position = TextEditorSelection.GetEndInner(This);
 
                    This.Selection.SetCaretToPosition(position, position.LogicalDirection, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false);
                } 
 
                ITextPointer movingPointer = This.Selection.MovingPosition.CreatePointer();
                ITextRange paragraphRange = new TextRange(movingPointer, movingPointer); 
                paragraphRange.SelectParagraph(movingPointer);

                movingPointer.MoveToPosition(paragraphRange.End);
                if (movingPointer.MoveToNextInsertionPosition(LogicalDirection.Forward)) 
                {
                    // Next paragraph found. Set selection to its start 
                    paragraphRange.SelectParagraph(movingPointer); 
                    This.Selection.SetCaretToPosition(paragraphRange.Start, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false);
                } 
                else
                {
                    // Next paragraph does not exist. Set selectionn to the end of current paragraph
                    This.Selection.SetCaretToPosition(paragraphRange.End, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false); 
                }
            } 
        } 

        private static void OnMoveUpByParagraph(object sender, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return; 
            } 

            TextEditorTyping._FlushPendingInputItems(This); 

            using (This.Selection.DeclareChangeBlock())
            {
                // Forget previously suggested horizontal position 
                TextEditorSelection._ClearSuggestedX(This);
 
                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This);
 
                // Clear springload formatting
                ClearSpringloadFormatting(This);

                // Move/extend selection in requested direction 
                if (!This.Selection.IsEmpty)
                { 
                    // If the selection is non-empty and ends on a word boundary, collapse it to that boundary. 
                    // Collapsing must happen to selection START - not to its moving position.
                    // It is Word behavior for setting a cratet on moving down from nonempty selection. 
                    ITextPointer position = TextEditorSelection.GetStartInner(This);

                    This.Selection.SetCaretToPosition(position, position.LogicalDirection, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false);
                } 
                ITextPointer movingPointer = This.Selection.MovingPosition.CreatePointer();
                ITextRange paragraphRange = new TextRange(movingPointer, movingPointer); 
                paragraphRange.SelectParagraph(movingPointer); 

                if (This.Selection.Start.CompareTo(paragraphRange.Start) > 0) 
                {
                    // We are in the middle of a paragraph. Move to its start
                    This.Selection.SetCaretToPosition(paragraphRange.Start, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false);
                } 
                else
                { 
                    movingPointer.MoveToPosition(paragraphRange.Start); 
                    if (movingPointer.MoveToNextInsertionPosition(LogicalDirection.Backward))
                    { 
                        // Previous paragraph found. Set selection to its start
                        paragraphRange.SelectParagraph(movingPointer);
                        This.Selection.SetCaretToPosition(paragraphRange.Start, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false);
                    } 
                }
            } 
        } 

        private static void OnMoveDownByPage(object sender, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return; 
            } 

            TextEditorTyping._FlushPendingInputItems(This); 

            // We need a non-dirty layout to walk pages.
            if (!This.Selection.End.ValidateLayout())
            { 
                return;
            } 
 
            using (This.Selection.DeclareChangeBlock())
            { 
                if (!This.Selection.IsEmpty)
                {
                    // If the selection is non-empty and ends on a word boundary, collapse it to that boundary.
                    // Collapsing must happen to selection END - not to its moving position. 
                    // It is Word behavior for setting a cratet on moving down from nonempty selection.
 
                    // When Selection.End is moving position we must adjust it 
                    // for LineEnd condition - choose inner position within a line.
                    ITextPointer position = TextEditorSelection.GetEndInner(This); 

                    This.Selection.SetCaretToPosition(position, position.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
                }
 
                ITextPointer movingPosition;
                double suggestedX = TextEditorSelection.GetSuggestedX(This, out movingPosition); 
 
                // Continue only if we have a moving position with valid layout
                if (movingPosition == null) 
                {
                    return;
                }
 
                ITextPointer targetPosition;
                double newSuggestedX; 
                double pageHeight = (double)This.UiScope.GetValue(TextEditor.PageHeightProperty); 

                // Presence of page height property on TextEditor instructs us to use simple bottomless version of 
                // pagination (TextBox/RichTextBox).
                // Otherwise, when page height = 0, we use TextView implementation of GetPositionAtNextPage().

                // 

 
                if (pageHeight == 0) 
                {
                    if (IsPaginated(This.TextView)) 
                    {
                        int pagesMoved;
                        Point newSuggestedOffset;
 
                        // Get suggested Y for moving position
                        double suggestedY = GetSuggestedYFromPosition(This, movingPosition); 
 
                        targetPosition = This.TextView.GetPositionAtNextPage(movingPosition, new Point(GetViewportXOffset(This.TextView, suggestedX), suggestedY), +1, out newSuggestedOffset, out pagesMoved);
                        newSuggestedX = newSuggestedOffset.X; 
                        Invariant.Assert(targetPosition != null);

                        if (pagesMoved != 0)
                        { 
                            // Update suggestedX
                            TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, newSuggestedX); 
 
                            // If shift key isn't down, collapse the range.
                            This.Selection.SetCaretToPosition(targetPosition, targetPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/false); 
                        }
                        else if (IsPaginated(This.TextView))
                        {
                            // If page move wasn't successful because it is not in the view, bring the next page into view. 
                            This.TextView.BringPageIntoViewCompleted += new BringPageIntoViewCompletedEventHandler(HandleMoveByPageCompleted);
                            This.TextView.BringPageIntoViewAsync(targetPosition, newSuggestedOffset, +1, This); 
                        } 
                    }
                } 
                else
                {
                    // Calculate target position - at a specified distance from current movingPosition
                    Rect targetRect = This.TextView.GetRectangleFromTextPosition(movingPosition); 
                    Point targetPoint = new Point(GetViewportXOffset(This.TextView, suggestedX), targetRect.Top + pageHeight);
                    targetPosition = This.TextView.GetTextPositionFromPoint(targetPoint, /*snapToText:*/true); 
 
                    if (targetPosition == null)
                    { 
                        return;
                    }

                    // Check if the new position really moving forward; 
                    // otherwise force it to the very end of container.
                    if (targetPosition.CompareTo(movingPosition) <= 0) 
                    { 
                        targetPosition = This.TextContainer.End;
                        TextEditorSelection._ClearSuggestedX(This); 
                    }

                    // Fire a page up/down command on the renderScope, so any ScrollViewer will pick it up
                    ScrollBar.PageDownCommand.Execute(null, This.TextView.RenderScope); 

                    // We need the page down to happen before the caret moves.  Force a layout update 
                    // so the command queue gets processed. 
                    This.TextView.RenderScope.UpdateLayout();
 
                    // If shift key isn't down, collapse the range.
                    This.Selection.SetCaretToPosition(targetPosition, targetPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/false);
                }
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This); 
 
                // Clear springload formatting
                ClearSpringloadFormatting(This); 
            }
        }

        private static void OnMoveUpByPage(object sender, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender); 
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return;
            }

            TextEditorTyping._FlushPendingInputItems(This); 

            // We need a non-dirty layout to walk pages. 
            if (!This.Selection.Start.ValidateLayout()) 
            {
                return; 
            }

            using (This.Selection.DeclareChangeBlock())
            { 
                if (!This.Selection.IsEmpty)
                { 
                    // If the selection is non-empty and ends on a word boundary, collapse it to that boundary. 
                    // Collapsing must happen to selection START - not to its moving position.
                    // It is Word behavior for setting a cratet on moving down from nonempty selection. 
                    ITextPointer position = TextEditorSelection.GetStartInner(This);

                    This.Selection.SetCaretToPosition(position, position.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
                } 

                ITextPointer movingPosition; 
                double suggestedX = TextEditorSelection.GetSuggestedX(This, out movingPosition); 

                // Continue only if we have a moving position with valid layout 
                if (movingPosition == null)
                {
                    return;
                } 

                ITextPointer targetPosition; 
                double newSuggestedX; 
                double pageHeight = (double)This.UiScope.GetValue(TextEditor.PageHeightProperty);
 
                // Presence of page height property on TextEditor instructs us to use simple bottomless version of
                // pagination (TextBox/RichTextBox).
                // Otherwise, when page height = 0, we use TextView implementation of GetPositionAtNextPage().
                if (pageHeight == 0) 
                {
                    if (IsPaginated(This.TextView)) 
                    { 
                        int pagesMoved;
                        Point newSuggestedOffset; 

                        // Get suggested Y for moving position
                        double suggestedY = GetSuggestedYFromPosition(This, movingPosition);
 
                        targetPosition = This.TextView.GetPositionAtNextPage(movingPosition, new Point(GetViewportXOffset(This.TextView, suggestedX), suggestedY), -1, out newSuggestedOffset, out pagesMoved);
                        newSuggestedX = newSuggestedOffset.X; 
                        Invariant.Assert(targetPosition != null); 

                        if (pagesMoved != 0) 
                        {
                            // Update suggestedX
                            TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, newSuggestedX);
 
                            // If shift key isn't down, collapse the range.
                            This.Selection.SetCaretToPosition(targetPosition, targetPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/false); 
                        } 
                        else if (IsPaginated(This.TextView))
                        { 
                            // If page move wasn't successful because it is not in the view, bring the next page into view.
                            This.TextView.BringPageIntoViewCompleted += new BringPageIntoViewCompletedEventHandler(HandleMoveByPageCompleted);
                            This.TextView.BringPageIntoViewAsync(targetPosition, newSuggestedOffset, -1, This);
                        } 
                    }
                } 
                else 
                {
                    // Calculate target position - at a specified distance from current movingPosition 
                    Rect targetRect = This.TextView.GetRectangleFromTextPosition(movingPosition);
                    Point targetPoint = new Point(GetViewportXOffset(This.TextView, suggestedX), targetRect.Bottom - pageHeight);
                    targetPosition = This.TextView.GetTextPositionFromPoint(targetPoint, /*snapToText:*/true);
 
                    if (targetPosition == null)
                    { 
                        return; 
                    }
 
                    // Check if the new position really moving forward;
                    // otherwise force it to the very end of container.
                    if (targetPosition.CompareTo(movingPosition) >= 0)
                    { 
                        targetPosition = This.TextContainer.Start;
                        TextEditorSelection._ClearSuggestedX(This); 
                    } 

                    // Fire a page up/down command on the renderScope, so any ScrollViewer will pick it up 
                    ScrollBar.PageUpCommand.Execute(null, This.TextView.RenderScope);

                    // We need the page down to happen before the caret moves.  Force a layout update
                    // so the command queue gets processed. 
                    This.TextView.RenderScope.UpdateLayout();
 
                    // If shift key isn't down, collapse the range. 
                    This.Selection.SetCaretToPosition(targetPosition, targetPosition.LogicalDirection, /*allowStopAtLineEnd:*/
                                                      true, /*allowStopNearSpace:*/false); 
                }

                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This); 

                // Clear springload formatting 
                ClearSpringloadFormatting(This); 
            }
        } 

        /// 
        /// 
        private static void OnMoveToLineStart(object target, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(target); 
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return;
            }

            TextEditorTyping._FlushPendingInputItems(This); 

            // When getting start position, we need to take care of end-of-line case 
            // and adjust start position according to its orientation. 
            ITextPointer startPositionInner = TextEditorSelection.GetStartInner(This);
 
            // We need a non-dirty layout to walk pages.
            if (!startPositionInner.ValidateLayout())
            {
                return; 
            }
 
            // Standard behavior, move to begin/end of line. 
            TextSegment lineRange = TextEditorSelection.GetNormalizedLineRange(This.TextView, startPositionInner);
            if (lineRange.IsNull) 
            {
                return;
            }
 
            using (This.Selection.DeclareChangeBlock())
            { 
                // Note caret direction here: must be forward to keep caret on the same line 
                //
 
                // Create caret position normalized forward - towards the very first character of the line
                ITextPointer caretPosition = lineRange.Start.GetFrozenPointer(LogicalDirection.Forward);

                // Set caret to beginning of a line 
                This.Selection.SetCaretToPosition(caretPosition, LogicalDirection.Forward, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
 
                // Forget previously suggested horizontal position 
                TextEditorSelection._ClearSuggestedX(This);
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This);

                // Clear springload formatting 
                ClearSpringloadFormatting(This);
            } 
        } 

        ///  
        /// 
        private static void OnMoveToLineEnd(object target, ExecutedRoutedEventArgs args)
        {
            TextEditor This = TextEditor._GetTextEditor(target); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            { 
                return;
            } 

            TextEditorTyping._FlushPendingInputItems(This);

            // When getting end position, we need to take care of end-of-line case 
            // and adjust end position according to its orientation.
            ITextPointer endPositionInner = TextEditorSelection.GetEndInner(This); 
 
            // We need a non-dirty layout to walk pages.
            if (!endPositionInner.ValidateLayout()) 
            {
                return;
            }
 
            TextSegment lineRange = TextEditorSelection.GetNormalizedLineRange(This.TextView, endPositionInner);
            if (lineRange.IsNull) 
            { 
                return;
            } 

            using (This.Selection.DeclareChangeBlock())
            {
                // Note caret direction here: must be backward to keep caret on the same line when it is wrapped by flow. 
                // Orientation must be Backward when the line is wrapped by flow, otherwise - normal Forward
                LogicalDirection orientation = TextPointerBase.IsNextToPlainLineBreak(lineRange.End, LogicalDirection.Backward) ? LogicalDirection.Forward : LogicalDirection.Backward; 
 
                // Create caret position normalized the same way as orientation
                ITextPointer caretPosition = lineRange.End.GetFrozenPointer(orientation); 

                // Set caret to the end of line
                This.Selection.SetCaretToPosition(caretPosition, orientation, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
 
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This); 
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This); 

                // Clear springload formatting
                ClearSpringloadFormatting(This);
            } 
        }
 
        ///  
        /// 
        private static void OnMoveToDocumentStart(object target, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(target);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return; 
            } 

            TextEditorTyping._FlushPendingInputItems(This); 

            using (This.Selection.DeclareChangeBlock())
            {
                This.Selection.SetCaretToPosition(This.TextContainer.Start, LogicalDirection.Forward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false); 

                // Forget previously suggested horizontal position 
                TextEditorSelection._ClearSuggestedX(This); 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This);

                // Clear springload formatting
                ClearSpringloadFormatting(This); 
            }
        } 
 
        /// 
        ///  
        private static void OnMoveToDocumentEnd(object target, ExecutedRoutedEventArgs args)
        {
            TextEditor This = TextEditor._GetTextEditor(target);
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return; 
            }
 
            TextEditorTyping._FlushPendingInputItems(This);

            using (This.Selection.DeclareChangeBlock())
            { 
                // Orientation is standard - forward, because text cannot wrap by flow at this position
                This.Selection.SetCaretToPosition(This.TextContainer.End, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false); 
 
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This); 

                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This);
 
                // Clear springload formatting
                ClearSpringloadFormatting(This); 
            } 
        }
 
        // ................................................................
        //
        // Editing Commands: Selection Building
        // 
        // ................................................................
 
        ///  
        /// SelectRightByCharacter command event handler.
        ///  
        private static void OnSelectRightByCharacter(object target, ExecutedRoutedEventArgs args)
        {
            TextEditor This = TextEditor._GetTextEditor(target);
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return; 
            }
 
            LogicalDirection movementDirection = IsFlowDirectionRightToLeftThenTopToBottom(This) ? LogicalDirection.Backward : LogicalDirection.Forward;
            MoveToCharacterLogicalDirection(This, movementDirection, /*extend:*/true);
        }
 
        /// 
        /// SelectLeftByCharacter command event handler. 
        ///  
        private static void OnSelectLeftByCharacter(object target, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(target);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return;
            } 
 
            LogicalDirection movementDirection = IsFlowDirectionRightToLeftThenTopToBottom(This) ? LogicalDirection.Forward : LogicalDirection.Backward;
            MoveToCharacterLogicalDirection(This, movementDirection, /*extend:*/true); 
        }

        /// 
        ///  
        private static void OnSelectRightByWord(object target, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(target); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return;
            }
 
            // Extend word to the logical forward.
            LogicalDirection movementDirection = IsFlowDirectionRightToLeftThenTopToBottom(This) ? LogicalDirection.Backward : LogicalDirection.Forward; 
            ExtendWordLogicalDirection(This, movementDirection); 
        }
 
        /// 
        /// 
        private static void OnSelectLeftByWord(object target, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(target);
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return; 
            }

            // Extend word to the logical backward.
            LogicalDirection movementDirection = IsFlowDirectionRightToLeftThenTopToBottom(This) ? LogicalDirection.Forward : LogicalDirection.Backward; 
            ExtendWordLogicalDirection(This, movementDirection);
        } 
 
        private static void OnSelectDownByLine(object sender, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return;
            } 
 
            // We need a non-dirty layout to walk lines.
            TextEditorTyping._FlushPendingInputItems(This); 

            using (This.Selection.DeclareChangeBlock())
            {
                if (This.Selection.ExtendToNextTableRow(LogicalDirection.Forward)) 
                {
                    // This is table selection case. Vertical extension. 
                    // Table selection has been successfully extended in vertical direction. 
                    // Nothing more to do.
                } 
                else
                {
                    ITextPointer originalMovingPosition;
                    double suggestedX = TextEditorSelection.GetSuggestedX(This, out originalMovingPosition); 

                    // Continue only if we have a moving position with valid layout 
                    if (originalMovingPosition == null) 
                    {
                        return; 
                    }

                    if (This._NextLineAdvanceMovingPosition != null &&
                        This._IsNextLineAdvanceMovingPositionAtDocumentHead) 
                    {
                        // Moving position is at the beginning of text container 
                        // as a result of previous Shift+Up extension; 
                        // so now we need to return to a positing within the current line
                        ExtendSelectionAndBringIntoView(This._NextLineAdvanceMovingPosition, This); 
                        This._NextLineAdvanceMovingPosition = null;
                    }
                    else
                    { 
                        // When the moving position is at RowEnd position, we start by moving it into the last cell of this row.
                        ITextPointer newMovingPosition = AdjustPositionAtTableRowEnd(originalMovingPosition); 
 
                        // Find a position in the next line
                        double newSuggestedX; 
                        int linesMoved;

                        newMovingPosition = This.TextView.GetPositionAtNextLine(newMovingPosition, suggestedX, +1, out newSuggestedX, out linesMoved);
                        Invariant.Assert(newMovingPosition != null); 

                        if (linesMoved != 0) 
                        { 
                            // Update suggestedX
                            TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, newSuggestedX); 

                            // Shift key is down - Extend the selection edge
                            AdjustMovingPositionForSelectDownByLine(This, newMovingPosition, originalMovingPosition, newSuggestedX);
                        } 
                        else
                        { 
                            if (TextPointerBase.IsInAnchoredBlock(originalMovingPosition)) 
                            {
                                // TextView treats AnchoredBlock elements as hard structural boundaries. 
                                // As a result GetPositionAtNextLine() does not work from the first/last line within an AnchoredBlock.

                                // If line move wasn't successful because our moving position is at the end of an AnchoredBlock,
                                // expand selection so that it crosses AnchoredBlock boundary. 
                                // If there is no next position after the AnchoredBlock, expand to current line end.
 
                                ITextPointer lineEndPosition = GetPositionAtLineEnd(originalMovingPosition); 
                                ITextPointer nextPosition = lineEndPosition.GetNextInsertionPosition(LogicalDirection.Forward);
 
                                // Extend selection and bring new position into view if needed (for paginated viewers)
                                ExtendSelectionAndBringIntoView(nextPosition != null ? nextPosition : lineEndPosition, This);
                            }
                            else if (IsPaginated(This.TextView)) 
                            {
                                // If line move wasn't successful because it is not in the view, bring the next line into view. 
                                This.TextView.BringLineIntoViewCompleted += new BringLineIntoViewCompletedEventHandler(HandleSelectByLineCompleted); 
                                This.TextView.BringLineIntoViewAsync(newMovingPosition, newSuggestedX, +1, This);
                            } 
                            else
                            {
                                // Remember where we were so that we can return if a line up follows.
                                if (This._NextLineAdvanceMovingPosition == null) 
                                {
                                    This._NextLineAdvanceMovingPosition = originalMovingPosition; 
                                    This._IsNextLineAdvanceMovingPositionAtDocumentHead = false; 
                                }
                                // No more lines in this direction. Move to end of current line. 
                                ExtendSelectionAndBringIntoView(GetPositionAtLineEnd(newMovingPosition), This);
                            }
                        }
                    } 
                }
 
                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This);
 
                // Clear springload formatting
                ClearSpringloadFormatting(This);
            }
        } 

        // Helper for OnSelectDownByLine.  Updates the selection moving position 
        // during select down by line. 
        private static void AdjustMovingPositionForSelectDownByLine(TextEditor This, ITextPointer newMovingPosition, ITextPointer originalMovingPosition, double suggestedX)
        { 
            int newComparedToOld = newMovingPosition.CompareTo(originalMovingPosition);

            // Note: we compare orientations of equal positions to handle a case
            // when original position was at the end of line (after its linebreak with backward orientation) 
            // as a result of Shift+End selection; and the new position is in the beginning of the next line,
            // which is essentially the same position but oriented differently. 
            // In such a case the new position is good enough to go there. 
            // We certainly don't want to go to the end of the document in this case.
            if (newComparedToOld > 0 || newComparedToOld == 0 && newMovingPosition.LogicalDirection != originalMovingPosition.LogicalDirection) 
            {
                // We have another line in a given direction; move to it

                // If the destination exactly preceeds a line break, expand to include 
                // the line break if we haven't reached our desired suggestedX.
                if (TextPointerBase.IsNextToAnyBreak(newMovingPosition, LogicalDirection.Forward) || 
                    newMovingPosition.GetNextInsertionPosition(LogicalDirection.Forward) == null) 
                {
                    double newPositionX = GetAbsoluteXOffset(This.TextView, newMovingPosition); 
                    FlowDirection paragraphFlowDirection = GetScopingParagraphFlowDirection(newMovingPosition);
                    FlowDirection controlFlowDirection = This.UiScope.FlowDirection;

                    if ((paragraphFlowDirection == controlFlowDirection && newPositionX < suggestedX) || 
                        (paragraphFlowDirection != controlFlowDirection && newPositionX > suggestedX))
                    { 
                        newMovingPosition = newMovingPosition.GetInsertionPosition(LogicalDirection.Forward); 
                        newMovingPosition = newMovingPosition.GetNextInsertionPosition(LogicalDirection.Forward);
 
                        // If we're at the last Paragraph, move to document end to include
                        // the final paragraph break.
                        if (newMovingPosition == null)
                        { 
                            newMovingPosition = originalMovingPosition.TextContainer.End;
                        } 
 
                        newMovingPosition = newMovingPosition.GetFrozenPointer(LogicalDirection.Backward);
                    } 
                }

                ExtendSelectionAndBringIntoView(newMovingPosition, This);
            } 
            else
            { 
                // Remember where we were so that we can return if a line up follows. 
                if (This._NextLineAdvanceMovingPosition == null)
                { 
                    This._NextLineAdvanceMovingPosition = originalMovingPosition;
                    This._IsNextLineAdvanceMovingPositionAtDocumentHead = false;
                }
 
                // No more lines in this direction. Move to end of current line.
                newMovingPosition = GetPositionAtLineEnd(originalMovingPosition); 
 
                if (newMovingPosition.GetNextInsertionPosition(LogicalDirection.Forward) == null)
                { 
                    // Move to the final implicit line at end-of-doc.
                    newMovingPosition = newMovingPosition.TextContainer.End;
                }
 
                ExtendSelectionAndBringIntoView(newMovingPosition, This);
            } 
        } 

        private static void OnSelectUpByLine(object sender, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return; 
            } 

            // We need a non-dirty layout to walk lines. 
            TextEditorTyping._FlushPendingInputItems(This);

            using (This.Selection.DeclareChangeBlock())
            { 
                if (This.Selection.ExtendToNextTableRow(LogicalDirection.Backward))
                { 
                    // This is table selection case. Vertical extension. 
                    // Table selection has been successfully extended in vertical direction.
                    // Nothing more to do. 
                }
                else
                {
                    ITextPointer originalMovingPosition; 
                    double suggestedX = TextEditorSelection.GetSuggestedX(This, out originalMovingPosition);
 
                    // Continue only if we have a moving position with valid layout 
                    if (originalMovingPosition == null)
                    { 
                        return;
                    }

                    if (This._NextLineAdvanceMovingPosition != null && 
                        !This._IsNextLineAdvanceMovingPositionAtDocumentHead)
                    { 
                        // Moving position is at the end of text container 
                        // as a result of previous Shift+Down extension;
                        // so now we need to return to a positing within the current line 
                        ExtendSelectionAndBringIntoView(This._NextLineAdvanceMovingPosition, This);
                        This._NextLineAdvanceMovingPosition = null;
                    }
                    else 
                    {
                        // When the moving position is at RowEnd position, we start by moving it into the last cell of this row. 
                        ITextPointer newMovingPosition = AdjustPositionAtTableRowEnd(originalMovingPosition); 

                        // Extend the selection edge. 
                        double newSuggestedX;
                        int linesMoved;

                        newMovingPosition = This.TextView.GetPositionAtNextLine(newMovingPosition, suggestedX, -1, out newSuggestedX, out linesMoved); 
                        Invariant.Assert(newMovingPosition != null);
 
                        if (linesMoved != 0) 
                        {
                            // Update suggestedX 
                            TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, newSuggestedX);

                            int newComparedToOld = newMovingPosition.CompareTo(originalMovingPosition);
 
                            // Shift key is down - Extend the selection edge
                            if (newComparedToOld < 0 || newComparedToOld == 0 && newMovingPosition.LogicalDirection != originalMovingPosition.LogicalDirection) 
                            { 
                                // Note: we compare orientations of equal positions to handle a case
                                // when original position was at the end of line (after its linebreak with backward orientation) 
                                // as a result of Shift+End selection; and the new position is in the beginning of the next line,
                                // which is essentially the same position but oriented differently.
                                // In such a case the new position is good enough to go there.
                                // We certainly don't want to go to the end of the document in this case. 

                                // We have another line in a given direction; move to it 
                                ExtendSelectionAndBringIntoView(newMovingPosition, This); 
                            }
                            else 
                            {
                                // No more lines in this direction. Move to current line start.
                                ExtendSelectionAndBringIntoView(GetPositionAtLineStart(originalMovingPosition), This);
                            } 
                        }
                        else 
                        { 
                            if (TextPointerBase.IsInAnchoredBlock(originalMovingPosition))
                            { 
                                // TextView treats AnchoredBlock elements as hard structural boundaries.
                                // As a result GetPositionAtNextLine() does not work from the first/last line within an AnchoredBlock.

                                // If line move wasn't successful because our moving position is at the start of an AnchoredBlock, 
                                // expand selection so that it crosses AnchoredBlock boundary.
                                // If there is no previous position before the AnchoredBlock, expand to current line start. 
 
                                ITextPointer lineStartPosition = GetPositionAtLineStart(originalMovingPosition);
                                ITextPointer previousPosition = lineStartPosition.GetNextInsertionPosition(LogicalDirection.Backward); 

                                // Extend selection and bring new position into view if needed (for paginated viewers)
                                ExtendSelectionAndBringIntoView(previousPosition != null ? previousPosition : lineStartPosition, This);
                            } 
                            else if (IsPaginated(This.TextView))
                            { 
                                // If line move wasn't successful because it is not in the view, bring the previous line into view. 
                                This.TextView.BringLineIntoViewCompleted += new BringLineIntoViewCompletedEventHandler(HandleSelectByLineCompleted);
                                This.TextView.BringLineIntoViewAsync(newMovingPosition, newSuggestedX, -1, This); 
                            }
                            else
                            {
                                // Remember where we were so that we can return if a line down follows. 
                                if (This._NextLineAdvanceMovingPosition == null)
                                { 
                                    This._NextLineAdvanceMovingPosition = originalMovingPosition; 
                                    This._IsNextLineAdvanceMovingPositionAtDocumentHead = true;
                                } 
                                // No more lines in this direction. Move to start of current line.
                                ExtendSelectionAndBringIntoView(GetPositionAtLineStart(newMovingPosition), This);
                            }
                        } 
                    }
                } 
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This); 

                // Clear springload formatting
                ClearSpringloadFormatting(This);
            } 
        }
 
        private static void OnSelectDownByParagraph(object sender, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            {
                return; 
            }
 
            TextEditorTyping._FlushPendingInputItems(This); 

            using (This.Selection.DeclareChangeBlock()) 
            {
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This);
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This); 
 
                // Clear springload formatting
                ClearSpringloadFormatting(This); 

                ITextPointer movingPointer = This.Selection.MovingPosition.CreatePointer();
                ITextRange paragraphRange = new TextRange(movingPointer, movingPointer);
                paragraphRange.SelectParagraph(movingPointer); 

                movingPointer.MoveToPosition(paragraphRange.End); 
                if (movingPointer.MoveToNextInsertionPosition(LogicalDirection.Forward)) 
                {
                    // Next paragraph found. Set selection to its start 
                    paragraphRange.SelectParagraph(movingPointer);
                    ExtendSelectionAndBringIntoView(paragraphRange.Start, This);
                }
                else 
                {
                    // Next paragraph does not exist. Set selectionn to the end of current paragraph 
                    ExtendSelectionAndBringIntoView(paragraphRange.End, This); 
                }
            } 
        }

        private static void OnSelectUpByParagraph(object sender, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(sender);
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return; 
            }

            TextEditorTyping._FlushPendingInputItems(This);
 
            using (This.Selection.DeclareChangeBlock())
            { 
                // Forget previously suggested horizontal position 
                TextEditorSelection._ClearSuggestedX(This);
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This);

                // Clear springload formatting 
                ClearSpringloadFormatting(This);
 
                ITextPointer movingPointer = This.Selection.MovingPosition.CreatePointer(); 
                ITextRange paragraphRange = new TextRange(movingPointer, movingPointer);
                paragraphRange.SelectParagraph(movingPointer); 

                if (movingPointer.CompareTo(paragraphRange.Start) > 0)
                {
                    // We are in the middle of a paragraph. Move to its start 
                    ExtendSelectionAndBringIntoView(paragraphRange.Start, This);
                } 
                else 
                {
                    movingPointer.MoveToPosition(paragraphRange.Start); 
                    if (movingPointer.MoveToNextInsertionPosition(LogicalDirection.Backward))
                    {
                        // Previous paragraph found. Set selection to its start
                        paragraphRange.SelectParagraph(movingPointer); 
                        ExtendSelectionAndBringIntoView(paragraphRange.Start, This);
                    } 
                } 
            }
        } 

        private static void OnSelectDownByPage(object sender, ExecutedRoutedEventArgs args)
        {
            TextEditor This = TextEditor._GetTextEditor(sender); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            { 
                return;
            } 

            TextEditorTyping._FlushPendingInputItems(This);

            ITextPointer movingPosition; 
            double suggestedX = TextEditorSelection.GetSuggestedX(This, out movingPosition);
 
            // Continue only if we have a moving position with valid layout. 
            if (movingPosition == null)
            { 
                return;
            }

            using (This.Selection.DeclareChangeBlock()) 
            {
                ITextPointer targetPosition; 
                double newSuggestedX; 
                double pageHeight = (double)This.UiScope.GetValue(TextEditor.PageHeightProperty);
 
                // Presence of page height property on TextEditor instructs us to use simple bottomless version of
                // pagination (TextBox/RichTextBox).
                // Otherwise, when page height = 0, we use TextView implementation of GetPositionAtNextPage().
                if (pageHeight == 0) 
                {
                    if (IsPaginated(This.TextView)) 
                    { 
                        int pagesMoved;
                        Point newSuggestedOffset; 

                        // Get suggested Y for moving position
                        double suggestedY = GetSuggestedYFromPosition(This, movingPosition);
 
                        targetPosition = This.TextView.GetPositionAtNextPage(movingPosition, new Point(GetViewportXOffset(This.TextView, suggestedX), suggestedY), +1, out newSuggestedOffset, out pagesMoved);
                        newSuggestedX = newSuggestedOffset.X; 
                        Invariant.Assert(targetPosition != null); 

                        if (pagesMoved != 0) 
                        {
                            // Update suggestedX
                            TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, newSuggestedX);
                            ExtendSelectionAndBringIntoView(targetPosition, This); 
                        }
                        else if (IsPaginated(This.TextView)) 
                        { 
                            // If page move wasn't successful because it is not in the view, bring the next page into view.
                            This.TextView.BringPageIntoViewCompleted += new BringPageIntoViewCompletedEventHandler(HandleSelectByPageCompleted); 
                            This.TextView.BringPageIntoViewAsync(targetPosition, newSuggestedOffset, +1, This);
                        }
                        else
                        { 
                            // No more pages in this direction. Move to container end.
                            ExtendSelectionAndBringIntoView(targetPosition.TextContainer.End, This); 
                        } 
                    }
                } 
                else
                {
                    // Calculate target position - at a specified distance from current movingPosition
                    Rect targetRect = This.TextView.GetRectangleFromTextPosition(movingPosition); 
                    Point targetPoint = new Point(GetViewportXOffset(This.TextView, suggestedX), targetRect.Top + pageHeight);
                    targetPosition = This.TextView.GetTextPositionFromPoint(targetPoint, /*snapToText:*/true); 
 
                    if (targetPosition == null)
                    { 
                        return;
                    }

                    // Check if the new position really moving forward; 
                    // otherwise force it to the very end of container.
                    if (targetPosition.CompareTo(movingPosition) <= 0) 
                    { 
                        targetPosition = This.TextContainer.End;
                    } 

                    // Extend the selection edge.
                    ExtendSelectionAndBringIntoView(targetPosition, This);
 
                    // Fire a page up/down command on the renderScope, so any ScrollViewer will pick it up
                    ScrollBar.PageDownCommand.Execute(null, This.TextView.RenderScope); 
                } 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This);

                // Clear springload formatting
                ClearSpringloadFormatting(This); 
            }
        } 
 
        private static void OnSelectUpByPage(object sender, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            { 
                return;
            } 
 
            TextEditorTyping._FlushPendingInputItems(This);
 
            ITextPointer movingPosition;
            double suggestedX = TextEditorSelection.GetSuggestedX(This, out movingPosition);

            // Continue only if we have a moving position with valid layout. 
            if (movingPosition == null)
            { 
                return; 
            }
 
            using (This.Selection.DeclareChangeBlock())
            {
                ITextPointer targetPosition;
                double newSuggestedX; 
                double pageHeight = (double)This.UiScope.GetValue(TextEditor.PageHeightProperty);
 
                // Presence of page height property on TextEditor instructs us to use simple bottomless version of 
                // pagination (TextBox/RichTextBox).
                // Otherwise, when page height = 0, we use TextView implementation of GetPositionAtNextPage(). 
                if (pageHeight == 0)
                {
                    if (IsPaginated(This.TextView))
                    { 
                        int pagesMoved;
                        Point newSuggestedOffset; 
 
                        // Get suggested Y for moving position
                        double suggestedY = GetSuggestedYFromPosition(This, movingPosition); 

                        targetPosition = This.TextView.GetPositionAtNextPage(movingPosition, new Point(GetViewportXOffset(This.TextView, suggestedX), suggestedY), -1, out newSuggestedOffset, out pagesMoved);
                        newSuggestedX = newSuggestedOffset.X;
                        Invariant.Assert(targetPosition != null); 

                        if (pagesMoved != 0) 
                        { 
                            // Update suggestedX
                            TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, newSuggestedX); 
                            ExtendSelectionAndBringIntoView(targetPosition, This);
                        }
                        else if (IsPaginated(This.TextView))
                        { 
                            // If page move wasn't successful because it is not in the view, bring the next page into view.
                            This.TextView.BringPageIntoViewCompleted += new BringPageIntoViewCompletedEventHandler(HandleSelectByPageCompleted); 
                            This.TextView.BringPageIntoViewAsync(targetPosition, newSuggestedOffset, -1, This); 
                        }
                        else 
                        {
                            // No more pages in this direction. Move to container start.
                            ExtendSelectionAndBringIntoView(targetPosition.TextContainer.Start, This);
                        } 
                    }
                } 
                else 
                {
                    // Calculate target position - at a specified distance from current movingPosition 
                    Rect targetRect = This.TextView.GetRectangleFromTextPosition(movingPosition);
                    Point targetPoint = new Point(GetViewportXOffset(This.TextView, suggestedX), targetRect.Bottom - pageHeight);
                    targetPosition = This.TextView.GetTextPositionFromPoint(targetPoint, /*snapToText:*/true);
 
                    if (targetPosition == null)
                    { 
                        return; 
                    }
 
                    // Check if the new position really moving forward;
                    // otherwise force it to the very end of container.
                    if (targetPosition.CompareTo(movingPosition) >= 0)
                    { 
                        targetPosition = This.TextContainer.Start;
                    } 
 
                    // Extend the selection edge.
                    ExtendSelectionAndBringIntoView(targetPosition, This); 

                    // Fire a page up/down command on the renderScope, so any ScrollViewer will pick it up
                    ScrollBar.PageUpCommand.Execute(null, This.TextView.RenderScope);
                } 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This); 

                // Clear springload formatting 
                ClearSpringloadFormatting(This);
            }
        }
 
        /// 
        ///  
        private static void OnSelectToLineStart(object target, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(target); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            {
                return; 
            }
 
            TextEditorTyping._FlushPendingInputItems(This); 

            // When getting moving position, we need to take care of end-of-line case 
            // and adjust moving position according to its orientation.
            ITextPointer movingPositionInner = TextEditorSelection.GetMovingPositionInner(This);

            // We need a non-dirty layout to walk pages. 
            if (!movingPositionInner.ValidateLayout())
            { 
                return; 
            }
 
            TextSegment lineRange = TextEditorSelection.GetNormalizedLineRange(This.TextView, movingPositionInner);
            if (lineRange.IsNull)
            {
                return; 
            }
 
            using (This.Selection.DeclareChangeBlock()) 
            {
                // Extend the selection from the active end (oriented forward) 
                ExtendSelectionAndBringIntoView(lineRange.Start.CreatePointer(LogicalDirection.Forward), This);

                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This); 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This); 

                // Clear springload formatting 
                ClearSpringloadFormatting(This);
            }
        }
 
        /// 
        ///  
        private static void OnSelectToLineEnd(object target, ExecutedRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(target); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            {
                return; 
            }
 
            TextEditorTyping._FlushPendingInputItems(This); 

            // When getting moving position, we need to take care of end-of-line case 
            // and adjust moving position according to its orientation.
            ITextPointer movingPositionInner = TextEditorSelection.GetMovingPositionInner(This);

            // We need a non-dirty layout to walk pages. 
            if (!movingPositionInner.ValidateLayout())
            { 
                return; 
            }
 
            TextSegment lineRange = TextEditorSelection.GetNormalizedLineRange(This.TextView, movingPositionInner);
            if (lineRange.IsNull)
            {
                return; 
            }
 
            // The selection end is on the other side of a line break, don't move it. 
            if (lineRange.End.CompareTo(This.Selection.End) < 0)
            { 
                return;
            }

            using (This.Selection.DeclareChangeBlock()) 
            {
                ITextPointer destination = lineRange.End; 
 
                if (TextPointerBase.IsNextToPlainLineBreak(destination, LogicalDirection.Forward) ||
                    TextPointerBase.IsNextToRichLineBreak(destination, LogicalDirection.Forward)) 
                {
                    // Extend to include any following line break if the anchor position lies at the start of a line.

                    if (This.Selection.AnchorPosition.ValidateLayout()) 
                    {
                        TextSegment anchorLineRange = TextEditorSelection.GetNormalizedLineRange(This.TextView, This.Selection.AnchorPosition); 
                        if (!lineRange.IsNull && anchorLineRange.Start.CompareTo(This.Selection.AnchorPosition) == 0) 
                        {
                            destination = destination.GetNextInsertionPosition(LogicalDirection.Forward); 
                        }
                    }
                }
                else if (TextPointerBase.IsNextToParagraphBreak(destination, LogicalDirection.Forward) && 
                         TextPointerBase.IsNextToParagraphBreak(This.Selection.AnchorPosition, LogicalDirection.Backward))
                { 
                    // Extend to include any following Paragraph break if the anchor position lies at the start of a Paragraph. 

                    ITextPointer newDestination = destination.GetNextInsertionPosition(LogicalDirection.Forward); 

                    if (newDestination == null)
                    {
                        // We are at the end of container - extend to include position after last paragraph 
                        destination = destination.TextContainer.End;
                    } 
                    else 
                    {
                        destination = newDestination; 
                    }
                }

                // Set orientation towards line content 
                destination = destination.GetFrozenPointer(LogicalDirection.Backward);
 
                // Extend the selection from the active end. 
                ExtendSelectionAndBringIntoView(destination, This);
 
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This);

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This);
 
                // Clear springload formatting 
                ClearSpringloadFormatting(This);
            } 
        }

        /// 
        ///  
        private static void OnSelectToDocumentStart(object target, ExecutedRoutedEventArgs args)
        { 
            TextEditor This = TextEditor._GetTextEditor(target); 

            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source)) 
            {
                return;
            }
 
            TextEditorTyping._FlushPendingInputItems(This);
 
            using (This.Selection.DeclareChangeBlock()) 
            {
                ExtendSelectionAndBringIntoView(This.TextContainer.Start, This); 

                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This);
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(This); 
 
                // Clear springload formatting
                ClearSpringloadFormatting(This); 
            }
        }

        ///  
        /// 
        private static void OnSelectToDocumentEnd(object target, ExecutedRoutedEventArgs args) 
        { 
            TextEditor This = TextEditor._GetTextEditor(target);
 
            if (This == null || !This._IsEnabled || !This._IsSourceInScope(args.Source))
            {
                return;
            } 

            TextEditorTyping._FlushPendingInputItems(This); 
 
            using (This.Selection.DeclareChangeBlock())
            { 
                ExtendSelectionAndBringIntoView(This.TextContainer.End, This);

                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(This); 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(This); 

                // Clear springload formatting 
                ClearSpringloadFormatting(This);
            }
        }
 
        /// 
        /// Handler for ITextView.BringLineIntoViewCompleted event. 
        ///  
        private static void HandleMoveByLineCompleted(object sender, BringLineIntoViewCompletedEventArgs e)
        { 
            Invariant.Assert(sender is ITextView);
            ((ITextView)sender).BringLineIntoViewCompleted -= new BringLineIntoViewCompletedEventHandler(HandleMoveByLineCompleted);

            if (e != null && !e.Cancelled && e.Error == null) 
            {
                TextEditor This = e.UserState as TextEditor; 
 
                if (This == null || !This._IsEnabled)
                { 
                    return;
                }

                TextEditorTyping._FlushPendingInputItems(This); 

                using (This.Selection.DeclareChangeBlock()) 
                { 
                    // Update suggestedX
                    TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, e.NewSuggestedX); 

                    // Move insertion point to next or previous line
                    This.Selection.SetCaretToPosition(e.NewPosition, e.NewPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true);
                } 
            }
        } 
 
        /// 
        /// Handler for ITextView.BringPageIntoViewCompleted event. 
        /// 
        private static void HandleMoveByPageCompleted(object sender, BringPageIntoViewCompletedEventArgs e)
        {
            Invariant.Assert(sender is ITextView); 
            ((ITextView)sender).BringPageIntoViewCompleted -= new BringPageIntoViewCompletedEventHandler(HandleMoveByPageCompleted);
 
            if (e != null && !e.Cancelled && e.Error == null) 
            {
                TextEditor This = e.UserState as TextEditor; 

                if (This == null || !This._IsEnabled)
                {
                    return; 
                }
 
                TextEditorTyping._FlushPendingInputItems(This); 

                using (This.Selection.DeclareChangeBlock()) 
                {
                    // Update suggestedX
                    TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, e.NewSuggestedOffset.X);
 
                    // Move insertion point to next or previous page
                    This.Selection.SetCaretToPosition(e.NewPosition, e.NewPosition.LogicalDirection, /*allowStopAtLineEnd:*/true, /*allowStopNearSpace:*/true); 
                } 
            }
        } 

        /// 
        /// Handler for ITextView.BringLineIntoViewCompleted event.
        ///  
        private static void HandleSelectByLineCompleted(object sender, BringLineIntoViewCompletedEventArgs e)
        { 
            TextEditor This; 

            Invariant.Assert(sender is ITextView); 
            ((ITextView)sender).BringLineIntoViewCompleted -= new BringLineIntoViewCompletedEventHandler(HandleSelectByLineCompleted);

            if (e != null && !e.Cancelled && e.Error == null)
            { 
                This = e.UserState as TextEditor;
 
                if (This == null || !This._IsEnabled) 
                {
                    return; 
                }

                TextEditorTyping._FlushPendingInputItems(This);
 
                using (This.Selection.DeclareChangeBlock())
                { 
                    // Update suggestedX 
                    TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, e.NewSuggestedX);
                    int newComparedToOld = e.NewPosition.CompareTo(e.Position); 

                    if (e.Count < 0) // Moving up if count < 0, moving down otherwise
                    {
                        // Shift key is down - Extend the selection edge 
                        if (newComparedToOld < 0 || newComparedToOld == 0 && e.NewPosition.LogicalDirection != e.Position.LogicalDirection)
                        { 
                            // Note: we compare orientations of equal positions to handle a case 
                            // when original position was at the end of line (after its linebreak with backward orientation)
                            // as a result of Shift+End selection; and the new position is in the beginning of the next line, 
                            // which is essentially the same position but oriented differently.
                            // In such a case the new position is good enough to go there.
                            // We certainly don't want to go to the end of the document in this case.
 
                            // We have another line in a given direction; move to it
                            ExtendSelectionAndBringIntoView(e.NewPosition, This); 
                        } 
                        else
                        { 
                            // Remember where we were so that we can return if a line down follows.
                            if (This._NextLineAdvanceMovingPosition == null)
                            {
                                This._NextLineAdvanceMovingPosition = e.Position; 
                                This._IsNextLineAdvanceMovingPositionAtDocumentHead = true;
                            } 
 
                            // No more lines in this direction. Move to start of current line.
                            ExtendSelectionAndBringIntoView(GetPositionAtLineStart(e.NewPosition), This); 
                        }
                    }
                    else
                    { 
                        AdjustMovingPositionForSelectDownByLine(This, e.NewPosition, e.Position, e.NewSuggestedX);
                    } 
                } 
            }
        } 

        /// 
        /// Handler for ITextView.BringPageIntoViewCompleted event.
        ///  
        private static void HandleSelectByPageCompleted(object sender, BringPageIntoViewCompletedEventArgs e)
        { 
            TextEditor This; 

            Invariant.Assert(sender is ITextView); 
            ((ITextView)sender).BringPageIntoViewCompleted -= new BringPageIntoViewCompletedEventHandler(HandleSelectByPageCompleted);

            if (e != null && !e.Cancelled && e.Error == null)
            { 
                This = e.UserState as TextEditor;
 
                if (This == null || !This._IsEnabled) 
                {
                    return; 
                }

                TextEditorTyping._FlushPendingInputItems(This);
 
                using (This.Selection.DeclareChangeBlock())
                { 
                    // Update suggestedX 
                    TextEditorSelection.UpdateSuggestedXOnColumnOrPageBoundary(This, e.NewSuggestedOffset.X);
                    int newComparedToOld = e.NewPosition.CompareTo(e.Position); 

                    if (e.Count < 0) // Moving up if count < 0, moving down otherwise
                    {
                        // Shift key is down - Extend the selection edge 
                        if (newComparedToOld < 0)
                        { 
                            // We have another page in a given direction; move to it 
                            ExtendSelectionAndBringIntoView(e.NewPosition, This);
                        } 
                        else
                        {
                            // No more pages in this direction. Move to container start.
                            ExtendSelectionAndBringIntoView(e.NewPosition.TextContainer.Start, This); 
                        }
                    } 
                    else 
                    {
                        // Shift key is down - Extend the selection edge 
                        if (newComparedToOld > 0)
                        {
                            // We have another page in a given direction; move to it
                            ExtendSelectionAndBringIntoView(e.NewPosition, This); 
                        }
                        else 
                        { 
                            // No more pages in this direction. Move to container end.
                            ExtendSelectionAndBringIntoView(e.NewPosition.TextContainer.End, This); 
                        }
                    }
                }
            } 
        }
 
        // ---------------------------------------------------------- 
        //
        // Misceleneous Commands 
        //
        // ----------------------------------------------------------

        #region Misceleneous Commands 

        ///  
        /// Keyboard selection commands QueryStatus handler 
        /// 
        private static void OnQueryStatusKeyboardSelection(object target, CanExecuteRoutedEventArgs args) 
        {
            TextEditor This = TextEditor._GetTextEditor(target);

            if (This == null || !This._IsEnabled) 
            {
                return; 
            } 

            args.CanExecute = true; 
        }

        /// 
        /// Caret navigation commands QueryStatus handler 
        /// 
        private static void OnQueryStatusCaretNavigation(object target, CanExecuteRoutedEventArgs args) 
        { 
            TextEditor This = TextEditor._GetTextEditor(target);
 
            if (This == null || !This._IsEnabled)
            {
                return;
            } 

            // We want to disable caret navigation for readonly content, when caret is not visible. (Caret is visible in DocumentViewer case) 
            if (This.IsReadOnly && !This.IsReadOnlyCaretVisible) 
            {
                return; 
            }

            args.CanExecute = true;
        } 

        ///  
        /// Placeholder for commands which are not yet implemented 
        /// 
        ///  
        /// 
        private static void OnNYICommand(object source, ExecutedRoutedEventArgs args)
        {
        } 

        #endregion Misceleneous Commands 
 
        // ---------------------------------------------------------
        // 
        // Misceleneous Private Methods
        //
        // ----------------------------------------------------------
 
        #region Misceleneous Private Methods
 
        // Helper for clearing springload formatting 
        private static void ClearSpringloadFormatting(TextEditor This)
        { 
            if (This.Selection is TextSelection)
            {
                ((TextSelection)This.Selection).ClearSpringloadFormatting();
            } 
        }
 
        ///  
        /// Return true if the flow direction is RightToLeft.
        ///  
        private static bool IsFlowDirectionRightToLeftThenTopToBottom(TextEditor textEditor)
        {
            Invariant.Assert(textEditor != null);
 
            ITextPointer position = textEditor.Selection.MovingPosition.CreatePointer();
 
            // Skip any scoping formatting elements. 
            while (TextSchema.IsFormattingType(position.ParentType))
            { 
                position.MoveToElementEdge(ElementEdge.AfterEnd);
            }

            FlowDirection flowDirection = (FlowDirection)position.GetValue(FlowDocument.FlowDirectionProperty); 

            return (flowDirection == FlowDirection.RightToLeft); 
        } 

        ///  
        /// Move or extend to character according to the logical direction.
        /// 
        private static void MoveToCharacterLogicalDirection(TextEditor textEditor, LogicalDirection direction, bool extend)
        { 
            Invariant.Assert(textEditor != null);
 
            TextEditorTyping._FlushPendingInputItems(textEditor); 

            // Move selection in requested direction 
            using (textEditor.Selection.DeclareChangeBlock())
            {
                if (extend)
                { 
                    // Extend the selection edge. Shift key should be pressed in this case.
                    textEditor.Selection.ExtendToNextInsertionPosition(direction); 
 
                    // Bring selection moving position into view
                    BringIntoView(textEditor.Selection.MovingPosition, textEditor); 
                }
                else
                {
                    // Note that when the selection is non-empty we just collapse it, i.e. use one of its ends 
                    ITextPointer movingEnd = (direction == LogicalDirection.Forward ? textEditor.Selection.End : textEditor.Selection.Start);
 
                    if (textEditor.Selection.IsEmpty) 
                    {
                        movingEnd = movingEnd.GetNextInsertionPosition(direction); 
                    }

                    if (movingEnd != null)
                    { 
                        // Identify an orientation toward content as a character just passed by this move
                        LogicalDirection contentDirection = direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward; 
 
                        // Set caret next to a text character just passed
                        movingEnd = movingEnd.GetInsertionPosition(contentDirection); 

                        // By disallowing to stop near spaces we suppress our "next-to-space" formatting heuristics
                        // which would consider space character as formatting insignificant.
                        // This means that when we pass a space by keyboard we will respect its formatting, 
                        // while when we click next to a space we always ignore space's formatting
                        // and prefer neighboring non-space character formatting instead. 
                        textEditor.Selection.SetCaretToPosition(movingEnd, contentDirection, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false); 
                    }
                } 

                // Remember to scroll the text if we're outside the viewport.
                textEditor.Selection.OnCaretNavigation();
 
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(textEditor); 
 
                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(textEditor); 

                // Clear springload formatting
                ClearSpringloadFormatting(textEditor);
            } 
        }
 
        ///  
        /// Navigate word according to the logical direction.
        ///  
        private static void NavigateWordLogicalDirection(TextEditor textEditor, LogicalDirection direction)
        {
            Invariant.Assert(textEditor != null);
 
            TextEditorTyping._FlushPendingInputItems(textEditor);
 
            using (textEditor.Selection.DeclareChangeBlock()) 
            {
                // Forget previously suggested horizontal position 
                TextEditorSelection._ClearSuggestedX(textEditor);

                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(textEditor); 

                // Clear springload formatting 
                ClearSpringloadFormatting(textEditor); 

                if (direction == LogicalDirection.Forward) 
                {
                    // Move/extend selection in requested direction
                    if (!textEditor.Selection.IsEmpty && TextPointerBase.IsAtWordBoundary(textEditor.Selection.End, LogicalDirection.Forward))
                    { 
                        // If the selection is non-empty and ends on a word boundary, collapse it to that boundary.
                        textEditor.Selection.SetCaretToPosition(textEditor.Selection.End, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false); 
                        // Note that we are using a "smart" version of SetCaretToPosition 
                        // to choose caret orientation on formattinng switches appropriately.
                    } 
                    else
                    {
                        ITextPointer wordBoundary = textEditor.Selection.End.CreatePointer();
                        TextPointerBase.MoveToNextWordBoundary(wordBoundary, LogicalDirection.Forward); 

                        textEditor.Selection.SetCaretToPosition(wordBoundary, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false); 
                        // Note that we are using a "smart" version of SetCaretToPosition 
                        // to choose caret orientation on formattinng switches appropriately.
                    } 
                }
                else
                {
                    // Move/extend selection in requested direction 
                    if (!textEditor.Selection.IsEmpty && TextPointerBase.IsAtWordBoundary(textEditor.Selection.Start, LogicalDirection.Forward))
                    { 
                        // If the selection is non-empty and starts at word boundary, collapse it to that boundary. 
                        textEditor.Selection.SetCaretToPosition(textEditor.Selection.Start, LogicalDirection.Forward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false);
                        // Note that we are using a "smart" version of SetCaretToPosition 
                        // to choose caret orientation on formattinng switches appropriately.
                    }
                    else
                    { 
                        ITextPointer wordBoundary = textEditor.Selection.Start.CreatePointer();
                        TextPointerBase.MoveToNextWordBoundary(wordBoundary, LogicalDirection.Backward); 
 
                        textEditor.Selection.SetCaretToPosition(wordBoundary, LogicalDirection.Forward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false);
                        // Note that we are using a "smart" version of SetCaretToPosition 
                        // to choose caret orientation on formattinng switches appropriately.
                    }
                }
 
                // Remember to scroll the text if we're outside the viewport.
                textEditor.Selection.OnCaretNavigation(); 
 
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(textEditor); 

                // Discard typing undo unit merging
                TextEditorTyping._BreakTypingSequence(textEditor);
 
                // Clear springload formatting
                ClearSpringloadFormatting(textEditor); 
            } 
        }
 
        /// 
        /// Extend word according to the logical direction.
        /// 
        private static void ExtendWordLogicalDirection(TextEditor textEditor, LogicalDirection direction) 
        {
            Invariant.Assert(textEditor != null); 
 
            TextEditorTyping._FlushPendingInputItems(textEditor);
 
            using (textEditor.Selection.DeclareChangeBlock())
            {
                // Forget previously suggested horizontal position
                TextEditorSelection._ClearSuggestedX(textEditor); 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(textEditor); 

                // Clear springload formatting 
                ClearSpringloadFormatting(textEditor);

                // Move/extend selection in requested direction
                ITextPointer wordBoundary = textEditor.Selection.MovingPosition.CreatePointer(); 
                TextPointerBase.MoveToNextWordBoundary(wordBoundary, direction);
 
                wordBoundary.SetLogicalDirection(direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward); 

                // Extend selection and bring new position into view if needed (for paginated viewers) 
                ExtendSelectionAndBringIntoView(wordBoundary, textEditor);

                // Remember to scroll the text if we're outside the viewport.
                textEditor.Selection.OnCaretNavigation(); 

                // Forget previously suggested horizontal position 
                TextEditorSelection._ClearSuggestedX(textEditor); 

                // Discard typing undo unit merging 
                TextEditorTyping._BreakTypingSequence(textEditor);

                // Clear springload formatting
                ClearSpringloadFormatting(textEditor); 
            }
        } 
 
        /// 
        /// Returns a moving position and the suggestedX value for it. 
        /// 
        /// TextEditor
        /// Inner moving position if it has valid layout, otherwise null.
        /// Returns suggestedX when moving position has valid layout, Double.NaN otherwise. 
        private static Double GetSuggestedX(TextEditor This, out ITextPointer innerMovingPosition)
        { 
            // When getting moving position, we need to take care of end-of-line case 
            // and adjust moving position according to its orientation.
            innerMovingPosition = TextEditorSelection.GetMovingPositionInner(This); 

            // We need a non-dirty layout to walk pages.
            if (!innerMovingPosition.ValidateLayout())
            { 
                innerMovingPosition = null;
                return Double.NaN; // This value is not supposed to be used by a caller. 
            } 

            if (Double.IsNaN(This._suggestedX)) 
            {
                This._suggestedX = GetAbsoluteXOffset(This.TextView, innerMovingPosition);

                // If the original moving position is on the other side of a line break, 
                // add in the pixel width of the line break visualization.
                // Note this logic implicitly only modifies suggested x when the 
                // selection is non-empty. 
                if (This.Selection.MovingPosition.CompareTo(innerMovingPosition) > 0)
                { 
                    double breakWidth = (double)innerMovingPosition.GetValue(TextElement.FontSizeProperty) * CaretElement.c_endOfParaMagicMultiplier;

                    FlowDirection paragraphFlowDirection = GetScopingParagraphFlowDirection(innerMovingPosition);
                    FlowDirection controlFlowDirection = This.UiScope.FlowDirection; 

                    if (paragraphFlowDirection != controlFlowDirection) 
                    { 
                        // Adjust for X-axis flip on Paragraphs with non-default flow direction.
                        breakWidth = -breakWidth; 
                    }

                    This._suggestedX += breakWidth;
                } 
            }
 
            return This._suggestedX; 
        }
 
        /// 
        /// Returns a suggested Y-value for a given position.
        /// 
        /// TextEditor 
        /// Position for which suggested Y is needed
        /// If position is null, returns Double.NaN. This method will not find the moving position. It is meant to be 
        /// used after the moving position has been calculated with GetSuggestedX 
        private static Double GetSuggestedYFromPosition(TextEditor This, ITextPointer position)
        { 
            double suggestedY = Double.NaN;
            if (position != null)
            {
                suggestedY = This.TextView.GetRectangleFromTextPosition(position).Y; 
            }
 
            return suggestedY; 
        }
 
        /// 
        /// Update suggestedX value if it has changed due to selection moving position crossing a page or column boundary.
        /// 
        /// TextEditor 
        /// New suggestedX value
        private static void UpdateSuggestedXOnColumnOrPageBoundary(TextEditor This, double newSuggestedX) 
        { 
            if (This._suggestedX != newSuggestedX)
            { 
                This._suggestedX = newSuggestedX;
            }
        }
 
        /// 
        /// Returns a position belonging to currently selected line. 
        /// On a line boundary it depends on the movingPosition orientation. 
        /// When the position is at the end of Selection and oriented backward
        /// we consider it belonging to a previous line. 
        /// When it is oriented forward in the same location,
        /// it belongs to the next line.
        /// This method is supposed to perform appropriate correction -
        /// returns a position which is inside (inner) of the desired visual line. 
        /// 
        private static ITextPointer GetMovingPositionInner(TextEditor This) 
        { 
            ITextPointer movingPosition = This.Selection.MovingPosition;
 
            if (!(movingPosition is DocumentSequenceTextPointer || movingPosition is FixedTextPointer) &&
                movingPosition.LogicalDirection == LogicalDirection.Backward &&
                This.Selection.Start.CompareTo(movingPosition) < 0 &&
                TextPointerBase.IsNextToAnyBreak(movingPosition, LogicalDirection.Backward)) 
            {
                movingPosition = movingPosition.GetNextInsertionPosition(LogicalDirection.Backward); 
 
                // When the end of selection was after the linebreak of empty line in plainn text
                // we need to change its orientation to not put it at the end of preceding line. 
                if (TextPointerBase.IsNextToPlainLineBreak(movingPosition, LogicalDirection.Backward))
                {
                    movingPosition = movingPosition.GetFrozenPointer(LogicalDirection.Forward);
                } 
            }
            else if (TextPointerBase.IsAfterLastParagraph(movingPosition)) 
            { 
                movingPosition = movingPosition.GetInsertionPosition(movingPosition.LogicalDirection);
            } 

            return movingPosition;
        }
 
        // Returns a position in the beginning of a selection which
        // belongs to visually selected line. 
        // Its is Start position of a selection, only its orientation 
        // must be Forward when selection is non-empty.
        private static ITextPointer GetStartInner(TextEditor This) 
        {
            return This.Selection.IsEmpty ? This.Selection.Start : This.Selection.Start.GetFrozenPointer(LogicalDirection.Forward);
        }
 

        // Returns a position in the end of a selection, 
        // which belongs to visually selected line. 
        // It may be different from Selection.End when
        // selection ends immediately after line break 
        // and oriented backward, i.e. belongs visually
        // to previous line.
        private static ITextPointer GetEndInner(TextEditor This)
        { 
            ITextPointer end = This.Selection.End;
            if (end.CompareTo(This.Selection.MovingPosition) == 0) 
            { 
                end = GetMovingPositionInner(This);
            } 
            return end;
        }

        // Returns a position at the start of current line of movingPosition. 
        private static ITextPointer GetPositionAtLineStart(ITextPointer position)
        { 
            TextSegment lineRange = position.TextContainer.TextView.GetLineRange(position); 
            // When the moving position passed to this method is at hard structual boundaries such as AnchoredBlock or TableCell,
            // TextView returns a null line range. 
            return lineRange.IsNull ? position : lineRange.Start;
        }

        // Returns a position at the end of current line of movingPosition. 
        private static ITextPointer GetPositionAtLineEnd(ITextPointer position)
        { 
            TextSegment lineRange = position.TextContainer.TextView.GetLineRange(position); 
            return lineRange.IsNull ? position : lineRange.End;
        } 

        // Helper to extend selection edge to passed position and bring it into view for paginated viewers.
        private static void ExtendSelectionAndBringIntoView(ITextPointer position, TextEditor textEditor)
        { 
            textEditor.Selection.ExtendToPosition(position);
            BringIntoView(position, textEditor); 
        } 

        private static void BringIntoView(ITextPointer position, TextEditor textEditor) 
        {
            double pageHeight = (double)textEditor.UiScope.GetValue(TextEditor.PageHeightProperty);

            if (pageHeight == 0 && // Check for paginated viewer case 
                textEditor.TextView != null && textEditor.TextView.IsValid && !textEditor.TextView.Contains(position) && IsPaginated(textEditor.TextView))
            { 
                // This will bring the position into view when it is in another page for paginated viewers. 
                textEditor.TextView.BringPositionIntoViewAsync(position, textEditor);
            } 
        }

        // If the caret is currently at a Table row end, move it inside
        // the last cell. 
        // This is useful when trying to navigate by line, because ITextView
        // cannot handle the special end of row position. 
        private static void AdjustCaretAtTableRowEnd(TextEditor This) 
        {
            if (This.Selection.IsEmpty && TextPointerBase.IsAtRowEnd(This.Selection.Start)) 
            {
                ITextPointer position = This.Selection.Start.GetNextInsertionPosition(LogicalDirection.Backward);
                if (position != null)
                { 
                    This.Selection.SetCaretToPosition(position, LogicalDirection.Forward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false);
                } 
            } 
        }
 
        // If a position is currently at a Table row end, move it inside
        // the last cell.
        // This is useful when trying to navigate by line, because ITextView
        // cannot handle the special end of row position. 
        private static ITextPointer AdjustPositionAtTableRowEnd(ITextPointer position)
        { 
            if (TextPointerBase.IsAtRowEnd(position)) 
            {
                ITextPointer cellEnd = position.GetNextInsertionPosition(LogicalDirection.Backward); 
                if (cellEnd != null)
                {
                    position = cellEnd;
                } 
            }
 
            return position; 
        }
 
        // Returns the FlowDirection of the closest scoping Block.
        private static FlowDirection GetScopingParagraphFlowDirection(ITextPointer position)
        {
            ITextPointer navigator = position.CreatePointer(); 

            while (typeof(Inline).IsAssignableFrom(navigator.ParentType)) 
            { 
                navigator.MoveToElementEdge(ElementEdge.BeforeStart);
            } 

            return (FlowDirection)navigator.GetValue(FrameworkElement.FlowDirectionProperty);
        }
 
        // Returns the x offset, relative to the left edge of the document
        // of an ITextPointer. 
        // 
        // This is distinct from ITextView.GetRectFromPosition, which returns
        // a point relative to the viewport, which may be offset by a scrollviewer. 
        private static double GetAbsoluteXOffset(ITextView textview, ITextPointer position)
        {
            double x = textview.GetRectangleFromTextPosition(position).X;
 
            //
 
 
            if (textview is TextBoxView) // Extra strict....this could be removed in the future.
            { 
                IScrollInfo scrollInfo = textview as IScrollInfo;
                if (scrollInfo != null)
                {
                    x += scrollInfo.HorizontalOffset; 
                }
            } 
 
            return x;
        } 

        // Returns the x offset, relative to the viewport, of an x position
        // in document coordinates.
        private static double GetViewportXOffset(ITextView textview, double suggestedX) 
        {
            // 
 

            if (textview is TextBoxView) // Extra strict....this could be removed in the future. 
            {
                IScrollInfo scrollInfo = textview as IScrollInfo;
                if (scrollInfo != null)
                { 
                    suggestedX -= scrollInfo.HorizontalOffset;
                } 
            } 

            return suggestedX; 
        }

        #endregion Misceleneous Private Methods
 
        #endregion Private methods
    } 
} 

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