diff Chronosv2/source/DragAndDrop/DragHelper.cs @ 10:443821e55f06

Initial cleaned up add from Codeplex files
author stevenh7776 stevenhollidge@hotmail.com
date Tue, 21 Feb 2012 17:25:44 +0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Chronosv2/source/DragAndDrop/DragHelper.cs	Tue Feb 21 17:25:44 2012 +0700
@@ -0,0 +1,465 @@
+using System;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Interop;
+using System.Windows.Media;
+using System.Windows.Shapes;
+using Chronos.Interop;
+
+namespace Chronos.Presentation.DragAndDrop
+{
+    public sealed class DragHelper
+    {
+        #region · Static Methods ·
+
+        private static UIElement GetDragElementOnHitTest(UIElement src, MouseEventArgs args)
+        {
+            HitTestResult hr = VisualTreeHelper.HitTest(src, args.GetPosition((IInputElement)src));
+            return hr.VisualHit as UIElement;
+        }
+
+        #endregion
+
+        #region · Fields ·
+
+        private UIElement               dragSource;
+        private UIElement               dragScope;
+        private IDataDropObjectProvider callback;
+        private Point                   startPoint;
+        private DragAdorner             adorner;
+        private AdornerLayer            layer;
+        private Window                  dragdropWindow;
+        private DragDropEffects         allowedEffects;
+        private bool                    mouseLeftScope;
+        private bool                    isDragging;
+        private double                  opacity;        
+
+        #endregion
+
+        #region · Properties ·
+
+        public double Opacity
+        {
+            get { return this.opacity; }
+        }
+
+        public DragDropEffects AllowedEffects
+        {
+            get { return this.allowedEffects; }
+            set { this.allowedEffects = value; }
+        }
+
+        #endregion
+
+        #region · Private Properties ·
+
+        private UIElement DragSource
+        {
+            get { return this.dragSource; }
+            set
+            {
+                this.dragSource = value;
+                this.WireEvents(value);
+            }
+        }
+
+        private UIElement DragScope
+        {
+            get { return this.dragScope; }
+            set { this.dragScope = value; }
+        }
+
+        private IDataDropObjectProvider Callback
+        {
+            get { return this.callback; }
+            set { this.callback = value; }
+        }
+
+        private bool IsDragging
+        {
+            get { return this.isDragging; }
+            set { this.isDragging = value; }
+        }
+
+        private bool AllowsLink
+        {
+            get { return ((this.AllowedEffects & DragDropEffects.Link) != 0); }
+        }
+
+        private bool AllowsMove
+        {
+            get { return ((this.AllowedEffects & DragDropEffects.Move) != 0); }
+        }
+
+        private bool AllowsCopy
+        {
+            get { return ((this.AllowedEffects & DragDropEffects.Copy) != 0); }
+        }
+
+        #endregion
+
+        #region · Constructors ·
+
+        public DragHelper(UIElement dragSource, IDataDropObjectProvider callback, UIElement dragScope)
+        {
+            this.allowedEffects = DragDropEffects.Copy | DragDropEffects.Move;
+            this.opacity        = 0.7;
+            this.DragSource     = dragSource;
+            this.Callback       = callback;
+            this.DragScope      = dragScope;
+        }
+
+        #endregion
+
+        #region · DragSource Event Handlers ·
+
+        private void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+        {
+            this.startPoint = e.GetPosition(DragScope);
+        }
+
+#if DEBUG
+        void DragSource_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
+        {
+            System.Diagnostics.Debug.Assert(IsDragging == false);
+        }
+#endif
+
+        private void DragSource_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
+        {
+            if (e.LeftButton == MouseButtonState.Pressed && !this.IsDragging)
+            {
+                Point position = e.GetPosition((IInputElement)DragScope);
+
+                if (Math.Abs(position.X - startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
+                    Math.Abs(position.Y - startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
+                {
+                    this.StartDrag(e);
+                }
+            }
+        }
+
+        #endregion
+
+        #region · DragScope Event Handlers ·
+
+        private void DragScope_DragLeave(object sender, DragEventArgs args)
+        {
+            if (args.OriginalSource == this.DragScope)
+            {
+                this.mouseLeftScope = true;
+            }
+        }
+
+        private void DragScope_DragOver(object sender, DragEventArgs args)
+        {
+            if (this.adorner != null)
+            {
+                this.adorner.LeftOffset = args.GetPosition(this.DragScope).X; /* - _startPoint.X */
+                this.adorner.TopOffset  = args.GetPosition(this.DragScope).Y; /* - _startPoint.Y */
+            }
+        }
+
+        #endregion
+
+        #region · Event Wiring ·
+
+        private void WireEvents(UIElement uie)
+        {
+            Debug.Assert(uie != null);
+
+            if (uie != null)
+            {
+                uie.PreviewMouseLeftButtonDown  += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
+                uie.PreviewMouseMove            += new MouseEventHandler(DragSource_PreviewMouseMove);
+
+#if DEBUG
+                uie.PreviewMouseLeftButtonUp    += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonUp);
+#endif
+            }
+        }
+
+        #endregion
+
+        #region · Private Methods ·
+
+        private void StartDrag(MouseEventArgs args)
+        {
+            IDataObject data        = null;
+            UIElement   dragelement = null;
+
+            // ADD THE DATA 
+            if (this.Callback != null)
+            {
+                DragDataWrapper dw = new DragDataWrapper();
+
+                data = new DataObject(typeof(DragDataWrapper).ToString(), dw);
+
+                if ((this.Callback.SupportedActions & DragDropProviderActions.MultiFormatData) != 0)
+                {
+                    this.Callback.AppendData(ref data, args);
+                }
+
+                if ((this.Callback.SupportedActions & DragDropProviderActions.Data) != 0) 
+                {
+                    dw.Data = this.Callback.GetData();
+                }
+
+                if ((this.Callback.SupportedActions & DragDropProviderActions.Visual) != 0)
+                {
+                    dragelement = this.Callback.GetVisual(args);
+                }
+                else
+                {
+                    dragelement = args.OriginalSource as UIElement;
+                }
+
+                dw.Source   = this.DragSource;
+                dw.Shim     = this.Callback;
+
+                Debug.Assert(this.DragScope == null, "The DragDataWrapper is meant for in-proc...  Sorry for asserting, just wanted to confirm.. comment out assertion if needed"); 
+            }
+            else
+            {
+                dragelement = args.OriginalSource as UIElement;
+                data        = new DataObject(typeof(UIElement).ToString(), dragelement);                 
+            }
+
+            if (dragelement == null || data == null || dragelement == this.DragSource)
+            {
+                return;
+            }         
+
+            DragEventHandler                dragOver        = null;
+            DragEventHandler                dragLeave       = null;
+            QueryContinueDragEventHandler   queryContinue   = null;
+            GiveFeedbackEventHandler        giveFeedback    = null;
+            DragDropEffects                 effects         = this.GetDragDropEffects();
+            DragDropEffects                 resultEffects;
+
+            // Inprocess Drag  ...
+            if (this.DragScope != null)
+            {
+                bool previousAllowDrop = this.DragScope.AllowDrop;
+
+                this.adorner    = new DragAdorner(this.DragScope, (UIElement)dragelement, true, this.Opacity);
+                this.layer      = AdornerLayer.GetAdornerLayer(this.DragScope as Visual);
+
+                this.layer.Add(this.adorner);
+
+                if (this.DragScope != this.DragSource)
+                {
+                    this.DragScope.AllowDrop = true;
+
+                    DragDrop.AddPreviewDragOverHandler((DependencyObject)this.DragScope, dragOver = new DragEventHandler(DragScope_DragOver));
+                    DragDrop.AddPreviewDragLeaveHandler(this.DragScope, dragLeave = new DragEventHandler(DragScope_DragLeave));
+                    DragDrop.AddPreviewQueryContinueDragHandler(this.DragSource, queryContinue = new QueryContinueDragEventHandler(OnQueryContinueDrag));
+                }
+
+                try
+                {
+                    this.IsDragging     = true;
+                    this.mouseLeftScope = false;                    
+                    resultEffects       = DragDrop.DoDragDrop(this.DragSource, data, effects);
+
+                    this.DragFinished(resultEffects);
+                }
+                catch
+                {
+                    Debug.Assert(false);
+                }
+
+                if (this.DragScope != this.DragSource)
+                {
+                    this.DragScope.AllowDrop = previousAllowDrop;
+
+                    DragDrop.RemovePreviewDragOverHandler(this.DragScope, dragOver);
+                    DragDrop.RemovePreviewDragLeaveHandler(this.DragScope, dragLeave);
+                    DragDrop.RemovePreviewQueryContinueDragHandler(this.DragSource, queryContinue); 
+                }
+            }
+            else  
+            {
+                DragDrop.AddPreviewQueryContinueDragHandler(this.DragSource, queryContinue = new QueryContinueDragEventHandler(OnQueryContinueDrag));
+                DragDrop.AddGiveFeedbackHandler(this.DragSource, giveFeedback = new GiveFeedbackEventHandler(OnGiveFeedback));
+
+                this.IsDragging = true;
+
+                if ((this.Callback.SupportedActions & DragDropProviderActions.Visual) != 0)
+                {
+                    this.CreateDragDropWindow(dragelement);
+                    this.dragdropWindow.Show();
+                }
+
+                try
+                {
+                    resultEffects = DragDrop.DoDragDrop(this.DragSource, data, effects);
+                }
+                finally 
+                { 
+                }
+
+                if ((this.Callback.SupportedActions & DragDropProviderActions.Visual) != 0)
+                {
+                    this.DestroyDragDropWindow();
+                }
+
+                DragDrop.RemovePreviewQueryContinueDragHandler(this.DragSource, OnQueryContinueDrag);
+                DragDrop.AddGiveFeedbackHandler(this.DragSource, OnGiveFeedback);
+                
+                this.IsDragging = false;
+                this.DragFinished(resultEffects);
+            }
+        }
+
+        private DragDropEffects GetDragDropEffects()
+        {
+            DragDropEffects effects = DragDropEffects.None;
+
+            bool ctrl   = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
+            bool shift  = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
+
+            if (ctrl && shift && this.AllowsLink)
+            {
+                effects |= DragDropEffects.Link;
+            }
+            else if (ctrl && this.AllowsCopy)
+            {
+                effects |= DragDropEffects.Copy;
+            }
+            else if (this.AllowsMove)
+            {
+                effects |= DragDropEffects.Move;
+            }
+
+            return effects;
+        }     
+     
+        private void OnGiveFeedback(object sender, GiveFeedbackEventArgs args)
+        {
+            args.UseDefaultCursors  = ((this.Callback.SupportedActions & DragDropProviderActions.Visual) == 0);
+            args.Handled            = true;
+        }       
+
+        private void OnQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
+        {
+#if DEBUG
+            if (this.DragScope != null)
+            {
+                Point pd = Mouse.GetPosition(this.DragScope);
+            }
+#endif
+            if (this.DragScope == null)
+            {
+                this.UpdateWindowLocation();
+            }
+            else
+            {
+                Point p = Mouse.GetPosition(this.DragScope);
+
+                if (this.adorner != null)
+                {
+                    this.adorner.LeftOffset    = p.X /* - _startPoint.X */ ;
+                    this.adorner.TopOffset     = p.Y /* - _startPoint.Y */ ;
+                }
+
+                if (this.mouseLeftScope)
+                {
+                    e.Action = DragAction.Cancel;
+                    e.Handled = true; 
+                } 
+            }       
+        }
+
+        private void DestroyDragDropWindow()
+        {
+            if (this.dragdropWindow != null)
+            {
+                this.dragdropWindow.Close();
+                this.dragdropWindow = null;
+            }
+        }
+
+        private void CreateDragDropWindow(Visual dragElement)
+        {
+            Debug.Assert(this.dragdropWindow == null);
+
+            this.dragdropWindow = new Window();
+
+            this.dragdropWindow.WindowStyle        = WindowStyle.None;
+            this.dragdropWindow.AllowsTransparency = true;
+            this.dragdropWindow.AllowDrop          = false;
+            this.dragdropWindow.Background         = null;
+            this.dragdropWindow.IsHitTestVisible   = false;
+            this.dragdropWindow.SizeToContent      = SizeToContent.WidthAndHeight;
+            this.dragdropWindow.Topmost            = true;
+            this.dragdropWindow.ShowInTaskbar      = false;
+
+            this.dragdropWindow.SourceInitialized += new EventHandler(
+                delegate(object sender, EventArgs args)
+                {
+                    //TODO assert that we can do this.. 
+                    PresentationSource  windowSource    = PresentationSource.FromVisual(this.dragdropWindow);
+                    IntPtr              handle          = ((HwndSource)windowSource).Handle;
+
+                    Int32 styles = Win32Interop.GetWindowLong(handle, Win32Interop.GWL_EXSTYLE);
+
+                    Win32Interop.SetWindowLong(handle, Win32Interop.GWL_EXSTYLE, styles | Win32Interop.WS_EX_LAYERED | Win32Interop.WS_EX_TRANSPARENT);
+                });
+
+            Rectangle r = new Rectangle();
+
+            r.Width     = ((FrameworkElement)dragElement).ActualWidth;
+            r.Height    = ((FrameworkElement)dragElement).ActualHeight;
+            r.Fill  = new VisualBrush(dragElement);
+
+            this.dragdropWindow.Content = r;
+
+            // we want QueryContinueDrag notification so we can update the window position
+            //DragDrop.AddPreviewQueryContinueDragHandler(source, QueryContinueDrag);
+
+            // put the window in the right place to start
+            this.UpdateWindowLocation();
+        }
+
+        private void UpdateWindowLocation()
+        {
+            if (this.dragdropWindow != null)
+            {
+                Win32Interop.POINT p;
+
+                if (!Win32Interop.GetCursorPos(out p))
+                {
+                    return;
+                }
+
+                this.dragdropWindow.Left   = (double)p.X;
+                this.dragdropWindow.Top    = (double)p.Y;
+            }
+        }
+
+        private void DragFinished(DragDropEffects ret)
+        {
+            Mouse.Capture(null);
+
+            if (this.IsDragging)
+            {
+                if (this.DragScope != null)
+                {
+                    //AdornerLayer.GetAdornerLayer(this.DragScope).Remove(this.adorner);
+                    //this.adorner = null;
+                }
+                else
+                {
+                    this.DestroyDragDropWindow();
+                }
+            }
+
+            this.IsDragging = false;
+        }
+
+        #endregion
+    }
+}