comparison 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
comparison
equal deleted inserted replaced
9:904a9faadf8b 10:443821e55f06
1 using System;
2 using System.Diagnostics;
3 using System.Windows;
4 using System.Windows.Documents;
5 using System.Windows.Input;
6 using System.Windows.Interop;
7 using System.Windows.Media;
8 using System.Windows.Shapes;
9 using Chronos.Interop;
10
11 namespace Chronos.Presentation.DragAndDrop
12 {
13 public sealed class DragHelper
14 {
15 #region · Static Methods ·
16
17 private static UIElement GetDragElementOnHitTest(UIElement src, MouseEventArgs args)
18 {
19 HitTestResult hr = VisualTreeHelper.HitTest(src, args.GetPosition((IInputElement)src));
20 return hr.VisualHit as UIElement;
21 }
22
23 #endregion
24
25 #region · Fields ·
26
27 private UIElement dragSource;
28 private UIElement dragScope;
29 private IDataDropObjectProvider callback;
30 private Point startPoint;
31 private DragAdorner adorner;
32 private AdornerLayer layer;
33 private Window dragdropWindow;
34 private DragDropEffects allowedEffects;
35 private bool mouseLeftScope;
36 private bool isDragging;
37 private double opacity;
38
39 #endregion
40
41 #region · Properties ·
42
43 public double Opacity
44 {
45 get { return this.opacity; }
46 }
47
48 public DragDropEffects AllowedEffects
49 {
50 get { return this.allowedEffects; }
51 set { this.allowedEffects = value; }
52 }
53
54 #endregion
55
56 #region · Private Properties ·
57
58 private UIElement DragSource
59 {
60 get { return this.dragSource; }
61 set
62 {
63 this.dragSource = value;
64 this.WireEvents(value);
65 }
66 }
67
68 private UIElement DragScope
69 {
70 get { return this.dragScope; }
71 set { this.dragScope = value; }
72 }
73
74 private IDataDropObjectProvider Callback
75 {
76 get { return this.callback; }
77 set { this.callback = value; }
78 }
79
80 private bool IsDragging
81 {
82 get { return this.isDragging; }
83 set { this.isDragging = value; }
84 }
85
86 private bool AllowsLink
87 {
88 get { return ((this.AllowedEffects & DragDropEffects.Link) != 0); }
89 }
90
91 private bool AllowsMove
92 {
93 get { return ((this.AllowedEffects & DragDropEffects.Move) != 0); }
94 }
95
96 private bool AllowsCopy
97 {
98 get { return ((this.AllowedEffects & DragDropEffects.Copy) != 0); }
99 }
100
101 #endregion
102
103 #region · Constructors ·
104
105 public DragHelper(UIElement dragSource, IDataDropObjectProvider callback, UIElement dragScope)
106 {
107 this.allowedEffects = DragDropEffects.Copy | DragDropEffects.Move;
108 this.opacity = 0.7;
109 this.DragSource = dragSource;
110 this.Callback = callback;
111 this.DragScope = dragScope;
112 }
113
114 #endregion
115
116 #region · DragSource Event Handlers ·
117
118 private void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
119 {
120 this.startPoint = e.GetPosition(DragScope);
121 }
122
123 #if DEBUG
124 void DragSource_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
125 {
126 System.Diagnostics.Debug.Assert(IsDragging == false);
127 }
128 #endif
129
130 private void DragSource_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
131 {
132 if (e.LeftButton == MouseButtonState.Pressed && !this.IsDragging)
133 {
134 Point position = e.GetPosition((IInputElement)DragScope);
135
136 if (Math.Abs(position.X - startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
137 Math.Abs(position.Y - startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
138 {
139 this.StartDrag(e);
140 }
141 }
142 }
143
144 #endregion
145
146 #region · DragScope Event Handlers ·
147
148 private void DragScope_DragLeave(object sender, DragEventArgs args)
149 {
150 if (args.OriginalSource == this.DragScope)
151 {
152 this.mouseLeftScope = true;
153 }
154 }
155
156 private void DragScope_DragOver(object sender, DragEventArgs args)
157 {
158 if (this.adorner != null)
159 {
160 this.adorner.LeftOffset = args.GetPosition(this.DragScope).X; /* - _startPoint.X */
161 this.adorner.TopOffset = args.GetPosition(this.DragScope).Y; /* - _startPoint.Y */
162 }
163 }
164
165 #endregion
166
167 #region · Event Wiring ·
168
169 private void WireEvents(UIElement uie)
170 {
171 Debug.Assert(uie != null);
172
173 if (uie != null)
174 {
175 uie.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
176 uie.PreviewMouseMove += new MouseEventHandler(DragSource_PreviewMouseMove);
177
178 #if DEBUG
179 uie.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonUp);
180 #endif
181 }
182 }
183
184 #endregion
185
186 #region · Private Methods ·
187
188 private void StartDrag(MouseEventArgs args)
189 {
190 IDataObject data = null;
191 UIElement dragelement = null;
192
193 // ADD THE DATA
194 if (this.Callback != null)
195 {
196 DragDataWrapper dw = new DragDataWrapper();
197
198 data = new DataObject(typeof(DragDataWrapper).ToString(), dw);
199
200 if ((this.Callback.SupportedActions & DragDropProviderActions.MultiFormatData) != 0)
201 {
202 this.Callback.AppendData(ref data, args);
203 }
204
205 if ((this.Callback.SupportedActions & DragDropProviderActions.Data) != 0)
206 {
207 dw.Data = this.Callback.GetData();
208 }
209
210 if ((this.Callback.SupportedActions & DragDropProviderActions.Visual) != 0)
211 {
212 dragelement = this.Callback.GetVisual(args);
213 }
214 else
215 {
216 dragelement = args.OriginalSource as UIElement;
217 }
218
219 dw.Source = this.DragSource;
220 dw.Shim = this.Callback;
221
222 Debug.Assert(this.DragScope == null, "The DragDataWrapper is meant for in-proc... Sorry for asserting, just wanted to confirm.. comment out assertion if needed");
223 }
224 else
225 {
226 dragelement = args.OriginalSource as UIElement;
227 data = new DataObject(typeof(UIElement).ToString(), dragelement);
228 }
229
230 if (dragelement == null || data == null || dragelement == this.DragSource)
231 {
232 return;
233 }
234
235 DragEventHandler dragOver = null;
236 DragEventHandler dragLeave = null;
237 QueryContinueDragEventHandler queryContinue = null;
238 GiveFeedbackEventHandler giveFeedback = null;
239 DragDropEffects effects = this.GetDragDropEffects();
240 DragDropEffects resultEffects;
241
242 // Inprocess Drag ...
243 if (this.DragScope != null)
244 {
245 bool previousAllowDrop = this.DragScope.AllowDrop;
246
247 this.adorner = new DragAdorner(this.DragScope, (UIElement)dragelement, true, this.Opacity);
248 this.layer = AdornerLayer.GetAdornerLayer(this.DragScope as Visual);
249
250 this.layer.Add(this.adorner);
251
252 if (this.DragScope != this.DragSource)
253 {
254 this.DragScope.AllowDrop = true;
255
256 DragDrop.AddPreviewDragOverHandler((DependencyObject)this.DragScope, dragOver = new DragEventHandler(DragScope_DragOver));
257 DragDrop.AddPreviewDragLeaveHandler(this.DragScope, dragLeave = new DragEventHandler(DragScope_DragLeave));
258 DragDrop.AddPreviewQueryContinueDragHandler(this.DragSource, queryContinue = new QueryContinueDragEventHandler(OnQueryContinueDrag));
259 }
260
261 try
262 {
263 this.IsDragging = true;
264 this.mouseLeftScope = false;
265 resultEffects = DragDrop.DoDragDrop(this.DragSource, data, effects);
266
267 this.DragFinished(resultEffects);
268 }
269 catch
270 {
271 Debug.Assert(false);
272 }
273
274 if (this.DragScope != this.DragSource)
275 {
276 this.DragScope.AllowDrop = previousAllowDrop;
277
278 DragDrop.RemovePreviewDragOverHandler(this.DragScope, dragOver);
279 DragDrop.RemovePreviewDragLeaveHandler(this.DragScope, dragLeave);
280 DragDrop.RemovePreviewQueryContinueDragHandler(this.DragSource, queryContinue);
281 }
282 }
283 else
284 {
285 DragDrop.AddPreviewQueryContinueDragHandler(this.DragSource, queryContinue = new QueryContinueDragEventHandler(OnQueryContinueDrag));
286 DragDrop.AddGiveFeedbackHandler(this.DragSource, giveFeedback = new GiveFeedbackEventHandler(OnGiveFeedback));
287
288 this.IsDragging = true;
289
290 if ((this.Callback.SupportedActions & DragDropProviderActions.Visual) != 0)
291 {
292 this.CreateDragDropWindow(dragelement);
293 this.dragdropWindow.Show();
294 }
295
296 try
297 {
298 resultEffects = DragDrop.DoDragDrop(this.DragSource, data, effects);
299 }
300 finally
301 {
302 }
303
304 if ((this.Callback.SupportedActions & DragDropProviderActions.Visual) != 0)
305 {
306 this.DestroyDragDropWindow();
307 }
308
309 DragDrop.RemovePreviewQueryContinueDragHandler(this.DragSource, OnQueryContinueDrag);
310 DragDrop.AddGiveFeedbackHandler(this.DragSource, OnGiveFeedback);
311
312 this.IsDragging = false;
313 this.DragFinished(resultEffects);
314 }
315 }
316
317 private DragDropEffects GetDragDropEffects()
318 {
319 DragDropEffects effects = DragDropEffects.None;
320
321 bool ctrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
322 bool shift = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
323
324 if (ctrl && shift && this.AllowsLink)
325 {
326 effects |= DragDropEffects.Link;
327 }
328 else if (ctrl && this.AllowsCopy)
329 {
330 effects |= DragDropEffects.Copy;
331 }
332 else if (this.AllowsMove)
333 {
334 effects |= DragDropEffects.Move;
335 }
336
337 return effects;
338 }
339
340 private void OnGiveFeedback(object sender, GiveFeedbackEventArgs args)
341 {
342 args.UseDefaultCursors = ((this.Callback.SupportedActions & DragDropProviderActions.Visual) == 0);
343 args.Handled = true;
344 }
345
346 private void OnQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
347 {
348 #if DEBUG
349 if (this.DragScope != null)
350 {
351 Point pd = Mouse.GetPosition(this.DragScope);
352 }
353 #endif
354 if (this.DragScope == null)
355 {
356 this.UpdateWindowLocation();
357 }
358 else
359 {
360 Point p = Mouse.GetPosition(this.DragScope);
361
362 if (this.adorner != null)
363 {
364 this.adorner.LeftOffset = p.X /* - _startPoint.X */ ;
365 this.adorner.TopOffset = p.Y /* - _startPoint.Y */ ;
366 }
367
368 if (this.mouseLeftScope)
369 {
370 e.Action = DragAction.Cancel;
371 e.Handled = true;
372 }
373 }
374 }
375
376 private void DestroyDragDropWindow()
377 {
378 if (this.dragdropWindow != null)
379 {
380 this.dragdropWindow.Close();
381 this.dragdropWindow = null;
382 }
383 }
384
385 private void CreateDragDropWindow(Visual dragElement)
386 {
387 Debug.Assert(this.dragdropWindow == null);
388
389 this.dragdropWindow = new Window();
390
391 this.dragdropWindow.WindowStyle = WindowStyle.None;
392 this.dragdropWindow.AllowsTransparency = true;
393 this.dragdropWindow.AllowDrop = false;
394 this.dragdropWindow.Background = null;
395 this.dragdropWindow.IsHitTestVisible = false;
396 this.dragdropWindow.SizeToContent = SizeToContent.WidthAndHeight;
397 this.dragdropWindow.Topmost = true;
398 this.dragdropWindow.ShowInTaskbar = false;
399
400 this.dragdropWindow.SourceInitialized += new EventHandler(
401 delegate(object sender, EventArgs args)
402 {
403 //TODO assert that we can do this..
404 PresentationSource windowSource = PresentationSource.FromVisual(this.dragdropWindow);
405 IntPtr handle = ((HwndSource)windowSource).Handle;
406
407 Int32 styles = Win32Interop.GetWindowLong(handle, Win32Interop.GWL_EXSTYLE);
408
409 Win32Interop.SetWindowLong(handle, Win32Interop.GWL_EXSTYLE, styles | Win32Interop.WS_EX_LAYERED | Win32Interop.WS_EX_TRANSPARENT);
410 });
411
412 Rectangle r = new Rectangle();
413
414 r.Width = ((FrameworkElement)dragElement).ActualWidth;
415 r.Height = ((FrameworkElement)dragElement).ActualHeight;
416 r.Fill = new VisualBrush(dragElement);
417
418 this.dragdropWindow.Content = r;
419
420 // we want QueryContinueDrag notification so we can update the window position
421 //DragDrop.AddPreviewQueryContinueDragHandler(source, QueryContinueDrag);
422
423 // put the window in the right place to start
424 this.UpdateWindowLocation();
425 }
426
427 private void UpdateWindowLocation()
428 {
429 if (this.dragdropWindow != null)
430 {
431 Win32Interop.POINT p;
432
433 if (!Win32Interop.GetCursorPos(out p))
434 {
435 return;
436 }
437
438 this.dragdropWindow.Left = (double)p.X;
439 this.dragdropWindow.Top = (double)p.Y;
440 }
441 }
442
443 private void DragFinished(DragDropEffects ret)
444 {
445 Mouse.Capture(null);
446
447 if (this.IsDragging)
448 {
449 if (this.DragScope != null)
450 {
451 //AdornerLayer.GetAdornerLayer(this.DragScope).Remove(this.adorner);
452 //this.adorner = null;
453 }
454 else
455 {
456 this.DestroyDragDropWindow();
457 }
458 }
459
460 this.IsDragging = false;
461 }
462
463 #endregion
464 }
465 }