DragDrop.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / DragDrop.cs / 2 / 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 [....]/uis/Data%20Transfer%20clipboard%20dragdrop/DragDrop%20design%20on%20WPP.mht
// 
// History:
//  07/10/2003 : [....]    Created
//  08/19/2004 : [....]    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

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