Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SaveWorkflowCommand.cs
- ConfigXmlDocument.cs
- DbParameterHelper.cs
- OutputScopeManager.cs
- FileSystemWatcher.cs
- FixedSOMImage.cs
- ComplusEndpointConfigContainer.cs
- FileStream.cs
- HttpResponseBase.cs
- CheckedPointers.cs
- Cloud.cs
- MachineKey.cs
- PropertyFilterAttribute.cs
- HostedElements.cs
- DayRenderEvent.cs
- _OverlappedAsyncResult.cs
- namescope.cs
- ContentPlaceHolder.cs
- ResourceIDHelper.cs
- RTLAwareMessageBox.cs
- SlipBehavior.cs
- PropertyEntry.cs
- ParserStreamGeometryContext.cs
- DebugInfoExpression.cs
- ScrollChrome.cs
- StandardTransformFactory.cs
- CodeSnippetExpression.cs
- StatusBarAutomationPeer.cs
- DefaultAuthorizationContext.cs
- ApplicationServicesHostFactory.cs
- ScrollChrome.cs
- StateBag.cs
- NameValuePair.cs
- ListItemCollection.cs
- TemplateControlParser.cs
- FormatException.cs
- WebPartEditorApplyVerb.cs
- TreeWalkHelper.cs
- WebContext.cs
- MembershipUser.cs
- RightsManagementPermission.cs
- FunctionMappingTranslator.cs
- QueryStringParameter.cs
- SqlCacheDependencySection.cs
- SyndicationPerson.cs
- EntityContainer.cs
- PropertyBuilder.cs
- OleDbConnectionPoolGroupProviderInfo.cs
- AccessorTable.cs
- QueryAccessibilityHelpEvent.cs
- XmlAttributeCollection.cs
- CodeTypeMemberCollection.cs
- SqlSelectStatement.cs
- HandledEventArgs.cs
- AnimationClockResource.cs
- PersonalizationState.cs
- KerberosSecurityTokenProvider.cs
- LocalClientSecuritySettings.cs
- FastEncoderStatics.cs
- TrackingStringDictionary.cs
- CodeAccessSecurityEngine.cs
- HGlobalSafeHandle.cs
- Comparer.cs
- SrgsOneOf.cs
- StringPropertyBuilder.cs
- path.cs
- IpcChannel.cs
- SqlNodeAnnotations.cs
- RawAppCommandInputReport.cs
- ArrayWithOffset.cs
- RegexMatch.cs
- FamilyMap.cs
- TypeReference.cs
- sitestring.cs
- RuntimeHelpers.cs
- ReceiveSecurityHeaderEntry.cs
- SoapDocumentServiceAttribute.cs
- SystemColorTracker.cs
- IntegerValidator.cs
- TextServicesProperty.cs
- SchemaNamespaceManager.cs
- BitmapCodecInfo.cs
- InfoCardRSAOAEPKeyExchangeFormatter.cs
- MetadataArtifactLoaderXmlReaderWrapper.cs
- SafeCryptHandles.cs
- DataGridViewCellStyleChangedEventArgs.cs
- TreeNode.cs
- XmlCustomFormatter.cs
- AuthenticationModulesSection.cs
- DBConnection.cs
- PropertyEntry.cs
- BrowserCapabilitiesCodeGenerator.cs
- ParameterExpression.cs
- DesignerTransaction.cs
- PageContent.cs
- RemoteWebConfigurationHost.cs
- DeclarativeCatalogPart.cs
- ValueType.cs
- StyleHelper.cs
- ModuleConfigurationInfo.cs