Mercurial > silverbladetech
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 } |