TextEditorDragDrop.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / System / Windows / Documents / TextEditorDragDrop.cs / 1 / TextEditorDragDrop.cs

                            //---------------------------------------------------------------------------- 
//
// File: TextEditorDragDrop.cs
//
// Copyright (C) Microsoft Corporation.  All rights reserved. 
//
// Description: A Component of TextEditor class supposrtinng Drag-and-drop 
//              functionality 
//
//--------------------------------------------------------------------------- 

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.Windows.Threading;
    using System.Windows.Input; 
    using System.Windows.Interop;  // WindowInteropHelper
    using System.Windows.Controls; // ScrollChangedEventArgs 
    using System.Windows.Controls.Primitives;  // CharacterCasing, TextBoxBase 
    using System.Windows.Data; // BindingExpression
    using System.Windows.Media; 
    using System.Windows.Markup;
    using System.Windows;
    using System.Security;
    using System.Security.Permissions; // UIPermission 

    using MS.Utility; 
    using MS.Win32; 
    using MS.Internal.Documents;
    using MS.Internal.Commands; // CommandHelpers 
    using MS.Internal.PresentationFramework;  //Demand for drag and drop

    /// 
    /// Text editing service for controls. 
    /// 
    internal static class TextEditorDragDrop 
    { 
        //-----------------------------------------------------
        // 
        //  Class Internal Methods
        //
        //-----------------------------------------------------
 
        #region Class Internal Methods
 
        // Registers all text editing command handlers for a given control type 
        internal static void _RegisterClassHandlers(Type controlType, bool readOnly, bool registerEventListeners)
        { 
            if (registerEventListeners)
            {
                EventManager.RegisterClassHandler(controlType, DragDrop.QueryContinueDragEvent, new QueryContinueDragEventHandler(OnQueryContinueDrag));
                EventManager.RegisterClassHandler(controlType, DragDrop.GiveFeedbackEvent, new GiveFeedbackEventHandler(OnGiveFeedback)); 
                EventManager.RegisterClassHandler(controlType, DragDrop.DragEnterEvent, new DragEventHandler(OnDragEnter));
                EventManager.RegisterClassHandler(controlType, DragDrop.DragOverEvent, new DragEventHandler(OnDragOver)); 
                EventManager.RegisterClassHandler(controlType, DragDrop.DragLeaveEvent, new DragEventHandler(OnDragLeave)); 
                if (!readOnly)
                { 
                    EventManager.RegisterClassHandler(controlType, DragDrop.DropEvent, new DragEventHandler(OnDrop));
                }
            }
        } 

        #endregion Class Internal Methods 
 
        //------------------------------------------------------
        // 
        //  Class Internal Types
        //
        //-----------------------------------------------------
 
        #region Class Internal Types
 
        // A structure used for storing DragDrop status during dragging process 
        internal class _DragDropProcess
        { 
            internal _DragDropProcess(TextEditor textEditor)
            {
                Invariant.Assert(textEditor != null);
                _textEditor = textEditor; 
            }
 
            ///  
            /// Checks whether mouse down position belongs to selected portion of text,
            /// and initiates a drad-and-drop process in this case. 
            /// Drag-drop initiation does not capture mouse yet, and do not start
            /// OleDragDrop; this will happen on a subsequent mouse move event
            /// (if it will happen before mouse up).
            ///  
            /// 
            /// TextView-relative coordinates of mouse down event. 
            ///  
            /// 
            /// true if this mouse down was inside of selection and drag-drop process was activated. 
            /// false if the mouse down was outside of selected portion.
            /// 
            internal bool SourceOnMouseLeftButtonDown(Point mouseDownPoint)
            { 
                ITextSelection selection = _textEditor.Selection;
 
                if (_textEditor.UiScope is PasswordBox) 
                {
                    // 
                    _dragStarted = false;
                }
                else
                { 
                    // Get the drag minimum width/height from SystemMetrics.DragMinimumWidth/DragMinimumHeight.
                    // dragMinimumWidth and dragMinimumheight of a rectangle centered on a drag point to allow for limited movement 
                    // of the mouse pointer before a drag operation begins. 
                    // It allows the user to click and release the mouse button easily without unintentionally starting a drag operation.
                    int minimumHorizontalDragDistance = (int)SystemParameters.MinimumHorizontalDragDistance; 
                    int minimumVerticalDragDistance = (int)SystemParameters.MinimumVerticalDragDistance;

                    _dragRect = new Rect(mouseDownPoint.X - minimumHorizontalDragDistance, mouseDownPoint.Y - minimumVerticalDragDistance, minimumHorizontalDragDistance * 2, minimumVerticalDragDistance * 2);
 
                    // Check if click happened within existing selection
                    _dragStarted = selection.Contains(mouseDownPoint); 
                } 

                return _dragStarted; 
            }

            // MouseUpEvent handler.
            internal void DoMouseLeftButtonUp(MouseButtonEventArgs e) 
            {
                if (_dragStarted) 
                { 
                    // We get to this state when drag gesture ends within the selection,
                    // so we only need to set selection into mouse-releasing point. 
                    if (this.TextView.IsValid)
                    {
                        Point mouseDownPoint = e.GetPosition(_textEditor.TextView.RenderScope);
                        ITextPointer cursorPosition = this.TextView.GetTextPositionFromPoint(mouseDownPoint, /*snapToText:*/true); 
                        if (cursorPosition != null)
                        { 
                            _textEditor.Selection.SetSelectionByMouse(cursorPosition, mouseDownPoint); 
                        }
                    } 
                    _dragStarted = false;
                }
            }
 
            // Starts OLE dragdrop process if movement was started from
            // within selection and initial move is big enough for drag to start. 
            // Returns true if drag is in progress 
            /// 
            ///   Critical: This code calls into _createDataObject 
            ///   TreatAsSafe: This will bail if called in partial trust
            /// 
            [SecurityCritical,SecurityTreatAsSafe]	
            internal bool SourceOnMouseMove(Point mouseMovePoint) 
            {
                // Not allow the initiating DragDrop operation without the unmanaged code permission. 
                // We chose to use this over clipboard because this was causing issues in LocalIntranet 
                // which has similar restrictions as internet but has clipboard permission
                if (!_dragStarted || !SecurityHelper.CheckUnmanagedCodePermission()) 
                {
                    return false; // false means that drag is not involved at all - selection extension should continue
                }
 
                // Check the mouse drag to start DragDrop operation.
                if (!InitialThresholdCrossed(mouseMovePoint)) 
                { 
                    return true; // true means that drag is in progress, even though not yet started - so selection should not extend
                } 

                ITextSelection selection = _textEditor.Selection;

                // NOTE: This calls OnMouseMove recursively; 
                // but because UiScope.IsMouseCaptured is false already,
                // we'll return with no actions 
                // This is the first move in drag-drop gesture. 
                // Execure the whole drag-drop ssequence: returns after the drop
                _dragStarted = false; 

                // Execute OLE drag-drop process (synchronousely)
                // ----------------------------------------------
 
                // Set the original text range to delete it with DragDropEffects.Move effect.
                _dragSourceTextRange = new TextRange(selection.Start, selection.End); 
 
                // Prepare data object (including side effects from application customization)
 
                // Note: _CreateDataObject raises a public event which might throw a recoverable exception.
                IDataObject dataObject = TextEditorCopyPaste._CreateDataObject(_textEditor, /*isDragDrop:*/true);

                if (dataObject != null) // null would mean that application cancelled the command 
                {
                    // 
                    SourceDoDragDrop(selection, dataObject); 

                    // Release mouse capture, because DoDragDrop is taking 
                    // a mouse resposibility from now on.
                    // ReleaseMouseCapture shouldn't call before calling DoDragDroop
                    // that cause the generating WM_MOUSELEAVE message by system
                    // (xxxCapture xxxCancelMouseMoverTracking) that appear MouseLeave 
                    // event during DragDrop event.
                    _textEditor.UiScope.ReleaseMouseCapture(); 
 
                    return true; // true means that drag is in progress. Selection should not extend.
                } 
                else
                {
                    // The DragDrop process has been terminated by application custom code
                    // 
                    return false;
                } 
            } 

            // Check whether the mouse is dragged with the minimum width and height. 
            // _dragRect is Width and height of a rectangle centered on a drag point to allow for limited movement
            // of the mouse pointer before a drag operation begins.
            // It allows the user to click and release the mouse button easily without unintentionally starting a drag operation.
            private bool InitialThresholdCrossed(Point dragPoint) 
            {
                // Check the current poisition is in the drag rect. 
                return !_dragRect.Contains(dragPoint.X, dragPoint.Y); 
            }
 
            /// 
            /// DragEnd event handler from DragDrop behavior.
            /// 
            private void SourceDoDragDrop(ITextSelection selection, IDataObject dataObject) 
            {
                // Run OLE drag-drop process. It will eat all user input until the drop 
                DragDropEffects allowedDragDropEffects = DragDropEffects.Copy; 
                if (!_textEditor.IsReadOnly)
                { 
                    allowedDragDropEffects |= DragDropEffects.Move;
                }

                DragDropEffects resultingDragDropEffects = DragDrop.DoDragDrop( // 
                    _textEditor.UiScope, // dragSource,
                    dataObject, // 
                    allowedDragDropEffects); 

                // Remove source selection 
                if (!_textEditor.IsReadOnly && //
                    resultingDragDropEffects == DragDropEffects.Move && //
                    _dragSourceTextRange != null &&
                    !_dragSourceTextRange.IsEmpty) 
                {
                    // Normally we delete the source selection from OnDrop event, 
                    // unless source and target TextBoxes are different. 
                    // In this case the source selection is still not empty,
                    // which means that target was in a different TextBox. 
                    // So we still need to delete the selected content in the source one.
                    // This will create an undo unit different from a dropping one,
                    // which is ok, because it will be in different TextBox's undo stack.
                    using (selection.DeclareChangeBlock()) 
                    {
                        // This is end of Move - we need to delete source content 
                        _dragSourceTextRange.Text = String.Empty; 
                    }
                } 

                // Clean up the text range.
                _dragSourceTextRange = null;
 
                // Check the data binding expression and update the source and target if the drag source
                // has the binding expression. Without this, data binding is broken after complete the 
                // drag-drop operation because Drop() paste the object then set the focus to the target. 
                // The losting focus invoke the data binding expression's Update(), but the source isn't
                // updated yet before complete DoDragDrop. 
                BindingExpressionBase bindingExpression = BindingOperations.GetBindingExpressionBase(
                    _textEditor.UiScope, TextBox.TextProperty);
                if (bindingExpression != null)
                { 
                    bindingExpression.UpdateSource();
                    bindingExpression.UpdateTarget(); 
                } 
            }
 
            // Creates DropCaret
            internal void TargetEnsureDropCaret()
            {
                if (_caretDragDrop == null) 
                {
                    // 
 
                    // Add the caret.
                    // Create caret to show it during the dragging operation. 
                    _caretDragDrop = new CaretElement(_textEditor, /*isBlinkEnabled:*/false);

                    // Initialize the caret.
                    // 
                    _caretDragDrop.Hide();
                } 
            } 

            /// A handler for an event reporting that the drag enter during drag-and-drop operation. 
            internal void TargetOnDragEnter(DragEventArgs e)
            {
                if (!AllowDragDrop(e))
                { 
                    return;
                } 
 
                // Ok, there's data to move or copy here.
                if ((e.AllowedEffects & DragDropEffects.Move) != 0) 
                {
                    e.Effects = DragDropEffects.Move;
                }
 
                bool ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0);
                if (ctrlKeyDown) 
                { 
                    e.Effects |= DragDropEffects.Copy;
                } 

                // Create the drag-and-drop caret to show it on the drop target candidate place.
                TargetEnsureDropCaret();
            } 

            /// A handler for an event reporting that the drag over during drag-and-drop operation. 
            internal void TargetOnDragOver(DragEventArgs e) 
            {
                if (!AllowDragDrop(e)) 
                {
                    return;
                }
 
                // Ok, there's data to move or copy here.
                if ((e.AllowedEffects & DragDropEffects.Move) != 0) 
                { 
                    e.Effects = DragDropEffects.Move;
                } 

                bool ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0);
                if (ctrlKeyDown)
                { 
                    e.Effects |= DragDropEffects.Copy;
                } 
 
                // Show the caret on the drag over target position.
                if (_caretDragDrop != null) 
                {
                    // Update the layout to get the corrected text position. Otherwise, we can get the
                    // incorrected text position.
                    if (!_textEditor.TextView.Validate(e.GetPosition(_textEditor.TextView.RenderScope))) 
                    {
                        return; 
                    } 

                    // Find the scroller from the render scope 
                    FrameworkElement scroller = _textEditor._Scroller;

                    // Automatically scroll the dropable content(line or page up/down) if scroller is available
                    if (scroller != null) 
                    {
                        // Get the ScrollInfo to scroll a line or page up/down 
                        IScrollInfo scrollInfo = scroller as IScrollInfo; 

                        if (scrollInfo == null && scroller is ScrollViewer) 
                        {
                            scrollInfo = ((ScrollViewer)scroller).ScrollInfo;
                        }
 
                        Invariant.Assert(scrollInfo != null);
 
                        Point pointScroller = e.GetPosition((IInputElement)scroller); 
                        double pageHeight = (double)_textEditor.UiScope.GetValue(TextEditor.PageHeightProperty);
                        double slowAreaHeight = ScrollViewer._scrollLineDelta * 2; 

                        if (pointScroller.Y < slowAreaHeight)
                        {
                            // Drag position is on the scroll area that we need to scroll up 
                            if (pointScroller.Y > slowAreaHeight / 2)
                            { 
                                // scroll a line up 
                                scrollInfo.LineUp();
                            } 
                            else
                            {
                                // scroll a page up
                                scrollInfo.PageUp(); 
                            }
                        } 
                        else if (pointScroller.Y > (pageHeight - slowAreaHeight)) 
                        {
                            // Drag position is on the scroll area that we need to scroll down 
                            if (pointScroller.Y < (pageHeight - slowAreaHeight / 2))
                            {
                                // scroll a line down
                                scrollInfo.LineDown(); 
                            }
                            else 
                            { 
                                // scroll a page down
                                scrollInfo.PageDown(); 
                            }
                        }
                    }
 
                    // Get the current text position from the dropable mouse point.
                    _textEditor.TextView.RenderScope.UpdateLayout(); // 
 
                    if (_textEditor.TextView.IsValid)
                    { 
                        ITextPointer dragPosition = GetDropPosition(_textEditor.TextView.RenderScope as Visual, e.GetPosition(_textEditor.TextView.RenderScope));

                        if (dragPosition != null)
                        { 
                            // Get the caret position to show the dropable point.
                            Rect caretRectangle = this.TextView.GetRectangleFromTextPosition(dragPosition); 
 
                            // NOTE: We DO NOT use GetCurrentValue because springload formatting should NOT be involved for drop caret.
                            object fontStylePropertyValue = dragPosition.GetValue(TextElement.FontStyleProperty); 
                            bool italic = (_textEditor.AcceptsRichContent && fontStylePropertyValue != DependencyProperty.UnsetValue && (FontStyle)fontStylePropertyValue == FontStyles.Italic);
                            Brush caretBrush = TextSelection.GetCaretBrush(_textEditor, /*opacity:0.5f*/0x7f);

                            // Show the caret on the dropable position. 
                            _caretDragDrop.Update(/*visible:*/true, caretRectangle, caretBrush, italic, CaretScrollMethod.None, /*wordWrappingPosition*/ double.NaN);
                        } 
                    } 
                }
            } 

            /// 
            /// Calculates a TextPointer indended for dropping the text.
            ///  
            /// 
            ///  
            ///  
            /// ITextPointer intended for dropping the selected text.
            /// Adjusts the dropping point to a word boundary (beginning of word) 
            /// in case if source range contains whole words.
            /// The position returned is oriented towards a character
            /// under the mouse pointer.
            ///  
            private ITextPointer GetDropPosition(Visual target, Point point)
            { 
                Invariant.Assert(target != null); 
                Invariant.Assert(_textEditor.TextView.IsValid); // caller must guarantee this.
 
                // Convert point to RenderScope
                if (target != _textEditor.TextView.RenderScope && target != null && (_textEditor.TextView.RenderScope).IsAncestorOf(target))
                {
                    GeneralTransform transform = target.TransformToAncestor(_textEditor.TextView.RenderScope); 
                    transform.TryTransform(point, out point);
                } 
 
                ITextPointer dropPosition = this.TextView.GetTextPositionFromPoint(point, /*snapToText:*/true);
 
                // For rich text content we adjust drop position to word boundary
                if (dropPosition != null)
                {
                    // Normalize drop position 
                    dropPosition = dropPosition.GetInsertionPosition(dropPosition.LogicalDirection);
 
                    if (_textEditor.AcceptsRichContent) 
                    {
                        TextSegment lineRange = TextEditorSelection.GetNormalizedLineRange(this.TextView, dropPosition); 

                        if (!lineRange.IsNull &&
                            // The drop position must be before of end of line
                            dropPosition.CompareTo(lineRange.End) < 0 && 
                            // We check if we are not at word boundary already:
                            !TextPointerBase.IsAtWordBoundary(dropPosition, /*insideWordDirection:*/LogicalDirection.Forward) && 
                            // We do not do it if the source range was not on word boundaries from both ends 
                            _dragSourceTextRange != null && //
                            TextPointerBase.IsAtWordBoundary(_dragSourceTextRange.Start, LogicalDirection.Forward) && // 
                            TextPointerBase.IsAtWordBoundary(_dragSourceTextRange.End, LogicalDirection.Forward))
                        {
                            // Move to word boundary. Select closest one to a dropPosition.
                            TextSegment wordSegment = TextPointerBase.GetWordRange(dropPosition); 
                            string wordText = TextRangeBase.GetTextInternal(wordSegment.Start, wordSegment.End);
                            int indexInWord = wordSegment.Start.GetOffsetToPosition(dropPosition); 
                            dropPosition = (indexInWord < (wordText.Length / 2)) ? wordSegment.Start : wordSegment.End; 
                        }
                    } 
                }

                return dropPosition;
            } 

            internal void TargetOnDragLeave() 
            { 
                // Delete the caret
                if (_caretDragDrop != null) 
                {
                    AdornerLayer layer = AdornerLayer.GetAdornerLayer(TextView.RenderScope);
                    layer.Remove(_caretDragDrop);
                    _caretDragDrop = null; 
                }
            } 
 
            /// 
            /// Called from an event reporting that the drop happened. 
            /// 
            internal void TargetOnDrop(DragEventArgs e)
            {
                // 

                if (!AllowDragDrop(e)) 
                { 
                    return;
                } 

                ITextSelection selection = _textEditor.Selection;
                Invariant.Assert(selection != null);
 
                // Delete the caret.
                if (_caretDragDrop != null) 
                { 
                    AdornerLayer layer = AdornerLayer.GetAdornerLayer(TextView.RenderScope);
                    layer.Remove(_caretDragDrop); 
                    _caretDragDrop = null;
                }

                if (e.Data == null || e.AllowedEffects == DragDropEffects.None) 
                {
                    e.Effects = DragDropEffects.None; 
                    return; 
                }
 
                if ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0)
                {
                    e.Effects = DragDropEffects.Copy;
                } 
                else if (e.Effects != DragDropEffects.Copy)
                { 
                    e.Effects = DragDropEffects.Move; 
                }
 
                // Force a layout update on the content so the GetTextPositionFromPoint
                // call following can succeed.
                if (!_textEditor.TextView.Validate(e.GetPosition(_textEditor.TextView.RenderScope)))
                { 
                    e.Effects = DragDropEffects.None;
                    return; 
                } 

                // Get the text position from the text target point. 
                ITextPointer dropPosition = GetDropPosition(_textEditor.TextView.RenderScope as Visual, e.GetPosition(_textEditor.TextView.RenderScope));

                if (dropPosition != null)
                { 
                    if (_dragSourceTextRange != null && _dragSourceTextRange.Start.TextContainer == selection.Start.TextContainer &&
                        !selection.IsEmpty && IsSelectionContainsDropPosition(selection, dropPosition)) 
                    { 
                        // When we drop inside of selected area, we
                        // should not select dropped content, 
                        // otherwise it looks for end user as if
                        // nothing happened.

                        // Set caret to this position. 
                        selection.SetCaretToPosition(dropPosition, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/true);
 
                        // Indicate the resulting effect of an action 
                        // Note that dropResult may stay equal to DragDropResult.Drop
                        e.Effects = DragDropEffects.None; 

                        // Mark the event as handled
                        e.Handled = true;
                    } 
                    else
                    { 
                        using (selection.DeclareChangeBlock()) 
                        {
                            // For MaxLength filter work correctly in case 
                            // when we dragdrop within the same TextContainer,
                            // we need to delete dragged content first -
                            // before dropping when filtering will occur.
                            // Note, that this will duplicate operation on 
                            // source side, but it will be void deletion action
                            if ((e.Effects & DragDropEffects.Move) != 0 && // 
                                _dragSourceTextRange != null && _dragSourceTextRange.Start.TextContainer == selection.Start.TextContainer) 
                            {
                                _dragSourceTextRange.Text = String.Empty; 
                            }

                            // When we drop outside of selection,
                            // we should ignore current selection and 
                            // move ip into dropping point.
                            selection.SetCaretToPosition(dropPosition, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/true); 
 
                            // _DoPaste raises a public event -- could raise recoverable exception.
                            e.Handled = TextEditorCopyPaste._DoPaste(_textEditor, e.Data, /*isDragDrop:*/true); 
                            //
                        }
                    }
 
                    if (e.Handled)
                    { 
                        // Set the drop target as the foreground window. 
                        Win32SetForegroundWindow();
 
                        // Set the focus into the drop target.
                        _textEditor.UiScope.Focus();
                    }
                    else 
                    {
                        // When a target did not handle a drop event, we must 
                        // prevent from deleting a content on source end - 
                        // otherwise we'll have data loss
                        e.Effects = DragDropEffects.None; 
                    }
                }
            }
 
            // Table cell selection currently include the next adjacent cell start element so that
            // selection always contains the drop position even though the drop position is on the next cell. 
            // This private method check the table range really contains the drop position or not. 
            private bool IsSelectionContainsDropPosition(ITextSelection selection, ITextPointer dropPosition)
            { 
                bool selectionContainedDropPosition = selection.Contains(dropPosition);

                if (selectionContainedDropPosition && selection.IsTableCellRange)
                { 
                    for (int i = 0; i < selection.TextSegments.Count; i++)
                    { 
                        TextSegment textSegment = selection._TextSegments[i]; 

                        if (dropPosition.CompareTo(textSegment.End) == 0) 
                        {
                            selectionContainedDropPosition = false;
                            break;
                        } 
                    }
                } 
 
                return selectionContainedDropPosition;
            } 

            private bool AllowDragDrop(DragEventArgs e)
            {
                if (!_textEditor.IsReadOnly && _textEditor.TextView != null && _textEditor.TextView.RenderScope != null) 
                {
                    Window window = Window.GetWindow(_textEditor.TextView.RenderScope); 
                    if (window == null) 
                    {
                        return true; 
                    }

                    WindowInteropHelper helper = new WindowInteropHelper(window);
                    if (SafeNativeMethods.IsWindowEnabled(new HandleRef(null, helper.Handle))) 
                    {
                        return true; 
                    } 
                }
 
                e.Effects = DragDropEffects.None;
                return false;
            }
 
            /// 
            /// Call Win32 SetForegroundWindow to set the drop target as the foreground window. 
            ///  
            /// 
            /// Critical - This calls PresentationSource.FromVisual() and PresentationSource.Handle 
            ///            under elevation.
            /// Safe - This doesn't expose the information. The SetForegroundWindow call will only
            ///        set the drop window as the foreground without exposing the information.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            private void Win32SetForegroundWindow() 
            { 
                PresentationSource source = null;
                IntPtr hwnd = IntPtr.Zero; 
                source = PresentationSource.CriticalFromVisual(_textEditor.UiScope);
                if (source != null)
                {
                    new UIPermission(UIPermissionWindow.AllWindows).Assert();   //BlessedAssert 
                    try
                    { 
                        hwnd = (source as IWin32Window).Handle; 
                    }
                    finally 
                    {

                        UIPermission.RevertAssert();
                    } 
                }
 
                if (hwnd != IntPtr.Zero) 
                {
                    UnsafeNativeMethods.SetForegroundWindow(new HandleRef(null, hwnd)); 
                }
            }

            private ITextView TextView 
            {
                get 
                { 
                    return _textEditor.TextView;
                } 
            }

            private TextEditor _textEditor;
 
            // TextRange for drag source.
            private ITextRange _dragSourceTextRange; 
 
            // Flag indicating that mouse dragging was started within selection.
            // It is used for deferring drag/drop until first move, 
            // and for setting selection on mouseup in case of no move.
            private bool _dragStarted;

            // DragDrop caret to show it on the dropable target position. 
            //
 
 

            private CaretElement _caretDragDrop; 

            // Rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins.
            private Rect _dragRect;
        } 

        ///  
        /// An event reporting that the query continue drag during drag-and-drop operation. 
        /// 
        internal static void OnQueryContinueDrag(object sender, QueryContinueDragEventArgs e) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null) 
            {
                return; 
            } 

            // Ignore the event if the editor has been detached from its scope 
            if (!This._IsEnabled)
            {
                return;
            } 

            // Consider event handled 
            e.Handled = true; 

            e.Action = DragAction.Continue; 
            bool mouseUp = (((int)e.KeyStates & (int)DragDropKeyStates.LeftMouseButton) == 0);
            if (e.EscapePressed)
            {
                e.Action = DragAction.Cancel; 
            }
            else if (mouseUp) 
            { 
                e.Action = DragAction.Drop;
            } 
        }

        /// 
        /// An event reporting that the give feedback during drag-and-drop operation. 
        /// 
        internal static void OnGiveFeedback(object sender, GiveFeedbackEventArgs e) 
        { 
            TextEditor This = TextEditor._GetTextEditor(sender);
 
            if (This == null)
            {
                return;
            } 

            // Ignore the event if the editor has been detached from its scope 
            if (!This._IsEnabled) 
            {
                return; 
            }

            // Show the default DragDrop cursor.
            e.UseDefaultCursors = true; 

            // Consider event handled 
            e.Handled = true; 
        }
 
        /// 
        /// An event reporting that the drag enter during drag-and-drop operation.
        /// 
        internal static void OnDragEnter(object sender, DragEventArgs e) 
        {
            // Consider event handled 
            e.Handled = true; 

            TextEditor This = TextEditor._GetTextEditor(sender); 

            if (This == null)
            {
                e.Effects = DragDropEffects.None; 
                return;
            } 
 
            // Ignore the event if the editor has been detached from its scope
            if (!This._IsEnabled || This.TextView == null || This.TextView.RenderScope == null) 
            {
                e.Effects = DragDropEffects.None;
                return;
            } 

            // If there's no supported data available, don't allow the drag-and-drop. 
            if (e.Data == null) 
            {
                e.Effects = DragDropEffects.None; 
                return;
            }

            // Ignore the event if there isn't the dropable(pasteable) data format 
            if (TextEditorCopyPaste.GetPasteApplyFormat(This, e.Data) == string.Empty)
            { 
                e.Effects = DragDropEffects.None; 
                return;
            } 

            TextEditorTyping._FlushPendingInputItems(This);

            if (!This.TextView.Validate(e.GetPosition(This.TextView.RenderScope))) 
            {
                e.Effects = DragDropEffects.None; 
                return; 
            }
 
            This._dragDropProcess.TargetOnDragEnter(e);
        }

        ///  
        /// An event reporting that the drag over during drag-and-drop operation.
        ///  
        internal static void OnDragOver(object sender, DragEventArgs e) 
        {
            // Consider event handled 
            e.Handled = true;

            TextEditor This = TextEditor._GetTextEditor(sender);
 
            if (This == null)
            { 
                e.Effects = DragDropEffects.None; 
                return;
            } 

            // Ignore the event if the editor has been detached from its scope
            if (!This._IsEnabled || This.TextView == null || This.TextView.RenderScope == null)
            { 
                e.Effects = DragDropEffects.None;
                return; 
            } 

            // If there's no supported data available, don't allow the drag-and-drop. 
            if (e.Data == null)
            {
                e.Effects = DragDropEffects.None;
                return; 
            }
 
            // Ignore the event if there isn't the dropable(pasteable) data format 
            if (TextEditorCopyPaste.GetPasteApplyFormat(This, e.Data) == string.Empty)
            { 
                e.Effects = DragDropEffects.None;
                return;
            }
 
            TextEditorTyping._FlushPendingInputItems(This);
            if (!This.TextView.Validate(e.GetPosition(This.TextView.RenderScope))) 
            { 
                e.Effects = DragDropEffects.None;
                return; 
            }

            This._dragDropProcess.TargetOnDragOver(e);
        } 

        ///  
        /// An event reporting that the drag leave during drag-and-drop operation. 
        /// 
        internal static void OnDragLeave(object sender, DragEventArgs e) 
        {
            // Consider event handled
            e.Handled = true;
 
            TextEditor This = TextEditor._GetTextEditor(sender);
 
            if (This == null) 
            {
                return; 
            }

            //
            // Remove UI feedback here if UI is specified on DragEnter. 
            //
            // Ignore the event if the editor has been detached from its scope 
            if (!This._IsEnabled) 
            {
                e.Effects = DragDropEffects.None; 
                return;
            }

            TextEditorTyping._FlushPendingInputItems(This); 
            if (!This.TextView.Validate(e.GetPosition(This.TextView.RenderScope)))
            { 
                return; 
            }
 
            This._dragDropProcess.TargetOnDragLeave();
        }

        ///  
        /// An event reporting that the drop happened.
        ///  
        internal static void OnDrop(object sender, DragEventArgs e) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender); 

            if (This == null)
            {
                return; 
            }
 
            // Ignore the event if the editor has been detached from its scope 
            if (!This._IsEnabled)
            { 
                return;
            }

            TextEditorTyping._FlushPendingInputItems(This); 
            if (!This.TextView.Validate(e.GetPosition(This.TextView.RenderScope)))
            { 
                return; 
            }
 
            This._dragDropProcess.TargetOnDrop(e);
        }

        #endregion Class Internal Types 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// File: TextEditorDragDrop.cs
