Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / DragDrop.cs / 1 / DragDrop.cs
//---------------------------------------------------------------------------- // // File: DragDrop.cs // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: The DragDrop system is for drag-and-drop operation. // // See spec at http://avalon/uis/Data%20Transfer%20clipboard%20dragdrop/DragDrop%20design%20on%20WPP.mht // // History: // 07/10/2003 : sangilj Created // 08/19/2004 : sangilj Event name changes and code clean up // //--------------------------------------------------------------------------- using MS.Win32; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Security; using System.Security.Permissions; using MS.Internal; using MS.Internal.PresentationCore; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; namespace System.Windows { #region DragDrop ////// Provides drag-and-drop operation methods. /// public static class DragDrop { //----------------------------------------------------- // // DragDrop Event // //----------------------------------------------------- #region DragDrop Event ////// PreviewQueryContinueDrag /// public static readonly RoutedEvent PreviewQueryContinueDragEvent = EventManager.RegisterRoutedEvent("PreviewQueryContinueDrag", RoutingStrategy.Tunnel, typeof(QueryContinueDragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewQueryContinueDrag attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewQueryContinueDragHandler(DependencyObject element, QueryContinueDragEventHandler handler) { UIElement.AddHandler(element, PreviewQueryContinueDragEvent, handler); } ////// Removes a handler for the PreviewQueryContinueDrag attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewQueryContinueDragHandler(DependencyObject element, QueryContinueDragEventHandler handler) { UIElement.RemoveHandler(element, PreviewQueryContinueDragEvent, handler); } ////// QueryContinueDrag /// public static readonly RoutedEvent QueryContinueDragEvent = EventManager.RegisterRoutedEvent("QueryContinueDrag", RoutingStrategy.Bubble, typeof(QueryContinueDragEventHandler), typeof(DragDrop)); ////// Adds a handler for the QueryContinueDrag attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddQueryContinueDragHandler(DependencyObject element, QueryContinueDragEventHandler handler) { UIElement.AddHandler(element, QueryContinueDragEvent, handler); } ////// Removes a handler for the QueryContinueDrag attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveQueryContinueDragHandler(DependencyObject element, QueryContinueDragEventHandler handler) { UIElement.RemoveHandler(element, QueryContinueDragEvent, handler); } ////// PreviewGiveFeedback /// public static readonly RoutedEvent PreviewGiveFeedbackEvent = EventManager.RegisterRoutedEvent("PreviewGiveFeedback", RoutingStrategy.Tunnel, typeof(GiveFeedbackEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewGiveFeedback attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewGiveFeedbackHandler(DependencyObject element, GiveFeedbackEventHandler handler) { UIElement.AddHandler(element, PreviewGiveFeedbackEvent, handler); } ////// Removes a handler for the PreviewGiveFeedback attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewGiveFeedbackHandler(DependencyObject element, GiveFeedbackEventHandler handler) { UIElement.RemoveHandler(element, PreviewGiveFeedbackEvent, handler); } ////// GiveFeedback /// public static readonly RoutedEvent GiveFeedbackEvent = EventManager.RegisterRoutedEvent("GiveFeedback", RoutingStrategy.Bubble, typeof(GiveFeedbackEventHandler), typeof(DragDrop)); ////// Adds a handler for the GiveFeedback attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddGiveFeedbackHandler(DependencyObject element, GiveFeedbackEventHandler handler) { UIElement.AddHandler(element, GiveFeedbackEvent, handler); } ////// Removes a handler for the GiveFeedback attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveGiveFeedbackHandler(DependencyObject element, GiveFeedbackEventHandler handler) { UIElement.RemoveHandler(element, GiveFeedbackEvent, handler); } ////// PreviewDragEnter /// public static readonly RoutedEvent PreviewDragEnterEvent = EventManager.RegisterRoutedEvent("PreviewDragEnter", RoutingStrategy.Tunnel, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewDragEnter attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewDragEnterHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, PreviewDragEnterEvent, handler); } ////// Removes a handler for the PreviewDragEnter attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewDragEnterHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, PreviewDragEnterEvent, handler); } ////// DragEnter /// public static readonly RoutedEvent DragEnterEvent = EventManager.RegisterRoutedEvent("DragEnter", RoutingStrategy.Bubble, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the DragEnter attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddDragEnterHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, DragEnterEvent, handler); } ////// Removes a handler for the DragEnter attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveDragEnterHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, DragEnterEvent, handler); } ////// PreviewDragOver /// public static readonly RoutedEvent PreviewDragOverEvent = EventManager.RegisterRoutedEvent("PreviewDragOver", RoutingStrategy.Tunnel, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewDragOver attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewDragOverHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, PreviewDragOverEvent, handler); } ////// Removes a handler for the PreviewDragOver attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewDragOverHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, PreviewDragOverEvent, handler); } ////// DragOver /// public static readonly RoutedEvent DragOverEvent = EventManager.RegisterRoutedEvent("DragOver", RoutingStrategy.Bubble, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the DragOver attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddDragOverHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, DragOverEvent, handler); } ////// Removes a handler for the DragOver attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveDragOverHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, DragOverEvent, handler); } ////// PreviewDragLeave /// public static readonly RoutedEvent PreviewDragLeaveEvent = EventManager.RegisterRoutedEvent("PreviewDragLeave", RoutingStrategy.Tunnel, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewDragLeave attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewDragLeaveHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, PreviewDragLeaveEvent, handler); } ////// Removes a handler for the PreviewDragLeave attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewDragLeaveHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, PreviewDragLeaveEvent, handler); } ////// DragLeave /// public static readonly RoutedEvent DragLeaveEvent = EventManager.RegisterRoutedEvent("DragLeave", RoutingStrategy.Bubble, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the DragLeave attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddDragLeaveHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, DragLeaveEvent, handler); } ////// Removes a handler for the DragLeave attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveDragLeaveHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, DragLeaveEvent, handler); } ////// PreviewDrop /// public static readonly RoutedEvent PreviewDropEvent = EventManager.RegisterRoutedEvent("PreviewDrop", RoutingStrategy.Tunnel, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewDrop attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewDropHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, PreviewDropEvent, handler); } ////// Removes a handler for the PreviewDrop attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewDropHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, PreviewDropEvent, handler); } ////// Drop /// public static readonly RoutedEvent DropEvent = EventManager.RegisterRoutedEvent("Drop", RoutingStrategy.Bubble, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the Drop attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddDropHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, DropEvent, handler); } ////// Removes a handler for the Drop attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveDropHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, DropEvent, handler); } #endregion DragDrop Event //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Begins a drag-and-drop operation. /// /// /// The drag source object. /// /// /// The data to drag. /// /// /// The allowed effects that is one of the DragDropEffects values. /// ////// Requires UnmanagedCode permission. /// If caller does not have this permission, the dragdrop will not occur. /// ////// Critical - calls critical code (OleDoDragDrop), but this is OK since we won't /// allow the initiate DragDrop operation without the unmanaged code permission. /// Demand the unmanaged code permission to block initiating DragDrop both /// intranet and internet zone. /// PublicOK - It's disabled in partial trust. /// [SecurityCritical] public static DragDropEffects DoDragDrop(DependencyObject dragSource, object data, DragDropEffects allowedEffects) { DataObject dataObject; // Demand the unmanaged code permission to initiate DragDrop operation. SecurityHelper.DemandUnmanagedCode(); if (dragSource == null) { throw new ArgumentNullException("dragSource"); } if (data == null) { throw new ArgumentNullException("data"); } dataObject = data as DataObject; if (dataObject == null) { // Create DataObject for DragDrop from the data. dataObject = new DataObject(data); } // Call OleDoDragDrop with DataObject. return OleDoDragDrop(dragSource, dataObject, allowedEffects); } #endregion Public Methods //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// Register the drop target which want to a droppable window. /// /// /// The window handle to be drop target . /// ////// Critical - calls critical code (OleRegisterDragDrop), and potentially deals with unmanged code.. /// /// TreatAsSafe - RegisterDropTarget check the unmanged code permission. /// Demmand the unmanaged code permission to block the register drop target /// both intranet and internet zone. /// [SecurityCritical, SecurityTreatAsSafe] internal static void RegisterDropTarget(IntPtr windowHandle) { if (SecurityHelper.CheckUnmanagedCodePermission() && windowHandle != IntPtr.Zero) { // Create OleDragSource and call Ole DoDragDrop for starting DragDrop. OleDropTarget oleDropTarget = new OleDropTarget(windowHandle); // Call OLE RegisterDragDrop and it will get the drop target events during drag-and-drop // operation on the drop target window. OleServicesContext.CurrentOleServicesContext.OleRegisterDragDrop( new HandleRef(null, windowHandle), (UnsafeNativeMethods.IOleDropTarget)oleDropTarget); } } ////// Revoke the drop target which was a droppable window. /// /// /// The window handle that can accept drop. /// ////// Critical - calls critical code (OleRevokeDragDrop).We do not want this called excessively /// TreatAsSafe - RevokeDropTarget check the unmanged code permission. /// Demmand the unmanaged code permission to block the revoke drop target /// both intranet and internet zone. /// [SecurityCritical, SecurityTreatAsSafe] internal static void RevokeDropTarget(IntPtr windowHandle) { if (SecurityHelper.CheckUnmanagedCodePermission() && windowHandle != IntPtr.Zero) { // Call OLE RevokeDragDrop to revoke the droppable target window. OleServicesContext.CurrentOleServicesContext.OleRevokeDragDrop( new HandleRef(null, windowHandle)); } } ////// Validate the dragdrop effects of DragDrop. /// internal static bool IsValidDragDropEffects(DragDropEffects dragDropEffects) { int dragDropEffectsAll; dragDropEffectsAll = (int)(DragDropEffects.None | DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link | DragDropEffects.Scroll | DragDropEffects.All); if (((int)dragDropEffects & ~dragDropEffectsAll) != 0) { return false; } return true; } ////// Validate the drag action of DragDrop. /// internal static bool IsValidDragAction(DragAction dragAction) { if (dragAction == DragAction.Continue || dragAction == DragAction.Drop || dragAction == DragAction.Cancel) { return true; } else { return false; } } ////// Validate the key states of DragDrop. /// internal static bool IsValidDragDropKeyStates(DragDropKeyStates dragDropKeyStates) { int keyStatesAll; keyStatesAll = (int)(DragDropKeyStates.LeftMouseButton | DragDropKeyStates.RightMouseButton | DragDropKeyStates.ShiftKey | DragDropKeyStates.ControlKey | DragDropKeyStates.MiddleMouseButton | DragDropKeyStates.AltKey); if (((int)dragDropKeyStates & ~keyStatesAll) != 0) { return false; } return true; } #endregion Internal Methods //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods ////// Begins a drag-and-drop operation through OLE DoDragDrop. /// /// /// The drag source object. /// /// /// The data object to drag. /// /// /// The allowed effects that is one of the DragDropEffects values. /// private static DragDropEffects OleDoDragDrop(DependencyObject dragSource, DataObject dataObject, DragDropEffects allowedEffects) { int[] dwEffect; OleDragSource oleDragSource; Debug.Assert(dragSource != null, "Invalid dragSource"); Debug.Assert(dataObject != null, "Invalid dataObject"); // Create the int array for passing parameter of OLE DoDragDrop dwEffect = new int[1]; // Create OleDragSource and call Ole DoDragDrop for starting DragDrop. oleDragSource = new OleDragSource(dragSource); // Call OLE DoDragDrop and it will hanlde all mouse and keyboard input until drop the object. // We don't need to check the error return since PreserveSig attribute is defined as "false" // which will pops up the exception automatically. OleServicesContext.CurrentOleServicesContext.OleDoDragDrop( (IComDataObject)dataObject, (UnsafeNativeMethods.IOleDropSource)oleDragSource, (int)allowedEffects, dwEffect); // return the drop effect of DragDrop. return (DragDropEffects)dwEffect[0]; } #endregion Private Methods } #endregion DragDrop #region OleDragSource ////// OleDragSource that handle ole QueryContinueDrag and GiveFeedback. /// internal class OleDragSource : UnsafeNativeMethods.IOleDropSource { //----------------------------------------------------- // // Constructor // //----------------------------------------------------- #region Constructor ////// OleDragSource constructor. /// public OleDragSource(DependencyObject dragSource) { _dragSource = dragSource; } #endregion Constructor //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region IOleDropSource ////// Query the source to know the drag continue or not. /// int UnsafeNativeMethods.IOleDropSource.OleQueryContinueDrag(int escapeKey, int grfkeyState) { bool escapePressed; QueryContinueDragEventArgs args; escapePressed = false; if (escapeKey != 0) { escapePressed = true; } // Create QueryContinueDrag event arguments. args = new QueryContinueDragEventArgs(escapePressed, (DragDropKeyStates)grfkeyState); // Raise the query continue drag event for both Tunnel(Preview) and Bubble. RaiseQueryContinueDragEvent(args); // Check the drag continue result. if (args.Action == DragAction.Continue) { return NativeMethods.S_OK; } else if (args.Action == DragAction.Drop) { return NativeMethods.DRAGDROP_S_DROP; } else if (args.Action == DragAction.Cancel) { return NativeMethods.DRAGDROP_S_CANCEL; } return NativeMethods.S_OK; } ////// Give feedback from the source whether use the default cursor or not. /// int UnsafeNativeMethods.IOleDropSource.OleGiveFeedback(int effect) { GiveFeedbackEventArgs args; // Create GiveFeedback event arguments. args = new GiveFeedbackEventArgs((DragDropEffects)effect, /*UseDefaultCursors*/ false); // Raise the give feedback event for both Tunnel(Preview) and Bubble. RaiseGiveFeedbackEvent(args); // Check the give feedback result whether use default cursors or not. if (args.UseDefaultCursors) { return NativeMethods.DRAGDROP_S_USEDEFAULTCURSORS; } return NativeMethods.S_OK; } ////// Raise QueryContinueDrag event for Tunel and Bubble. /// private void RaiseQueryContinueDragEvent(QueryContinueDragEventArgs args) { // Set PreviewQueryContinueDrag(Tunnel) first. args.RoutedEvent=DragDrop.PreviewQueryContinueDragEvent; // Raise the preview QueryContinueDrag event(Tunnel). if (_dragSource is UIElement) { ((UIElement)_dragSource).RaiseEvent(args); } else if (_dragSource is ContentElement) { ((ContentElement)_dragSource).RaiseEvent(args); } else if (_dragSource is UIElement3D) { ((UIElement3D)_dragSource).RaiseEvent(args); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } // Set QueryContinueDrag(Bubble). args.RoutedEvent = DragDrop.QueryContinueDragEvent; // Raise QueryContinueDrag event(Bubble). if (!args.Handled) { if (_dragSource is UIElement) { ((UIElement)_dragSource).RaiseEvent(args); } else if (_dragSource is ContentElement) { ((ContentElement)_dragSource).RaiseEvent(args); } else if (_dragSource is UIElement3D) { ((UIElement3D)_dragSource).RaiseEvent(args); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } } // Call the default event handling method internally if no one handle the drag source events. if (!args.Handled) { OnDefaultQueryContinueDrag(args); } } ////// Raise GiveFeedback event for Tunnel and Bubble. /// private void RaiseGiveFeedbackEvent(GiveFeedbackEventArgs args) { // Set PreviewGiveFeedback(Tunnel) first. args.RoutedEvent=DragDrop.PreviewGiveFeedbackEvent; // Raise the preview GiveFeedback(Tunnel). if (_dragSource is UIElement) { ((UIElement)_dragSource).RaiseEvent(args); } else if (_dragSource is ContentElement) { ((ContentElement)_dragSource).RaiseEvent(args); } else if (_dragSource is UIElement3D) { ((UIElement3D)_dragSource).RaiseEvent(args); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } // Set GiveFeedback event ID(Bubble). args.RoutedEvent = DragDrop.GiveFeedbackEvent; if (!args.Handled) { // Raise GiveFeedback event(Bubble). if (_dragSource is UIElement) { ((UIElement)_dragSource).RaiseEvent(args); } else if (_dragSource is ContentElement) { ((ContentElement)_dragSource).RaiseEvent(args); } else if (_dragSource is UIElement3D) { ((UIElement3D)_dragSource).RaiseEvent(args); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } } // Call the default event handling method internally if no one handle the drag source events. if (!args.Handled) { OnDefaultGiveFeedback(args); } } ////// Default query continue drag during drag-and-drop operation. /// private void OnDefaultQueryContinueDrag(QueryContinueDragEventArgs e) { bool mouseUp; mouseUp = false; e.Action = DragAction.Continue; mouseUp = (((int)e.KeyStates & (int)DragDropKeyStates.LeftMouseButton) == 0); if (e.EscapePressed) { e.Action = DragAction.Cancel; } else if (mouseUp) { e.Action = DragAction.Drop; } } ////// Default give feedback during drag-and-drop operation. /// private void OnDefaultGiveFeedback(GiveFeedbackEventArgs e) { // Show the default DragDrop cursor. e.UseDefaultCursors = true; } #endregion IOleDropSource //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields private DependencyObject _dragSource; #endregion Private Fields } #endregion OleDragSource #region OleDropTarget ////// OleDropTarget that handle ole DragEnter DragOver DragLeave and DragDrop. /// internal class OleDropTarget : DispatcherObject, UnsafeNativeMethods.IOleDropTarget { //------------------------------------------------------ // // Constructor // //----------------------------------------------------- #region Constructor ////// OleDropTarget Constructor. /// public OleDropTarget(IntPtr handle) { if (handle == IntPtr.Zero) { throw new ArgumentNullException("handle"); } _windowHandle = handle; } #endregion Constructor //------------------------------------------------------ // // IOleDropTarget Interface // //----------------------------------------------------- #region IOleDropTarget ////// OleDragEnter - check the data object and notify DragEnter to the target element. /// int UnsafeNativeMethods.IOleDropTarget.OleDragEnter(object data, int dragDropKeyStates, long point, ref int effects) { DependencyObject target; Point targetPoint; // Get the data object and immediately return if there isn't the data object or no available data. _dataObject = GetDataObject(data); if (_dataObject == null || !IsDataAvailable(_dataObject)) { // Set the none effect. effects = (int)DragDropEffects.None; return NativeMethods.S_FALSE; } // Get the current target from the mouse drag point that is based on screen. target = GetCurrentTarget(point, out targetPoint); // Set the last target element with the current target. _lastTarget = target; if (target != null) { // Create DragEvent agrument and then raise DragEnter event for Tunnel or Buuble event. RaiseDragEvent( DragDrop.DragEnterEvent, dragDropKeyStates, ref effects, target, targetPoint); } else { // Set the none effect. effects = (int)DragDropEffects.None; } return NativeMethods.S_OK; } ////// OleDragOver - get the drop effect from the target element. /// int UnsafeNativeMethods.IOleDropTarget.OleDragOver(int dragDropKeyStates, long point, ref int effects) { DependencyObject target; Point targetPoint; Invariant.Assert(_dataObject != null); // Get the current target from the mouse drag point that is based on screen. target = GetCurrentTarget(point, out targetPoint); // Raise DragOver event to the target to get DragDrop effect status from the target. if (target != null) { // Avalon apps can have only one window handle, so we need to generate DragLeave and // DragEnter event to target when target is changed by the mouse dragging. // If the current target is the same as the last target, just raise DragOver event to the target. if (target != _lastTarget) { try { if (_lastTarget != null) { // Raise DragLeave event to the last target. RaiseDragEvent( DragDrop.DragLeaveEvent, dragDropKeyStates, ref effects, _lastTarget, targetPoint); } // Raise DragEnter event to the new target. RaiseDragEvent( DragDrop.DragEnterEvent, dragDropKeyStates, ref effects, target, targetPoint); } finally { // Reset the last target element to check it with the next current element. _lastTarget = target; } } else { // Raise DragOver event to the target. RaiseDragEvent( DragDrop.DragOverEvent, dragDropKeyStates, ref effects, target, targetPoint); } } else { try { if (_lastTarget != null) { // Raise DragLeave event to the last target. RaiseDragEvent( DragDrop.DragLeaveEvent, dragDropKeyStates, ref effects, _lastTarget, targetPoint); } } finally { // Update the last target element as the current target element. _lastTarget = target; effects = (int)DragDropEffects.None; } } return NativeMethods.S_OK; } ////// OleDragLeave. /// int UnsafeNativeMethods.IOleDropTarget.OleDragLeave() { if (_lastTarget != null) { int effects; // Set DragDrop effects as DragDropEffects.None effects = 0; try { // Raise DragLeave event for the last target element. RaiseDragEvent( DragDrop.DragLeaveEvent, /* DragDropKeyStates.None */ 0, ref effects, _lastTarget, new Point(0, 0)); } finally { // Reset the last target and data object. _lastTarget = null; _dataObject = null; } } return NativeMethods.S_OK; } ////// OleDrop - drop the object to the target element. /// int UnsafeNativeMethods.IOleDropTarget.OleDrop(object data, int dragDropKeyStates, long point, ref int effects) { IDataObject dataObject; DependencyObject target; Point targetPoint; // Get the data object and then immediately return fail if there isn't the proper data. dataObject = GetDataObject(data); if (dataObject == null || !IsDataAvailable(dataObject)) { effects = (int)DragDropEffects.None; return NativeMethods.S_FALSE; } // Reset last element and target point. _lastTarget = null; // Get the current target from the screen mouse point. target = GetCurrentTarget(point, out targetPoint); // Raise Drop event to the target element. if (target != null) { // Raise Drop event to the drop target. RaiseDragEvent( DragDrop.DropEvent, dragDropKeyStates, ref effects, target, targetPoint); } else { effects = (int)DragDropEffects.None; } return NativeMethods.S_OK; } #endregion IOleDropTarget #region Private Methods ////// Raise Drag(Enter/Over/Leave/Drop) events to the taret. /// private void RaiseDragEvent(RoutedEvent dragEvent, int dragDropKeyStates, ref int effects, DependencyObject target, Point targetPoint) { DragEventArgs dragEventArgs; Invariant.Assert(_dataObject != null); Invariant.Assert(target != null); // Create DragEvent argement to raise DragEnter events to the target. dragEventArgs = new DragEventArgs( _dataObject, (DragDropKeyStates)dragDropKeyStates, (DragDropEffects)effects, target, targetPoint); // Set the preview(Tunnel) drop target events(Tunnel) first. if (dragEvent == DragDrop.DragEnterEvent) { dragEventArgs.RoutedEvent = DragDrop.PreviewDragEnterEvent; } else if (dragEvent == DragDrop.DragOverEvent) { dragEventArgs.RoutedEvent = DragDrop.PreviewDragOverEvent; } else if (dragEvent == DragDrop.DragLeaveEvent) { dragEventArgs.RoutedEvent = DragDrop.PreviewDragLeaveEvent; } else if (dragEvent == DragDrop.DropEvent) { dragEventArgs.RoutedEvent = DragDrop.PreviewDropEvent; } // Raise the preview drop target events(Tunnel). if (target is UIElement) { ((UIElement)target).RaiseEvent(dragEventArgs); } else if (target is ContentElement) { ((ContentElement)target).RaiseEvent(dragEventArgs); } else if (target is UIElement3D) { ((UIElement3D)target).RaiseEvent(dragEventArgs); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } // Raise the bubble DragEvent event if the preview DragEvent isn't handled. if (!dragEventArgs.Handled) { // Set the drop target events(Bubble). dragEventArgs.RoutedEvent = dragEvent; // Raise the drop target events(Bubble). if (target is UIElement) { ((UIElement)target).RaiseEvent(dragEventArgs); } else if (target is ContentElement) { ((ContentElement)target).RaiseEvent(dragEventArgs); } else if (target is UIElement3D) { ((UIElement3D)target).RaiseEvent(dragEventArgs); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } } // Call the default drop target event handling method internally if no one handle the drop target events. if (!dragEventArgs.Handled) { if (dragEvent == DragDrop.DragEnterEvent) { OnDefaultDragEnter(dragEventArgs); } else if (dragEvent == DragDrop.DragOverEvent) { OnDefaultDragOver(dragEventArgs); } } // Update DragDrop effects after raise DragEvent. effects = (int)dragEventArgs.Effects; } ////// Default drag enter during drag-and-drop operation. /// private void OnDefaultDragEnter(DragEventArgs e) { bool ctrlKeyDown; // If there's no supported data available, don't allow the drag-and-drop. if (e.Data == null) { e.Effects = DragDropEffects.None; return; } // Ok, there's data to move or copy here. if ((e.AllowedEffects & DragDropEffects.Move) != 0) { e.Effects = DragDropEffects.Move; } ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0); if (ctrlKeyDown) { e.Effects = DragDropEffects.Copy; } } ////// Default drag over during drag-and-drop operation. /// private void OnDefaultDragOver(DragEventArgs e) { bool ctrlKeyDown; // If there's no supported data available, don't allow the drag-and-drop. if (e.Data == null) { e.Effects = DragDropEffects.None; return; } // Ok, there's data to move or copy here. if ((e.AllowedEffects & DragDropEffects.Move) != 0) { e.Effects = DragDropEffects.Move; } ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0); if (ctrlKeyDown) { e.Effects = DragDropEffects.Copy; } } ////// Get the client point from the screen point. /// private NativeMethods.POINT GetClientPointFromScreenPoint(long dragPoint) { NativeMethods.POINT screenPoint; NativeMethods.POINT clientPoint; // Convert the screen point to the client window point screenPoint = new NativeMethods.POINT((int)(dragPoint & 0xffffffff), (int)((dragPoint >> 32) & 0xffffffff)); clientPoint = screenPoint; SafeNativeMethods.ScreenToClient(new HandleRef(this, _windowHandle), clientPoint); return clientPoint; } ////// Get the current target object and target point from the mouse dragging point /// that is the screen point. /// private DependencyObject GetCurrentTarget(long dragPoint, out Point targetPoint) { HwndSource source; DependencyObject target; NativeMethods.POINT clientPoint; // Initialize the target as null. target = null; // Get the client point from the screen point. clientPoint = GetClientPointFromScreenPoint(dragPoint); // Set the target point as the client point. targetPoint = new Point(clientPoint.x, clientPoint.y); // Get the source from the source to hit-test and translate point. source = HwndSource.FromHwnd(_windowHandle); if (source != null) { UIElement targetUIElement; // Hit-Testing to get the target object from the current mouse dragging point. // LocalHitTest() will get the hit-tested object from the mouse dragging point after // conversion the pixel to the measure unit. target = MouseDevice.LocalHitTest(targetPoint, source) as DependencyObject; targetUIElement = target as UIElement; if (targetUIElement != null) { if (targetUIElement.AllowDrop) { // Assign the target as the UIElement. target = targetUIElement; } else { target = null; } } else { ContentElement targetContentElement; targetContentElement = target as ContentElement; if (targetContentElement != null) { if (targetContentElement.AllowDrop) { // Assign the target as the ContentElement. target = targetContentElement; } else { target = null; } } else { UIElement3D targetUIElement3D; targetUIElement3D = target as UIElement3D; if (targetUIElement3D != null) { if (targetUIElement3D.AllowDrop) { target = targetUIElement3D; } else { target = null; } } } } if (target != null) { // Translate the client point to the root point and then translate it to target point. targetPoint = PointUtil.ClientToRoot(targetPoint, source); targetPoint = InputElement.TranslatePoint(targetPoint, source.RootVisual, target); } } return target; } ////// Get the data object. /// private IDataObject GetDataObject(object data) { IDataObject dataObject; dataObject = null; // We see if data is available on the data object. if (data != null) { if (data is DataObject) { dataObject = (DataObject)data; } else { dataObject = new DataObject((IComDataObject)data); } } return dataObject; } ////// Check the available data. /// private bool IsDataAvailable(IDataObject dataObject) { bool dataAvailable; dataAvailable = false; if (dataObject != null) { string[] formats; formats = dataObject.GetFormats(); for (int i = 0; i < formats.Length; i++) { if (dataObject.GetDataPresent(formats[i])) { dataAvailable = true; break; } } } return dataAvailable; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- #region Private Fields private IntPtr _windowHandle; private IDataObject _dataObject; private DependencyObject _lastTarget; #endregion Private Fields } #endregion OleDropTarget } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // File: DragDrop.cs // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: The DragDrop system is for drag-and-drop operation. // // See spec at http://avalon/uis/Data%20Transfer%20clipboard%20dragdrop/DragDrop%20design%20on%20WPP.mht // // History: // 07/10/2003 : sangilj Created // 08/19/2004 : sangilj Event name changes and code clean up // //--------------------------------------------------------------------------- using MS.Win32; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Security; using System.Security.Permissions; using MS.Internal; using MS.Internal.PresentationCore; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; namespace System.Windows { #region DragDrop ////// Provides drag-and-drop operation methods. /// public static class DragDrop { //----------------------------------------------------- // // DragDrop Event // //----------------------------------------------------- #region DragDrop Event ////// PreviewQueryContinueDrag /// public static readonly RoutedEvent PreviewQueryContinueDragEvent = EventManager.RegisterRoutedEvent("PreviewQueryContinueDrag", RoutingStrategy.Tunnel, typeof(QueryContinueDragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewQueryContinueDrag attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewQueryContinueDragHandler(DependencyObject element, QueryContinueDragEventHandler handler) { UIElement.AddHandler(element, PreviewQueryContinueDragEvent, handler); } ////// Removes a handler for the PreviewQueryContinueDrag attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewQueryContinueDragHandler(DependencyObject element, QueryContinueDragEventHandler handler) { UIElement.RemoveHandler(element, PreviewQueryContinueDragEvent, handler); } ////// QueryContinueDrag /// public static readonly RoutedEvent QueryContinueDragEvent = EventManager.RegisterRoutedEvent("QueryContinueDrag", RoutingStrategy.Bubble, typeof(QueryContinueDragEventHandler), typeof(DragDrop)); ////// Adds a handler for the QueryContinueDrag attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddQueryContinueDragHandler(DependencyObject element, QueryContinueDragEventHandler handler) { UIElement.AddHandler(element, QueryContinueDragEvent, handler); } ////// Removes a handler for the QueryContinueDrag attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveQueryContinueDragHandler(DependencyObject element, QueryContinueDragEventHandler handler) { UIElement.RemoveHandler(element, QueryContinueDragEvent, handler); } ////// PreviewGiveFeedback /// public static readonly RoutedEvent PreviewGiveFeedbackEvent = EventManager.RegisterRoutedEvent("PreviewGiveFeedback", RoutingStrategy.Tunnel, typeof(GiveFeedbackEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewGiveFeedback attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewGiveFeedbackHandler(DependencyObject element, GiveFeedbackEventHandler handler) { UIElement.AddHandler(element, PreviewGiveFeedbackEvent, handler); } ////// Removes a handler for the PreviewGiveFeedback attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewGiveFeedbackHandler(DependencyObject element, GiveFeedbackEventHandler handler) { UIElement.RemoveHandler(element, PreviewGiveFeedbackEvent, handler); } ////// GiveFeedback /// public static readonly RoutedEvent GiveFeedbackEvent = EventManager.RegisterRoutedEvent("GiveFeedback", RoutingStrategy.Bubble, typeof(GiveFeedbackEventHandler), typeof(DragDrop)); ////// Adds a handler for the GiveFeedback attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddGiveFeedbackHandler(DependencyObject element, GiveFeedbackEventHandler handler) { UIElement.AddHandler(element, GiveFeedbackEvent, handler); } ////// Removes a handler for the GiveFeedback attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveGiveFeedbackHandler(DependencyObject element, GiveFeedbackEventHandler handler) { UIElement.RemoveHandler(element, GiveFeedbackEvent, handler); } ////// PreviewDragEnter /// public static readonly RoutedEvent PreviewDragEnterEvent = EventManager.RegisterRoutedEvent("PreviewDragEnter", RoutingStrategy.Tunnel, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewDragEnter attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewDragEnterHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, PreviewDragEnterEvent, handler); } ////// Removes a handler for the PreviewDragEnter attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewDragEnterHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, PreviewDragEnterEvent, handler); } ////// DragEnter /// public static readonly RoutedEvent DragEnterEvent = EventManager.RegisterRoutedEvent("DragEnter", RoutingStrategy.Bubble, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the DragEnter attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddDragEnterHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, DragEnterEvent, handler); } ////// Removes a handler for the DragEnter attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveDragEnterHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, DragEnterEvent, handler); } ////// PreviewDragOver /// public static readonly RoutedEvent PreviewDragOverEvent = EventManager.RegisterRoutedEvent("PreviewDragOver", RoutingStrategy.Tunnel, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewDragOver attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewDragOverHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, PreviewDragOverEvent, handler); } ////// Removes a handler for the PreviewDragOver attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewDragOverHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, PreviewDragOverEvent, handler); } ////// DragOver /// public static readonly RoutedEvent DragOverEvent = EventManager.RegisterRoutedEvent("DragOver", RoutingStrategy.Bubble, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the DragOver attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddDragOverHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, DragOverEvent, handler); } ////// Removes a handler for the DragOver attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveDragOverHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, DragOverEvent, handler); } ////// PreviewDragLeave /// public static readonly RoutedEvent PreviewDragLeaveEvent = EventManager.RegisterRoutedEvent("PreviewDragLeave", RoutingStrategy.Tunnel, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewDragLeave attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewDragLeaveHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, PreviewDragLeaveEvent, handler); } ////// Removes a handler for the PreviewDragLeave attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewDragLeaveHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, PreviewDragLeaveEvent, handler); } ////// DragLeave /// public static readonly RoutedEvent DragLeaveEvent = EventManager.RegisterRoutedEvent("DragLeave", RoutingStrategy.Bubble, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the DragLeave attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddDragLeaveHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, DragLeaveEvent, handler); } ////// Removes a handler for the DragLeave attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveDragLeaveHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, DragLeaveEvent, handler); } ////// PreviewDrop /// public static readonly RoutedEvent PreviewDropEvent = EventManager.RegisterRoutedEvent("PreviewDrop", RoutingStrategy.Tunnel, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the PreviewDrop attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddPreviewDropHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, PreviewDropEvent, handler); } ////// Removes a handler for the PreviewDrop attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemovePreviewDropHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, PreviewDropEvent, handler); } ////// Drop /// public static readonly RoutedEvent DropEvent = EventManager.RegisterRoutedEvent("Drop", RoutingStrategy.Bubble, typeof(DragEventHandler), typeof(DragDrop)); ////// Adds a handler for the Drop attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddDropHandler(DependencyObject element, DragEventHandler handler) { UIElement.AddHandler(element, DropEvent, handler); } ////// Removes a handler for the Drop attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveDropHandler(DependencyObject element, DragEventHandler handler) { UIElement.RemoveHandler(element, DropEvent, handler); } #endregion DragDrop Event //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Begins a drag-and-drop operation. /// /// /// The drag source object. /// /// /// The data to drag. /// /// /// The allowed effects that is one of the DragDropEffects values. /// ////// Requires UnmanagedCode permission. /// If caller does not have this permission, the dragdrop will not occur. /// ////// Critical - calls critical code (OleDoDragDrop), but this is OK since we won't /// allow the initiate DragDrop operation without the unmanaged code permission. /// Demand the unmanaged code permission to block initiating DragDrop both /// intranet and internet zone. /// PublicOK - It's disabled in partial trust. /// [SecurityCritical] public static DragDropEffects DoDragDrop(DependencyObject dragSource, object data, DragDropEffects allowedEffects) { DataObject dataObject; // Demand the unmanaged code permission to initiate DragDrop operation. SecurityHelper.DemandUnmanagedCode(); if (dragSource == null) { throw new ArgumentNullException("dragSource"); } if (data == null) { throw new ArgumentNullException("data"); } dataObject = data as DataObject; if (dataObject == null) { // Create DataObject for DragDrop from the data. dataObject = new DataObject(data); } // Call OleDoDragDrop with DataObject. return OleDoDragDrop(dragSource, dataObject, allowedEffects); } #endregion Public Methods //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// Register the drop target which want to a droppable window. /// /// /// The window handle to be drop target . /// ////// Critical - calls critical code (OleRegisterDragDrop), and potentially deals with unmanged code.. /// /// TreatAsSafe - RegisterDropTarget check the unmanged code permission. /// Demmand the unmanaged code permission to block the register drop target /// both intranet and internet zone. /// [SecurityCritical, SecurityTreatAsSafe] internal static void RegisterDropTarget(IntPtr windowHandle) { if (SecurityHelper.CheckUnmanagedCodePermission() && windowHandle != IntPtr.Zero) { // Create OleDragSource and call Ole DoDragDrop for starting DragDrop. OleDropTarget oleDropTarget = new OleDropTarget(windowHandle); // Call OLE RegisterDragDrop and it will get the drop target events during drag-and-drop // operation on the drop target window. OleServicesContext.CurrentOleServicesContext.OleRegisterDragDrop( new HandleRef(null, windowHandle), (UnsafeNativeMethods.IOleDropTarget)oleDropTarget); } } ////// Revoke the drop target which was a droppable window. /// /// /// The window handle that can accept drop. /// ////// Critical - calls critical code (OleRevokeDragDrop).We do not want this called excessively /// TreatAsSafe - RevokeDropTarget check the unmanged code permission. /// Demmand the unmanaged code permission to block the revoke drop target /// both intranet and internet zone. /// [SecurityCritical, SecurityTreatAsSafe] internal static void RevokeDropTarget(IntPtr windowHandle) { if (SecurityHelper.CheckUnmanagedCodePermission() && windowHandle != IntPtr.Zero) { // Call OLE RevokeDragDrop to revoke the droppable target window. OleServicesContext.CurrentOleServicesContext.OleRevokeDragDrop( new HandleRef(null, windowHandle)); } } ////// Validate the dragdrop effects of DragDrop. /// internal static bool IsValidDragDropEffects(DragDropEffects dragDropEffects) { int dragDropEffectsAll; dragDropEffectsAll = (int)(DragDropEffects.None | DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link | DragDropEffects.Scroll | DragDropEffects.All); if (((int)dragDropEffects & ~dragDropEffectsAll) != 0) { return false; } return true; } ////// Validate the drag action of DragDrop. /// internal static bool IsValidDragAction(DragAction dragAction) { if (dragAction == DragAction.Continue || dragAction == DragAction.Drop || dragAction == DragAction.Cancel) { return true; } else { return false; } } ////// Validate the key states of DragDrop. /// internal static bool IsValidDragDropKeyStates(DragDropKeyStates dragDropKeyStates) { int keyStatesAll; keyStatesAll = (int)(DragDropKeyStates.LeftMouseButton | DragDropKeyStates.RightMouseButton | DragDropKeyStates.ShiftKey | DragDropKeyStates.ControlKey | DragDropKeyStates.MiddleMouseButton | DragDropKeyStates.AltKey); if (((int)dragDropKeyStates & ~keyStatesAll) != 0) { return false; } return true; } #endregion Internal Methods //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods ////// Begins a drag-and-drop operation through OLE DoDragDrop. /// /// /// The drag source object. /// /// /// The data object to drag. /// /// /// The allowed effects that is one of the DragDropEffects values. /// private static DragDropEffects OleDoDragDrop(DependencyObject dragSource, DataObject dataObject, DragDropEffects allowedEffects) { int[] dwEffect; OleDragSource oleDragSource; Debug.Assert(dragSource != null, "Invalid dragSource"); Debug.Assert(dataObject != null, "Invalid dataObject"); // Create the int array for passing parameter of OLE DoDragDrop dwEffect = new int[1]; // Create OleDragSource and call Ole DoDragDrop for starting DragDrop. oleDragSource = new OleDragSource(dragSource); // Call OLE DoDragDrop and it will hanlde all mouse and keyboard input until drop the object. // We don't need to check the error return since PreserveSig attribute is defined as "false" // which will pops up the exception automatically. OleServicesContext.CurrentOleServicesContext.OleDoDragDrop( (IComDataObject)dataObject, (UnsafeNativeMethods.IOleDropSource)oleDragSource, (int)allowedEffects, dwEffect); // return the drop effect of DragDrop. return (DragDropEffects)dwEffect[0]; } #endregion Private Methods } #endregion DragDrop #region OleDragSource ////// OleDragSource that handle ole QueryContinueDrag and GiveFeedback. /// internal class OleDragSource : UnsafeNativeMethods.IOleDropSource { //----------------------------------------------------- // // Constructor // //----------------------------------------------------- #region Constructor ////// OleDragSource constructor. /// public OleDragSource(DependencyObject dragSource) { _dragSource = dragSource; } #endregion Constructor //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region IOleDropSource ////// Query the source to know the drag continue or not. /// int UnsafeNativeMethods.IOleDropSource.OleQueryContinueDrag(int escapeKey, int grfkeyState) { bool escapePressed; QueryContinueDragEventArgs args; escapePressed = false; if (escapeKey != 0) { escapePressed = true; } // Create QueryContinueDrag event arguments. args = new QueryContinueDragEventArgs(escapePressed, (DragDropKeyStates)grfkeyState); // Raise the query continue drag event for both Tunnel(Preview) and Bubble. RaiseQueryContinueDragEvent(args); // Check the drag continue result. if (args.Action == DragAction.Continue) { return NativeMethods.S_OK; } else if (args.Action == DragAction.Drop) { return NativeMethods.DRAGDROP_S_DROP; } else if (args.Action == DragAction.Cancel) { return NativeMethods.DRAGDROP_S_CANCEL; } return NativeMethods.S_OK; } ////// Give feedback from the source whether use the default cursor or not. /// int UnsafeNativeMethods.IOleDropSource.OleGiveFeedback(int effect) { GiveFeedbackEventArgs args; // Create GiveFeedback event arguments. args = new GiveFeedbackEventArgs((DragDropEffects)effect, /*UseDefaultCursors*/ false); // Raise the give feedback event for both Tunnel(Preview) and Bubble. RaiseGiveFeedbackEvent(args); // Check the give feedback result whether use default cursors or not. if (args.UseDefaultCursors) { return NativeMethods.DRAGDROP_S_USEDEFAULTCURSORS; } return NativeMethods.S_OK; } ////// Raise QueryContinueDrag event for Tunel and Bubble. /// private void RaiseQueryContinueDragEvent(QueryContinueDragEventArgs args) { // Set PreviewQueryContinueDrag(Tunnel) first. args.RoutedEvent=DragDrop.PreviewQueryContinueDragEvent; // Raise the preview QueryContinueDrag event(Tunnel). if (_dragSource is UIElement) { ((UIElement)_dragSource).RaiseEvent(args); } else if (_dragSource is ContentElement) { ((ContentElement)_dragSource).RaiseEvent(args); } else if (_dragSource is UIElement3D) { ((UIElement3D)_dragSource).RaiseEvent(args); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } // Set QueryContinueDrag(Bubble). args.RoutedEvent = DragDrop.QueryContinueDragEvent; // Raise QueryContinueDrag event(Bubble). if (!args.Handled) { if (_dragSource is UIElement) { ((UIElement)_dragSource).RaiseEvent(args); } else if (_dragSource is ContentElement) { ((ContentElement)_dragSource).RaiseEvent(args); } else if (_dragSource is UIElement3D) { ((UIElement3D)_dragSource).RaiseEvent(args); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } } // Call the default event handling method internally if no one handle the drag source events. if (!args.Handled) { OnDefaultQueryContinueDrag(args); } } ////// Raise GiveFeedback event for Tunnel and Bubble. /// private void RaiseGiveFeedbackEvent(GiveFeedbackEventArgs args) { // Set PreviewGiveFeedback(Tunnel) first. args.RoutedEvent=DragDrop.PreviewGiveFeedbackEvent; // Raise the preview GiveFeedback(Tunnel). if (_dragSource is UIElement) { ((UIElement)_dragSource).RaiseEvent(args); } else if (_dragSource is ContentElement) { ((ContentElement)_dragSource).RaiseEvent(args); } else if (_dragSource is UIElement3D) { ((UIElement3D)_dragSource).RaiseEvent(args); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } // Set GiveFeedback event ID(Bubble). args.RoutedEvent = DragDrop.GiveFeedbackEvent; if (!args.Handled) { // Raise GiveFeedback event(Bubble). if (_dragSource is UIElement) { ((UIElement)_dragSource).RaiseEvent(args); } else if (_dragSource is ContentElement) { ((ContentElement)_dragSource).RaiseEvent(args); } else if (_dragSource is UIElement3D) { ((UIElement3D)_dragSource).RaiseEvent(args); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } } // Call the default event handling method internally if no one handle the drag source events. if (!args.Handled) { OnDefaultGiveFeedback(args); } } ////// Default query continue drag during drag-and-drop operation. /// private void OnDefaultQueryContinueDrag(QueryContinueDragEventArgs e) { bool mouseUp; mouseUp = false; e.Action = DragAction.Continue; mouseUp = (((int)e.KeyStates & (int)DragDropKeyStates.LeftMouseButton) == 0); if (e.EscapePressed) { e.Action = DragAction.Cancel; } else if (mouseUp) { e.Action = DragAction.Drop; } } ////// Default give feedback during drag-and-drop operation. /// private void OnDefaultGiveFeedback(GiveFeedbackEventArgs e) { // Show the default DragDrop cursor. e.UseDefaultCursors = true; } #endregion IOleDropSource //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields private DependencyObject _dragSource; #endregion Private Fields } #endregion OleDragSource #region OleDropTarget ////// OleDropTarget that handle ole DragEnter DragOver DragLeave and DragDrop. /// internal class OleDropTarget : DispatcherObject, UnsafeNativeMethods.IOleDropTarget { //------------------------------------------------------ // // Constructor // //----------------------------------------------------- #region Constructor ////// OleDropTarget Constructor. /// public OleDropTarget(IntPtr handle) { if (handle == IntPtr.Zero) { throw new ArgumentNullException("handle"); } _windowHandle = handle; } #endregion Constructor //------------------------------------------------------ // // IOleDropTarget Interface // //----------------------------------------------------- #region IOleDropTarget ////// OleDragEnter - check the data object and notify DragEnter to the target element. /// int UnsafeNativeMethods.IOleDropTarget.OleDragEnter(object data, int dragDropKeyStates, long point, ref int effects) { DependencyObject target; Point targetPoint; // Get the data object and immediately return if there isn't the data object or no available data. _dataObject = GetDataObject(data); if (_dataObject == null || !IsDataAvailable(_dataObject)) { // Set the none effect. effects = (int)DragDropEffects.None; return NativeMethods.S_FALSE; } // Get the current target from the mouse drag point that is based on screen. target = GetCurrentTarget(point, out targetPoint); // Set the last target element with the current target. _lastTarget = target; if (target != null) { // Create DragEvent agrument and then raise DragEnter event for Tunnel or Buuble event. RaiseDragEvent( DragDrop.DragEnterEvent, dragDropKeyStates, ref effects, target, targetPoint); } else { // Set the none effect. effects = (int)DragDropEffects.None; } return NativeMethods.S_OK; } ////// OleDragOver - get the drop effect from the target element. /// int UnsafeNativeMethods.IOleDropTarget.OleDragOver(int dragDropKeyStates, long point, ref int effects) { DependencyObject target; Point targetPoint; Invariant.Assert(_dataObject != null); // Get the current target from the mouse drag point that is based on screen. target = GetCurrentTarget(point, out targetPoint); // Raise DragOver event to the target to get DragDrop effect status from the target. if (target != null) { // Avalon apps can have only one window handle, so we need to generate DragLeave and // DragEnter event to target when target is changed by the mouse dragging. // If the current target is the same as the last target, just raise DragOver event to the target. if (target != _lastTarget) { try { if (_lastTarget != null) { // Raise DragLeave event to the last target. RaiseDragEvent( DragDrop.DragLeaveEvent, dragDropKeyStates, ref effects, _lastTarget, targetPoint); } // Raise DragEnter event to the new target. RaiseDragEvent( DragDrop.DragEnterEvent, dragDropKeyStates, ref effects, target, targetPoint); } finally { // Reset the last target element to check it with the next current element. _lastTarget = target; } } else { // Raise DragOver event to the target. RaiseDragEvent( DragDrop.DragOverEvent, dragDropKeyStates, ref effects, target, targetPoint); } } else { try { if (_lastTarget != null) { // Raise DragLeave event to the last target. RaiseDragEvent( DragDrop.DragLeaveEvent, dragDropKeyStates, ref effects, _lastTarget, targetPoint); } } finally { // Update the last target element as the current target element. _lastTarget = target; effects = (int)DragDropEffects.None; } } return NativeMethods.S_OK; } ////// OleDragLeave. /// int UnsafeNativeMethods.IOleDropTarget.OleDragLeave() { if (_lastTarget != null) { int effects; // Set DragDrop effects as DragDropEffects.None effects = 0; try { // Raise DragLeave event for the last target element. RaiseDragEvent( DragDrop.DragLeaveEvent, /* DragDropKeyStates.None */ 0, ref effects, _lastTarget, new Point(0, 0)); } finally { // Reset the last target and data object. _lastTarget = null; _dataObject = null; } } return NativeMethods.S_OK; } ////// OleDrop - drop the object to the target element. /// int UnsafeNativeMethods.IOleDropTarget.OleDrop(object data, int dragDropKeyStates, long point, ref int effects) { IDataObject dataObject; DependencyObject target; Point targetPoint; // Get the data object and then immediately return fail if there isn't the proper data. dataObject = GetDataObject(data); if (dataObject == null || !IsDataAvailable(dataObject)) { effects = (int)DragDropEffects.None; return NativeMethods.S_FALSE; } // Reset last element and target point. _lastTarget = null; // Get the current target from the screen mouse point. target = GetCurrentTarget(point, out targetPoint); // Raise Drop event to the target element. if (target != null) { // Raise Drop event to the drop target. RaiseDragEvent( DragDrop.DropEvent, dragDropKeyStates, ref effects, target, targetPoint); } else { effects = (int)DragDropEffects.None; } return NativeMethods.S_OK; } #endregion IOleDropTarget #region Private Methods ////// Raise Drag(Enter/Over/Leave/Drop) events to the taret. /// private void RaiseDragEvent(RoutedEvent dragEvent, int dragDropKeyStates, ref int effects, DependencyObject target, Point targetPoint) { DragEventArgs dragEventArgs; Invariant.Assert(_dataObject != null); Invariant.Assert(target != null); // Create DragEvent argement to raise DragEnter events to the target. dragEventArgs = new DragEventArgs( _dataObject, (DragDropKeyStates)dragDropKeyStates, (DragDropEffects)effects, target, targetPoint); // Set the preview(Tunnel) drop target events(Tunnel) first. if (dragEvent == DragDrop.DragEnterEvent) { dragEventArgs.RoutedEvent = DragDrop.PreviewDragEnterEvent; } else if (dragEvent == DragDrop.DragOverEvent) { dragEventArgs.RoutedEvent = DragDrop.PreviewDragOverEvent; } else if (dragEvent == DragDrop.DragLeaveEvent) { dragEventArgs.RoutedEvent = DragDrop.PreviewDragLeaveEvent; } else if (dragEvent == DragDrop.DropEvent) { dragEventArgs.RoutedEvent = DragDrop.PreviewDropEvent; } // Raise the preview drop target events(Tunnel). if (target is UIElement) { ((UIElement)target).RaiseEvent(dragEventArgs); } else if (target is ContentElement) { ((ContentElement)target).RaiseEvent(dragEventArgs); } else if (target is UIElement3D) { ((UIElement3D)target).RaiseEvent(dragEventArgs); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } // Raise the bubble DragEvent event if the preview DragEvent isn't handled. if (!dragEventArgs.Handled) { // Set the drop target events(Bubble). dragEventArgs.RoutedEvent = dragEvent; // Raise the drop target events(Bubble). if (target is UIElement) { ((UIElement)target).RaiseEvent(dragEventArgs); } else if (target is ContentElement) { ((ContentElement)target).RaiseEvent(dragEventArgs); } else if (target is UIElement3D) { ((UIElement3D)target).RaiseEvent(dragEventArgs); } else { throw new ArgumentException(SR.Get(SRID.ScopeMustBeUIElementOrContent), "scope"); } } // Call the default drop target event handling method internally if no one handle the drop target events. if (!dragEventArgs.Handled) { if (dragEvent == DragDrop.DragEnterEvent) { OnDefaultDragEnter(dragEventArgs); } else if (dragEvent == DragDrop.DragOverEvent) { OnDefaultDragOver(dragEventArgs); } } // Update DragDrop effects after raise DragEvent. effects = (int)dragEventArgs.Effects; } ////// Default drag enter during drag-and-drop operation. /// private void OnDefaultDragEnter(DragEventArgs e) { bool ctrlKeyDown; // If there's no supported data available, don't allow the drag-and-drop. if (e.Data == null) { e.Effects = DragDropEffects.None; return; } // Ok, there's data to move or copy here. if ((e.AllowedEffects & DragDropEffects.Move) != 0) { e.Effects = DragDropEffects.Move; } ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0); if (ctrlKeyDown) { e.Effects = DragDropEffects.Copy; } } ////// Default drag over during drag-and-drop operation. /// private void OnDefaultDragOver(DragEventArgs e) { bool ctrlKeyDown; // If there's no supported data available, don't allow the drag-and-drop. if (e.Data == null) { e.Effects = DragDropEffects.None; return; } // Ok, there's data to move or copy here. if ((e.AllowedEffects & DragDropEffects.Move) != 0) { e.Effects = DragDropEffects.Move; } ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0); if (ctrlKeyDown) { e.Effects = DragDropEffects.Copy; } } ////// Get the client point from the screen point. /// private NativeMethods.POINT GetClientPointFromScreenPoint(long dragPoint) { NativeMethods.POINT screenPoint; NativeMethods.POINT clientPoint; // Convert the screen point to the client window point screenPoint = new NativeMethods.POINT((int)(dragPoint & 0xffffffff), (int)((dragPoint >> 32) & 0xffffffff)); clientPoint = screenPoint; SafeNativeMethods.ScreenToClient(new HandleRef(this, _windowHandle), clientPoint); return clientPoint; } ////// Get the current target object and target point from the mouse dragging point /// that is the screen point. /// private DependencyObject GetCurrentTarget(long dragPoint, out Point targetPoint) { HwndSource source; DependencyObject target; NativeMethods.POINT clientPoint; // Initialize the target as null. target = null; // Get the client point from the screen point. clientPoint = GetClientPointFromScreenPoint(dragPoint); // Set the target point as the client point. targetPoint = new Point(clientPoint.x, clientPoint.y); // Get the source from the source to hit-test and translate point. source = HwndSource.FromHwnd(_windowHandle); if (source != null) { UIElement targetUIElement; // Hit-Testing to get the target object from the current mouse dragging point. // LocalHitTest() will get the hit-tested object from the mouse dragging point after // conversion the pixel to the measure unit. target = MouseDevice.LocalHitTest(targetPoint, source) as DependencyObject; targetUIElement = target as UIElement; if (targetUIElement != null) { if (targetUIElement.AllowDrop) { // Assign the target as the UIElement. target = targetUIElement; } else { target = null; } } else { ContentElement targetContentElement; targetContentElement = target as ContentElement; if (targetContentElement != null) { if (targetContentElement.AllowDrop) { // Assign the target as the ContentElement. target = targetContentElement; } else { target = null; } } else { UIElement3D targetUIElement3D; targetUIElement3D = target as UIElement3D; if (targetUIElement3D != null) { if (targetUIElement3D.AllowDrop) { target = targetUIElement3D; } else { target = null; } } } } if (target != null) { // Translate the client point to the root point and then translate it to target point. targetPoint = PointUtil.ClientToRoot(targetPoint, source); targetPoint = InputElement.TranslatePoint(targetPoint, source.RootVisual, target); } } return target; } ////// Get the data object. /// private IDataObject GetDataObject(object data) { IDataObject dataObject; dataObject = null; // We see if data is available on the data object. if (data != null) { if (data is DataObject) { dataObject = (DataObject)data; } else { dataObject = new DataObject((IComDataObject)data); } } return dataObject; } ////// Check the available data. /// private bool IsDataAvailable(IDataObject dataObject) { bool dataAvailable; dataAvailable = false; if (dataObject != null) { string[] formats; formats = dataObject.GetFormats(); for (int i = 0; i < formats.Length; i++) { if (dataObject.GetDataPresent(formats[i])) { dataAvailable = true; break; } } } return dataAvailable; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //----------------------------------------------------- #region Private Fields private IntPtr _windowHandle; private IDataObject _dataObject; private DependencyObject _lastTarget; #endregion Private Fields } #endregion OleDropTarget } // 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
- PageStatePersister.cs
- UpdateTracker.cs
- CompiledELinqQueryState.cs
- ISessionStateStore.cs
- ResXResourceWriter.cs
- XmlReaderSettings.cs
- WebPartManagerInternals.cs
- JsonQNameDataContract.cs
- DetailsViewDeleteEventArgs.cs
- SubpageParagraph.cs
- Ref.cs
- SweepDirectionValidation.cs
- ViewBase.cs
- QueuePathEditor.cs
- CodeExpressionStatement.cs
- VideoDrawing.cs
- GridViewCancelEditEventArgs.cs
- EditorAttribute.cs
- ProtectedConfiguration.cs
- BrowsableAttribute.cs
- PointF.cs
- LicenseManager.cs
- PatternMatcher.cs
- AccessDataSourceView.cs
- BuildManager.cs
- NumericExpr.cs
- DataGridCellsPanel.cs
- FileAuthorizationModule.cs
- WithParamAction.cs
- XmlAttributeCollection.cs
- CollectionDataContractAttribute.cs
- ElementAction.cs
- GuidConverter.cs
- UITypeEditor.cs
- XmlILCommand.cs
- DeferredSelectedIndexReference.cs
- XPathPatternParser.cs
- QilGeneratorEnv.cs
- WindowsListView.cs
- UInt16Storage.cs
- GetWinFXPath.cs
- DesignerResources.cs
- PrivateFontCollection.cs
- CompiledScopeCriteria.cs
- NodeLabelEditEvent.cs
- CodeVariableDeclarationStatement.cs
- Memoizer.cs
- Point3DCollection.cs
- GridViewCancelEditEventArgs.cs
- localization.cs
- ProviderUtil.cs
- TransactionScope.cs
- SingleStorage.cs
- PopupControlService.cs
- controlskin.cs
- ConfigurationValidatorAttribute.cs
- XamlHostingSection.cs
- xmlglyphRunInfo.cs
- DoubleCollectionValueSerializer.cs
- SqlCommandBuilder.cs
- HtmlInputRadioButton.cs
- SelectionItemProviderWrapper.cs
- PropertyTab.cs
- DataGridLengthConverter.cs
- BaseCodeDomTreeGenerator.cs
- DataControlLinkButton.cs
- XmlDictionaryWriter.cs
- VisualStyleElement.cs
- XmlSchemaComplexContentExtension.cs
- WorkflowControlClient.cs
- TemplateBamlRecordReader.cs
- SelectionWordBreaker.cs
- IssuedTokenParametersEndpointAddressElement.cs
- ParseChildrenAsPropertiesAttribute.cs
- TableLayoutPanel.cs
- TypeConverterHelper.cs
- TextTabProperties.cs
- RelatedView.cs
- ListViewTableRow.cs
- NativeMethods.cs
- HttpCookieCollection.cs
- TypeConverterHelper.cs
- UserPreferenceChangedEventArgs.cs
- ContactManager.cs
- WindowsTitleBar.cs
- CollectionViewGroup.cs
- ClassHandlersStore.cs
- OleTxTransactionInfo.cs
- DbConnectionOptions.cs
- CryptoConfig.cs
- SelectionRange.cs
- WebException.cs
- AuthenticationConfig.cs
- TextProviderWrapper.cs
- mongolianshape.cs
- HorizontalAlignConverter.cs
- AuthorizationSection.cs
- InOutArgumentConverter.cs
- ByteConverter.cs
- MemberMaps.cs