//
// Copyright (C) Microsoft Corporation.  All rights reserved. 
//
// Description: A Component of TextEditor class supposrtinng Drag-and-drop 
//              functionality 
//
//--------------------------------------------------------------------------- 

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.Windows.Threading;
    using System.Windows.Input; 
    using System.Windows.Interop;  // WindowInteropHelper
    using System.Windows.Controls; // ScrollChangedEventArgs 
    using System.Windows.Controls.Primitives;  // CharacterCasing, TextBoxBase 
    using System.Windows.Data; // BindingExpression
    using System.Windows.Media; 
    using System.Windows.Markup;
    using System.Windows;
    using System.Security;
    using System.Security.Permissions; // UIPermission 

    using MS.Utility; 
    using MS.Win32; 
    using MS.Internal.Documents;
    using MS.Internal.Commands; // CommandHelpers 
    using MS.Internal.PresentationFramework;  //Demand for drag and drop

    /// 
    /// Text editing service for controls. 
    /// 
    internal static class TextEditorDragDrop 
    { 
        //-----------------------------------------------------
        // 
        //  Class Internal Methods
        //
        //-----------------------------------------------------
 
        #region Class Internal Methods
 
        // Registers all text editing command handlers for a given control type 
        internal static void _RegisterClassHandlers(Type controlType, bool readOnly, bool registerEventListeners)
        { 
            if (registerEventListeners)
            {
                EventManager.RegisterClassHandler(controlType, DragDrop.QueryContinueDragEvent, new QueryContinueDragEventHandler(OnQueryContinueDrag));
                EventManager.RegisterClassHandler(controlType, DragDrop.GiveFeedbackEvent, new GiveFeedbackEventHandler(OnGiveFeedback)); 
                EventManager.RegisterClassHandler(controlType, DragDrop.DragEnterEvent, new DragEventHandler(OnDragEnter));
                EventManager.RegisterClassHandler(controlType, DragDrop.DragOverEvent, new DragEventHandler(OnDragOver)); 
                EventManager.RegisterClassHandler(controlType, DragDrop.DragLeaveEvent, new DragEventHandler(OnDragLeave)); 
                if (!readOnly)
                { 
                    EventManager.RegisterClassHandler(controlType, DragDrop.DropEvent, new DragEventHandler(OnDrop));
                }
            }
        } 

        #endregion Class Internal Methods 
 
        //------------------------------------------------------
        // 
        //  Class Internal Types
        //
        //-----------------------------------------------------
 
        #region Class Internal Types
 
        // A structure used for storing DragDrop status during dragging process 
        internal class _DragDropProcess
        { 
            internal _DragDropProcess(TextEditor textEditor)
            {
                Invariant.Assert(textEditor != null);
                _textEditor = textEditor; 
            }
 
            ///  
            /// Checks whether mouse down position belongs to selected portion of text,
            /// and initiates a drad-and-drop process in this case. 
            /// Drag-drop initiation does not capture mouse yet, and do not start
            /// OleDragDrop; this will happen on a subsequent mouse move event
            /// (if it will happen before mouse up).
            ///  
            /// 
            /// TextView-relative coordinates of mouse down event. 
            ///  
            /// 
            /// true if this mouse down was inside of selection and drag-drop process was activated. 
            /// false if the mouse down was outside of selected portion.
            /// 
            internal bool SourceOnMouseLeftButtonDown(Point mouseDownPoint)
            { 
                ITextSelection selection = _textEditor.Selection;
 
                if (_textEditor.UiScope is PasswordBox) 
                {
                    // 
                    _dragStarted = false;
                }
                else
                { 
                    // Get the drag minimum width/height from SystemMetrics.DragMinimumWidth/DragMinimumHeight.
                    // dragMinimumWidth and dragMinimumheight of a rectangle centered on a drag point to allow for limited movement 
                    // of the mouse pointer before a drag operation begins. 
                    // It allows the user to click and release the mouse button easily without unintentionally starting a drag operation.
                    int minimumHorizontalDragDistance = (int)SystemParameters.MinimumHorizontalDragDistance; 
                    int minimumVerticalDragDistance = (int)SystemParameters.MinimumVerticalDragDistance;

                    _dragRect = new Rect(mouseDownPoint.X - minimumHorizontalDragDistance, mouseDownPoint.Y - minimumVerticalDragDistance, minimumHorizontalDragDistance * 2, minimumVerticalDragDistance * 2);
 
                    // Check if click happened within existing selection
                    _dragStarted = selection.Contains(mouseDownPoint); 
                } 

                return _dragStarted; 
            }

            // MouseUpEvent handler.
            internal void DoMouseLeftButtonUp(MouseButtonEventArgs e) 
            {
                if (_dragStarted) 
                { 
                    // We get to this state when drag gesture ends within the selection,
                    // so we only need to set selection into mouse-releasing point. 
                    if (this.TextView.IsValid)
                    {
                        Point mouseDownPoint = e.GetPosition(_textEditor.TextView.RenderScope);
                        ITextPointer cursorPosition = this.TextView.GetTextPositionFromPoint(mouseDownPoint, /*snapToText:*/true); 
                        if (cursorPosition != null)
                        { 
                            _textEditor.Selection.SetSelectionByMouse(cursorPosition, mouseDownPoint); 
                        }
                    } 
                    _dragStarted = false;
                }
            }
 
            // Starts OLE dragdrop process if movement was started from
            // within selection and initial move is big enough for drag to start. 
            // Returns true if drag is in progress 
            /// 
            ///   Critical: This code calls into _createDataObject 
            ///   TreatAsSafe: This will bail if called in partial trust
            /// 
            [SecurityCritical,SecurityTreatAsSafe]	
            internal bool SourceOnMouseMove(Point mouseMovePoint) 
            {
                // Not allow the initiating DragDrop operation without the unmanaged code permission. 
                // We chose to use this over clipboard because this was causing issues in LocalIntranet 
                // which has similar restrictions as internet but has clipboard permission
                if (!_dragStarted || !SecurityHelper.CheckUnmanagedCodePermission()) 
                {
                    return false; // false means that drag is not involved at all - selection extension should continue
                }
 
                // Check the mouse drag to start DragDrop operation.
                if (!InitialThresholdCrossed(mouseMovePoint)) 
                { 
                    return true; // true means that drag is in progress, even though not yet started - so selection should not extend
                } 

                ITextSelection selection = _textEditor.Selection;

                // NOTE: This calls OnMouseMove recursively; 
                // but because UiScope.IsMouseCaptured is false already,
                // we'll return with no actions 
                // This is the first move in drag-drop gesture. 
                // Execure the whole drag-drop ssequence: returns after the drop
                _dragStarted = false; 

                // Execute OLE drag-drop process (synchronousely)
                // ----------------------------------------------
 
                // Set the original text range to delete it with DragDropEffects.Move effect.
                _dragSourceTextRange = new TextRange(selection.Start, selection.End); 
 
                // Prepare data object (including side effects from application customization)
 
                // Note: _CreateDataObject raises a public event which might throw a recoverable exception.
                IDataObject dataObject = TextEditorCopyPaste._CreateDataObject(_textEditor, /*isDragDrop:*/true);

                if (dataObject != null) // null would mean that application cancelled the command 
                {
                    // 
                    SourceDoDragDrop(selection, dataObject); 

                    // Release mouse capture, because DoDragDrop is taking 
                    // a mouse resposibility from now on.
                    // ReleaseMouseCapture shouldn't call before calling DoDragDroop
                    // that cause the generating WM_MOUSELEAVE message by system
                    // (xxxCapture xxxCancelMouseMoverTracking) that appear MouseLeave 
                    // event during DragDrop event.
                    _textEditor.UiScope.ReleaseMouseCapture(); 
 
                    return true; // true means that drag is in progress. Selection should not extend.
                } 
                else
                {
                    // The DragDrop process has been terminated by application custom code
                    // 
                    return false;
                } 
            } 

            // Check whether the mouse is dragged with the minimum width and height. 
            // _dragRect is Width and height of a rectangle centered on a drag point to allow for limited movement
            // of the mouse pointer before a drag operation begins.
            // It allows the user to click and release the mouse button easily without unintentionally starting a drag operation.
            private bool InitialThresholdCrossed(Point dragPoint) 
            {
                // Check the current poisition is in the drag rect. 
                return !_dragRect.Contains(dragPoint.X, dragPoint.Y); 
            }
 
            /// 
            /// DragEnd event handler from DragDrop behavior.
            /// 
            private void SourceDoDragDrop(ITextSelection selection, IDataObject dataObject) 
            {
                // Run OLE drag-drop process. It will eat all user input until the drop 
                DragDropEffects allowedDragDropEffects = DragDropEffects.Copy; 
                if (!_textEditor.IsReadOnly)
                { 
                    allowedDragDropEffects |= DragDropEffects.Move;
                }

                DragDropEffects resultingDragDropEffects = DragDrop.DoDragDrop( // 
                    _textEditor.UiScope, // dragSource,
                    dataObject, // 
                    allowedDragDropEffects); 

                // Remove source selection 
                if (!_textEditor.IsReadOnly && //
                    resultingDragDropEffects == DragDropEffects.Move && //
                    _dragSourceTextRange != null &&
                    !_dragSourceTextRange.IsEmpty) 
                {
                    // Normally we delete the source selection from OnDrop event, 
                    // unless source and target TextBoxes are different. 
                    // In this case the source selection is still not empty,
                    // which means that target was in a different TextBox. 
                    // So we still need to delete the selected content in the source one.
                    // This will create an undo unit different from a dropping one,
                    // which is ok, because it will be in different TextBox's undo stack.
                    using (selection.DeclareChangeBlock()) 
                    {
                        // This is end of Move - we need to delete source content 
                        _dragSourceTextRange.Text = String.Empty; 
                    }
                } 

                // Clean up the text range.
                _dragSourceTextRange = null;
 
                // Check the data binding expression and update the source and target if the drag source
                // has the binding expression. Without this, data binding is broken after complete the 
                // drag-drop operation because Drop() paste the object then set the focus to the target. 
                // The losting focus invoke the data binding expression's Update(), but the source isn't
                // updated yet before complete DoDragDrop. 
                BindingExpressionBase bindingExpression = BindingOperations.GetBindingExpressionBase(
                    _textEditor.UiScope, TextBox.TextProperty);
                if (bindingExpression != null)
                { 
                    bindingExpression.UpdateSource();
                    bindingExpression.UpdateTarget(); 
                } 
            }
 
            // Creates DropCaret
            internal void TargetEnsureDropCaret()
            {
                if (_caretDragDrop == null) 
                {
                    // 
 
                    // Add the caret.
                    // Create caret to show it during the dragging operation. 
                    _caretDragDrop = new CaretElement(_textEditor, /*isBlinkEnabled:*/false);

                    // Initialize the caret.
                    // 
                    _caretDragDrop.Hide();
                } 
            } 

            /// A handler for an event reporting that the drag enter during drag-and-drop operation. 
            internal void TargetOnDragEnter(DragEventArgs e)
            {
                if (!AllowDragDrop(e))
                { 
                    return;
                } 
 
                // Ok, there's data to move or copy here.
                if ((e.AllowedEffects & DragDropEffects.Move) != 0) 
                {
                    e.Effects = DragDropEffects.Move;
                }
 
                bool ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0);
                if (ctrlKeyDown) 
                { 
                    e.Effects |= DragDropEffects.Copy;
                } 

                // Create the drag-and-drop caret to show it on the drop target candidate place.
                TargetEnsureDropCaret();
            } 

            /// A handler for an event reporting that the drag over during drag-and-drop operation. 
            internal void TargetOnDragOver(DragEventArgs e) 
            {
                if (!AllowDragDrop(e)) 
                {
                    return;
                }
 
                // Ok, there's data to move or copy here.
                if ((e.AllowedEffects & DragDropEffects.Move) != 0) 
                { 
                    e.Effects = DragDropEffects.Move;
                } 

                bool ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0);
                if (ctrlKeyDown)
                { 
                    e.Effects |= DragDropEffects.Copy;
                } 
 
                // Show the caret on the drag over target position.
                if (_caretDragDrop != null) 
                {
                    // Update the layout to get the corrected text position. Otherwise, we can get the
                    // incorrected text position.
                    if (!_textEditor.TextView.Validate(e.GetPosition(_textEditor.TextView.RenderScope))) 
                    {
                        return; 
                    } 

                    // Find the scroller from the render scope 
                    FrameworkElement scroller = _textEditor._Scroller;

                    // Automatically scroll the dropable content(line or page up/down) if scroller is available
                    if (scroller != null) 
                    {
                        // Get the ScrollInfo to scroll a line or page up/down 
                        IScrollInfo scrollInfo = scroller as IScrollInfo; 

                        if (scrollInfo == null && scroller is ScrollViewer) 
                        {
                            scrollInfo = ((ScrollViewer)scroller).ScrollInfo;
                        }
 
                        Invariant.Assert(scrollInfo != null);
 
                        Point pointScroller = e.GetPosition((IInputElement)scroller); 
                        double pageHeight = (double)_textEditor.UiScope.GetValue(TextEditor.PageHeightProperty);
                        double slowAreaHeight = ScrollViewer._scrollLineDelta * 2; 

                        if (pointScroller.Y < slowAreaHeight)
                        {
                            // Drag position is on the scroll area that we need to scroll up 
                            if (pointScroller.Y > slowAreaHeight / 2)
                            { 
                                // scroll a line up 
                                scrollInfo.LineUp();
                            } 
                            else
                            {
                                // scroll a page up
                                scrollInfo.PageUp(); 
                            }
                        } 
                        else if (pointScroller.Y > (pageHeight - slowAreaHeight)) 
                        {
                            // Drag position is on the scroll area that we need to scroll down 
                            if (pointScroller.Y < (pageHeight - slowAreaHeight / 2))
                            {
                                // scroll a line down
                                scrollInfo.LineDown(); 
                            }
                            else 
                            { 
                                // scroll a page down
                                scrollInfo.PageDown(); 
                            }
                        }
                    }
 
                    // Get the current text position from the dropable mouse point.
                    _textEditor.TextView.RenderScope.UpdateLayout(); // 
 
                    if (_textEditor.TextView.IsValid)
                    { 
                        ITextPointer dragPosition = GetDropPosition(_textEditor.TextView.RenderScope as Visual, e.GetPosition(_textEditor.TextView.RenderScope));

                        if (dragPosition != null)
                        { 
                            // Get the caret position to show the dropable point.
                            Rect caretRectangle = this.TextView.GetRectangleFromTextPosition(dragPosition); 
 
                            // NOTE: We DO NOT use GetCurrentValue because springload formatting should NOT be involved for drop caret.
                            object fontStylePropertyValue = dragPosition.GetValue(TextElement.FontStyleProperty); 
                            bool italic = (_textEditor.AcceptsRichContent && fontStylePropertyValue != DependencyProperty.UnsetValue && (FontStyle)fontStylePropertyValue == FontStyles.Italic);
                            Brush caretBrush = TextSelection.GetCaretBrush(_textEditor, /*opacity:0.5f*/0x7f);

                            // Show the caret on the dropable position. 
                            _caretDragDrop.Update(/*visible:*/true, caretRectangle, caretBrush, italic, CaretScrollMethod.None, /*wordWrappingPosition*/ double.NaN);
                        } 
                    } 
                }
            } 

            /// 
            /// Calculates a TextPointer indended for dropping the text.
            ///  
            /// 
            ///  
            ///  
            /// ITextPointer intended for dropping the selected text.
            /// Adjusts the dropping point to a word boundary (beginning of word) 
            /// in case if source range contains whole words.
            /// The position returned is oriented towards a character
            /// under the mouse pointer.
            ///  
            private ITextPointer GetDropPosition(Visual target, Point point)
            { 
                Invariant.Assert(target != null); 
                Invariant.Assert(_textEditor.TextView.IsValid); // caller must guarantee this.
 
                // Convert point to RenderScope
                if (target != _textEditor.TextView.RenderScope && target != null && (_textEditor.TextView.RenderScope).IsAncestorOf(target))
                {
                    GeneralTransform transform = target.TransformToAncestor(_textEditor.TextView.RenderScope); 
                    transform.TryTransform(point, out point);
                } 
 
                ITextPointer dropPosition = this.TextView.GetTextPositionFromPoint(point, /*snapToText:*/true);
 
                // For rich text content we adjust drop position to word boundary
                if (dropPosition != null)
                {
                    // Normalize drop position 
                    dropPosition = dropPosition.GetInsertionPosition(dropPosition.LogicalDirection);
 
                    if (_textEditor.AcceptsRichContent) 
                    {
                        TextSegment lineRange = TextEditorSelection.GetNormalizedLineRange(this.TextView, dropPosition); 

                        if (!lineRange.IsNull &&
                            // The drop position must be before of end of line
                            dropPosition.CompareTo(lineRange.End) < 0 && 
                            // We check if we are not at word boundary already:
                            !TextPointerBase.IsAtWordBoundary(dropPosition, /*insideWordDirection:*/LogicalDirection.Forward) && 
                            // We do not do it if the source range was not on word boundaries from both ends 
                            _dragSourceTextRange != null && //
                            TextPointerBase.IsAtWordBoundary(_dragSourceTextRange.Start, LogicalDirection.Forward) && // 
                            TextPointerBase.IsAtWordBoundary(_dragSourceTextRange.End, LogicalDirection.Forward))
                        {
                            // Move to word boundary. Select closest one to a dropPosition.
                            TextSegment wordSegment = TextPointerBase.GetWordRange(dropPosition); 
                            string wordText = TextRangeBase.GetTextInternal(wordSegment.Start, wordSegment.End);
                            int indexInWord = wordSegment.Start.GetOffsetToPosition(dropPosition); 
                            dropPosition = (indexInWord < (wordText.Length / 2)) ? wordSegment.Start : wordSegment.End; 
                        }
                    } 
                }

                return dropPosition;
            } 

            internal void TargetOnDragLeave() 
            { 
                // Delete the caret
                if (_caretDragDrop != null) 
                {
                    AdornerLayer layer = AdornerLayer.GetAdornerLayer(TextView.RenderScope);
                    layer.Remove(_caretDragDrop);
                    _caretDragDrop = null; 
                }
            } 
 
            /// 
            /// Called from an event reporting that the drop happened. 
            /// 
            internal void TargetOnDrop(DragEventArgs e)
            {
                // 

                if (!AllowDragDrop(e)) 
                { 
                    return;
                } 

                ITextSelection selection = _textEditor.Selection;
                Invariant.Assert(selection != null);
 
                // Delete the caret.
                if (_caretDragDrop != null) 
                { 
                    AdornerLayer layer = AdornerLayer.GetAdornerLayer(TextView.RenderScope);
                    layer.Remove(_caretDragDrop); 
                    _caretDragDrop = null;
                }

                if (e.Data == null || e.AllowedEffects == DragDropEffects.None) 
                {
                    e.Effects = DragDropEffects.None; 
                    return; 
                }
 
                if ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0)
                {
                    e.Effects = DragDropEffects.Copy;
                } 
                else if (e.Effects != DragDropEffects.Copy)
                { 
                    e.Effects = DragDropEffects.Move; 
                }
 
                // Force a layout update on the content so the GetTextPositionFromPoint
                // call following can succeed.
                if (!_textEditor.TextView.Validate(e.GetPosition(_textEditor.TextView.RenderScope)))
                { 
                    e.Effects = DragDropEffects.None;
                    return; 
                } 

                // Get the text position from the text target point. 
                ITextPointer dropPosition = GetDropPosition(_textEditor.TextView.RenderScope as Visual, e.GetPosition(_textEditor.TextView.RenderScope));

                if (dropPosition != null)
                { 
                    if (_dragSourceTextRange != null && _dragSourceTextRange.Start.TextContainer == selection.Start.TextContainer &&
                        !selection.IsEmpty && IsSelectionContainsDropPosition(selection, dropPosition)) 
                    { 
                        // When we drop inside of selected area, we
                        // should not select dropped content, 
                        // otherwise it looks for end user as if
                        // nothing happened.

                        // Set caret to this position. 
                        selection.SetCaretToPosition(dropPosition, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/true);
 
                        // Indicate the resulting effect of an action 
                        // Note that dropResult may stay equal to DragDropResult.Drop
                        e.Effects = DragDropEffects.None; 

                        // Mark the event as handled
                        e.Handled = true;
                    } 
                    else
                    { 
                        using (selection.DeclareChangeBlock()) 
                        {
                            // For MaxLength filter work correctly in case 
                            // when we dragdrop within the same TextContainer,
                            // we need to delete dragged content first -
                            // before dropping when filtering will occur.
                            // Note, that this will duplicate operation on 
                            // source side, but it will be void deletion action
                            if ((e.Effects & DragDropEffects.Move) != 0 && // 
                                _dragSourceTextRange != null && _dragSourceTextRange.Start.TextContainer == selection.Start.TextContainer) 
                            {
                                _dragSourceTextRange.Text = String.Empty; 
                            }

                            // When we drop outside of selection,
                            // we should ignore current selection and 
                            // move ip into dropping point.
                            selection.SetCaretToPosition(dropPosition, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/true); 
 
                            // _DoPaste raises a public event -- could raise recoverable exception.
                            e.Handled = TextEditorCopyPaste._DoPaste(_textEditor, e.Data, /*isDragDrop:*/true); 
                            //
                        }
                    }
 
                    if (e.Handled)
                    { 
                        // Set the drop target as the foreground window. 
                        Win32SetForegroundWindow();
 
                        // Set the focus into the drop target.
                        _textEditor.UiScope.Focus();
                    }
                    else 
                    {
                        // When a target did not handle a drop event, we must 
                        // prevent from deleting a content on source end - 
                        // otherwise we'll have data loss
                        e.Effects = DragDropEffects.None; 
                    }
                }
            }
 
            // Table cell selection currently include the next adjacent cell start element so that
            // selection always contains the drop position even though the drop position is on the next cell. 
            // This private method check the table range really contains the drop position or not. 
            private bool IsSelectionContainsDropPosition(ITextSelection selection, ITextPointer dropPosition)
            { 
                bool selectionContainedDropPosition = selection.Contains(dropPosition);

                if (selectionContainedDropPosition && selection.IsTableCellRange)
                { 
                    for (int i = 0; i < selection.TextSegments.Count; i++)
                    { 
                        TextSegment textSegment = selection._TextSegments[i]; 

                        if (dropPosition.CompareTo(textSegment.End) == 0) 
                        {
                            selectionContainedDropPosition = false;
                            break;
                        } 
                    }
                } 
 
                return selectionContainedDropPosition;
            } 

            private bool AllowDragDrop(DragEventArgs e)
            {
                if (!_textEditor.IsReadOnly && _textEditor.TextView != null && _textEditor.TextView.RenderScope != null) 
                {
                    Window window = Window.GetWindow(_textEditor.TextView.RenderScope); 
                    if (window == null) 
                    {
                        return true; 
                    }

                    WindowInteropHelper helper = new WindowInteropHelper(window);
                    if (SafeNativeMethods.IsWindowEnabled(new HandleRef(null, helper.Handle))) 
                    {
                        return true; 
                    } 
                }
 
                e.Effects = DragDropEffects.None;
                return false;
            }
 
            /// 
            /// Call Win32 SetForegroundWindow to set the drop target as the foreground window. 
            ///  
            /// 
            /// Critical - This calls PresentationSource.FromVisual() and PresentationSource.Handle 
            ///            under elevation.
            /// Safe - This doesn't expose the information. The SetForegroundWindow call will only
            ///        set the drop window as the foreground without exposing the information.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            private void Win32SetForegroundWindow() 
            { 
                PresentationSource source = null;
                IntPtr hwnd = IntPtr.Zero; 
                source = PresentationSource.CriticalFromVisual(_textEditor.UiScope);
                if (source != null)
                {
                    new UIPermission(UIPermissionWindow.AllWindows).Assert();   //BlessedAssert 
                    try
                    { 
                        hwnd = (source as IWin32Window).Handle; 
                    }
                    finally 
                    {

                        UIPermission.RevertAssert();
                    } 
                }
 
                if (hwnd != IntPtr.Zero) 
                {
                    UnsafeNativeMethods.SetForegroundWindow(new HandleRef(null, hwnd)); 
                }
            }

            private ITextView TextView 
            {
                get 
                { 
                    return _textEditor.TextView;
                } 
            }

            private TextEditor _textEditor;
 
            // TextRange for drag source.
            private ITextRange _dragSourceTextRange; 
 
            // Flag indicating that mouse dragging was started within selection.
            // It is used for deferring drag/drop until first move, 
            // and for setting selection on mouseup in case of no move.
            private bool _dragStarted;

            // DragDrop caret to show it on the dropable target position. 
            //
 
 

            private CaretElement _caretDragDrop; 

            // Rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins.
            private Rect _dragRect;
        } 

        ///  
        /// An event reporting that the query continue drag during drag-and-drop operation. 
        /// 
        internal static void OnQueryContinueDrag(object sender, QueryContinueDragEventArgs e) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender);

            if (This == null) 
            {
                return; 
            } 

            // Ignore the event if the editor has been detached from its scope 
            if (!This._IsEnabled)
            {
                return;
            } 

            // Consider event handled 
            e.Handled = true; 

            e.Action = DragAction.Continue; 
            bool mouseUp = (((int)e.KeyStates & (int)DragDropKeyStates.LeftMouseButton) == 0);
            if (e.EscapePressed)
            {
                e.Action = DragAction.Cancel; 
            }
            else if (mouseUp) 
            { 
                e.Action = DragAction.Drop;
            } 
        }

        /// 
        /// An event reporting that the give feedback during drag-and-drop operation. 
        /// 
        internal static void OnGiveFeedback(object sender, GiveFeedbackEventArgs e) 
        { 
            TextEditor This = TextEditor._GetTextEditor(sender);
 
            if (This == null)
            {
                return;
            } 

            // Ignore the event if the editor has been detached from its scope 
            if (!This._IsEnabled) 
            {
                return; 
            }

            // Show the default DragDrop cursor.
            e.UseDefaultCursors = true; 

            // Consider event handled 
            e.Handled = true; 
        }
 
        /// 
        /// An event reporting that the drag enter during drag-and-drop operation.
        /// 
        internal static void OnDragEnter(object sender, DragEventArgs e) 
        {
            // Consider event handled 
            e.Handled = true; 

            TextEditor This = TextEditor._GetTextEditor(sender); 

            if (This == null)
            {
                e.Effects = DragDropEffects.None; 
                return;
            } 
 
            // Ignore the event if the editor has been detached from its scope
            if (!This._IsEnabled || This.TextView == null || This.TextView.RenderScope == null) 
            {
                e.Effects = DragDropEffects.None;
                return;
            } 

            // If there's no supported data available, don't allow the drag-and-drop. 
            if (e.Data == null) 
            {
                e.Effects = DragDropEffects.None; 
                return;
            }

            // Ignore the event if there isn't the dropable(pasteable) data format 
            if (TextEditorCopyPaste.GetPasteApplyFormat(This, e.Data) == string.Empty)
            { 
                e.Effects = DragDropEffects.None; 
                return;
            } 

            TextEditorTyping._FlushPendingInputItems(This);

            if (!This.TextView.Validate(e.GetPosition(This.TextView.RenderScope))) 
            {
                e.Effects = DragDropEffects.None; 
                return; 
            }
 
            This._dragDropProcess.TargetOnDragEnter(e);
        }

        ///  
        /// An event reporting that the drag over during drag-and-drop operation.
        ///  
        internal static void OnDragOver(object sender, DragEventArgs e) 
        {
            // Consider event handled 
            e.Handled = true;

            TextEditor This = TextEditor._GetTextEditor(sender);
 
            if (This == null)
            { 
                e.Effects = DragDropEffects.None; 
                return;
            } 

            // Ignore the event if the editor has been detached from its scope
            if (!This._IsEnabled || This.TextView == null || This.TextView.RenderScope == null)
            { 
                e.Effects = DragDropEffects.None;
                return; 
            } 

            // If there's no supported data available, don't allow the drag-and-drop. 
            if (e.Data == null)
            {
                e.Effects = DragDropEffects.None;
                return; 
            }
 
            // Ignore the event if there isn't the dropable(pasteable) data format 
            if (TextEditorCopyPaste.GetPasteApplyFormat(This, e.Data) == string.Empty)
            { 
                e.Effects = DragDropEffects.None;
                return;
            }
 
            TextEditorTyping._FlushPendingInputItems(This);
            if (!This.TextView.Validate(e.GetPosition(This.TextView.RenderScope))) 
            { 
                e.Effects = DragDropEffects.None;
                return; 
            }

            This._dragDropProcess.TargetOnDragOver(e);
        } 

        ///  
        /// An event reporting that the drag leave during drag-and-drop operation. 
        /// 
        internal static void OnDragLeave(object sender, DragEventArgs e) 
        {
            // Consider event handled
            e.Handled = true;
 
            TextEditor This = TextEditor._GetTextEditor(sender);
 
            if (This == null) 
            {
                return; 
            }

            //
            // Remove UI feedback here if UI is specified on DragEnter. 
            //
            // Ignore the event if the editor has been detached from its scope 
            if (!This._IsEnabled) 
            {
                e.Effects = DragDropEffects.None; 
                return;
            }

            TextEditorTyping._FlushPendingInputItems(This); 
            if (!This.TextView.Validate(e.GetPosition(This.TextView.RenderScope)))
            { 
                return; 
            }
 
            This._dragDropProcess.TargetOnDragLeave();
        }

        ///  
        /// An event reporting that the drop happened.
        ///  
        internal static void OnDrop(object sender, DragEventArgs e) 
        {
            TextEditor This = TextEditor._GetTextEditor(sender); 

            if (This == null)
            {
                return; 
            }
 
            // Ignore the event if the editor has been detached from its scope 
            if (!This._IsEnabled)
            { 
                return;
            }

            TextEditorTyping._FlushPendingInputItems(This); 
            if (!This.TextView.Validate(e.GetPosition(This.TextView.RenderScope)))
            { 
                return; 
            }
 
            This._dragDropProcess.TargetOnDrop(e);
        }

        #endregion Class Internal Types 
    }
} 

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