PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/PSLib/CSharp/WOW Developing/SelectionHelperTest/QuickZip.UserControls/Components/SelectionHelper/SelectionHelper.cs

http://pslib.googlecode.com/
C# | 500 lines | 401 code | 90 blank | 9 comment | 81 complexity | 7fcf422ac0191a00b28de5ecf33ea133 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Documents;
  8. using System.Windows.Input;
  9. using System.Diagnostics;
  10. using System.Windows.Controls.Primitives;
  11. using System.Windows.Media;
  12. using System.ComponentModel;
  13. using System.Windows.Threading;
  14. namespace QuickZip.UserControls
  15. {
  16. public static class SelectionHelper
  17. {
  18. #region Attached Properties
  19. public static DependencyProperty EnableSelectionProperty =
  20. DependencyProperty.RegisterAttached("EnableSelection", typeof(bool), typeof(SelectionHelper),
  21. new PropertyMetadata(OnEnableSelectionpChanged));
  22. public static bool GetEnableSelection(DependencyObject target)
  23. {
  24. return (bool)target.GetValue(EnableSelectionProperty);
  25. }
  26. public static void SetEnableSelection(DependencyObject target, bool value)
  27. {
  28. target.SetValue(EnableSelectionProperty, value);
  29. }
  30. private static DependencyProperty LastScrollContentPresenterProperty =
  31. DependencyProperty.RegisterAttached("LastScrollContentPresenter", typeof(ScrollContentPresenter), typeof(SelectionHelper));
  32. public static ScrollContentPresenter GetLastScrollContentPresenter(DependencyObject target)
  33. {
  34. return (ScrollContentPresenter)target.GetValue(LastScrollContentPresenterProperty);
  35. }
  36. public static void SetLastScrollContentPresenter(DependencyObject target, ScrollContentPresenter value)
  37. {
  38. target.SetValue(LastScrollContentPresenterProperty, value);
  39. }
  40. private static DependencyProperty SelectionAdornerProperty =
  41. DependencyProperty.RegisterAttached("SelectionAdorner", typeof(SelectionAdorner), typeof(SelectionHelper));
  42. public static SelectionAdorner GetSelectionAdorner(DependencyObject target)
  43. {
  44. return (SelectionAdorner)target.GetValue(SelectionAdornerProperty);
  45. }
  46. public static void SetSelectionAdorner(DependencyObject target, SelectionAdorner value)
  47. {
  48. target.SetValue(SelectionAdornerProperty, value);
  49. }
  50. private static DependencyProperty StartScrollbarPositionProperty =
  51. DependencyProperty.RegisterAttached("StartScrollbarPosition", typeof(Point), typeof(SelectionHelper));
  52. public static Point GetStartScrollbarPosition(DependencyObject target)
  53. {
  54. return (Point)target.GetValue(StartScrollbarPositionProperty);
  55. }
  56. public static void SetStartScrollbarPosition(DependencyObject target, Point value)
  57. {
  58. target.SetValue(StartScrollbarPositionProperty, value);
  59. }
  60. private static DependencyProperty StartPositionProperty =
  61. DependencyProperty.RegisterAttached("StartPosition", typeof(Point), typeof(SelectionHelper));
  62. public static Point GetStartPosition(DependencyObject target)
  63. {
  64. return (Point)target.GetValue(StartPositionProperty);
  65. }
  66. public static void SetStartPosition(DependencyObject target, Point value)
  67. {
  68. target.SetValue(StartPositionProperty, value);
  69. }
  70. private static DependencyProperty IsDraggingProperty =
  71. DependencyProperty.RegisterAttached("IsDragging", typeof(bool), typeof(SelectionHelper), new PropertyMetadata(false));
  72. public static bool GetIsDragging(DependencyObject target)
  73. {
  74. return (bool)target.GetValue(IsDraggingProperty);
  75. }
  76. public static bool GetIsDragging(ListView sender)
  77. {
  78. ItemsPresenter ip = UITools.FindVisualChild<ItemsPresenter>(sender);
  79. ScrollContentPresenter p = UITools.FindAncestor<ScrollContentPresenter>(ip);
  80. return GetIsDragging(p);
  81. }
  82. public static void SetIsDragging(DependencyObject target, bool value)
  83. {
  84. target.SetValue(IsDraggingProperty, value);
  85. }
  86. public static void OnEnableSelectionpChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
  87. {
  88. if (s is ListView)
  89. {
  90. ListView control = s as ListView;
  91. var OnScrollChange = (RoutedEventHandler)delegate(object sender, RoutedEventArgs args)
  92. {
  93. ItemsPresenter ip = UITools.FindVisualChild<ItemsPresenter>(sender as ListView);
  94. ScrollContentPresenter p = UITools.FindAncestor<ScrollContentPresenter>(ip);
  95. if (GetIsDragging(p) && Mouse.LeftButton == MouseButtonState.Pressed)
  96. UpdatePosition(p, true);
  97. };
  98. var OnMouseDown = (RoutedEventHandler)delegate(object sender, RoutedEventArgs args)
  99. {
  100. (sender as ListView).SelectedItems.Clear();
  101. };
  102. var OnSizeChanged = (RoutedEventHandler)delegate(object sender, RoutedEventArgs args)
  103. {
  104. ItemsPresenter ip = UITools.FindVisualChild<ItemsPresenter>(sender as ListView);
  105. ScrollContentPresenter p = UITools.FindAncestor<ScrollContentPresenter>(ip);
  106. EndDragging(p);
  107. };
  108. Action unloadAdorner = () =>
  109. {
  110. ScrollContentPresenter p = GetLastScrollContentPresenter(control);
  111. if (p != null)
  112. {
  113. SelectionAdorner _adorner = GetSelectionAdorner(p);
  114. if (AdornerLayer.GetAdornerLayer(p) != null)
  115. AdornerLayer.GetAdornerLayer(p).Remove(_adorner);
  116. control.MouseUp -= new MouseButtonEventHandler(OnMouseUp);
  117. control.MouseMove -= new MouseEventHandler(OnMouseMove);
  118. _adorner.PreviewMouseDown -= new MouseButtonEventHandler(OnPreviewMouseDown);
  119. _adorner.MouseMove -= new MouseEventHandler(OnMouseMove);
  120. _adorner.MouseUp -= new MouseButtonEventHandler(OnMouseUp);
  121. control.RemoveHandler(ListView.SizeChangedEvent, OnSizeChanged);
  122. SetSelectionAdorner(p, null);
  123. }
  124. };
  125. Action attachAdorner = () =>
  126. {
  127. unloadAdorner();
  128. ItemsPresenter ip = UITools.FindVisualChild<ItemsPresenter>(control);
  129. ScrollContentPresenter p = UITools.FindAncestor<ScrollContentPresenter>(ip);
  130. if (p != null)
  131. {
  132. SelectionAdorner _adorner = new SelectionAdorner(p);
  133. SetSelectionAdorner(p, _adorner);
  134. AdornerLayer.GetAdornerLayer(p).Add(_adorner);
  135. control.PreviewMouseDown += new MouseButtonEventHandler(OnPreviewMouseDown);
  136. control.MouseUp += new MouseButtonEventHandler(OnMouseUp);
  137. control.MouseMove += new MouseEventHandler(OnMouseMove);
  138. _adorner.PreviewMouseDown += new MouseButtonEventHandler(OnPreviewMouseDown);
  139. _adorner.MouseMove += new MouseEventHandler(OnMouseMove);
  140. _adorner.MouseUp += new MouseButtonEventHandler(OnMouseUp);
  141. control.AddHandler(ListView.SizeChangedEvent, OnSizeChanged);
  142. SetLastScrollContentPresenter(control, p);
  143. }
  144. };
  145. if ((bool)e.NewValue == true)
  146. {
  147. if (control.IsLoaded)
  148. attachAdorner();
  149. else
  150. control.Loaded += delegate { attachAdorner(); };
  151. control.AddHandler(ScrollViewer.ScrollChangedEvent, OnScrollChange);
  152. control.AddHandler(ListView.MouseDownEvent, OnMouseDown);
  153. //Monitor view change, and reattach handlers.
  154. DependencyPropertyDescriptor viewDescriptor = DependencyPropertyDescriptor.FromProperty(ListView.ViewProperty, typeof(ListView));
  155. viewDescriptor.AddValueChanged
  156. (control, delegate
  157. {
  158. control.Dispatcher.BeginInvoke(DispatcherPriority.Input, attachAdorner);
  159. });
  160. }
  161. else //If EnableSelection = False
  162. {
  163. unloadAdorner();
  164. control.RemoveHandler(ScrollViewer.ScrollChangedEvent, OnScrollChange);
  165. control.RemoveHandler(ListView.MouseDownEvent, OnMouseDown);
  166. SetSelectionAdorner(control, null);
  167. }
  168. }
  169. }
  170. #endregion
  171. #region Methods
  172. static ListViewItem getSelectedItem(ScrollContentPresenter lvSender, Point position)
  173. {
  174. HitTestResult r = VisualTreeHelper.HitTest(lvSender, position);
  175. if (r == null) return null;
  176. DependencyObject obj = r.VisualHit;
  177. while (!(obj is ListView) && (obj != null))
  178. {
  179. obj = VisualTreeHelper.GetParent(obj);
  180. if (obj is ListViewItem)
  181. return obj as ListViewItem;
  182. }
  183. return null;
  184. }
  185. static Point GetScrollbarPosition(ScrollContentPresenter p)
  186. {
  187. ScrollViewer scrollViewer = UITools.FindAncestor<ScrollViewer>(p);
  188. return new Point(p.ActualWidth / scrollViewer.ViewportWidth * scrollViewer.HorizontalOffset,
  189. p.ActualHeight / scrollViewer.ViewportHeight * scrollViewer.VerticalOffset);
  190. }
  191. static void BeginDragging(ScrollContentPresenter p)
  192. {
  193. SetStartScrollbarPosition(p, GetScrollbarPosition(p));
  194. SetStartPosition(p, Mouse.GetPosition(p));
  195. SetIsDragging(p, true);
  196. }
  197. internal static object PositionCheck(DependencyObject sender, object value)
  198. {
  199. if (value is Point)
  200. {
  201. Point ptValue = (Point)value;
  202. SelectionAdorner adorner = sender as SelectionAdorner;
  203. ptValue.X = Math.Min(Math.Max(ptValue.X, 0), adorner.ActualWidth);
  204. ptValue.Y = Math.Min(Math.Max(ptValue.Y, 0), adorner.ActualHeight);
  205. return ptValue;
  206. }
  207. return value;
  208. }
  209. static void UpdateSelectedItems(ListView lvControl, IList<object> newList)
  210. {
  211. List<object> addList = new List<object>();
  212. List<object> removeList = new List<object>(lvControl.SelectedItems as IList<object>);
  213. foreach (object obj in newList)
  214. if (removeList.Contains(obj))
  215. removeList.Remove(obj);
  216. else addList.Add(obj);
  217. foreach (object obj in removeList)
  218. lvControl.SelectedItems.Remove(obj);
  219. foreach (object obj in addList)
  220. lvControl.SelectedItems.Add(obj);
  221. }
  222. static void HighlightItems(ListView lvControl, IList<int> newList)
  223. {
  224. for (int i = 0; i < lvControl.Items.Count; i++)
  225. {
  226. ListViewItem item = lvControl.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem;
  227. if (item != null)
  228. SetIsDragging(item, newList.Contains(i));
  229. }
  230. }
  231. static void UnhighlightItems(ListView lvControl)
  232. {
  233. for (int i = 0; i < lvControl.Items.Count; i++)
  234. {
  235. ListViewItem item = lvControl.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem;
  236. if (item != null)
  237. SetIsDragging(item, false);
  238. }
  239. }
  240. static void UpdateSelection(ScrollContentPresenter p, Rect selectionBounds, bool highlightOnly)
  241. {
  242. ListView lvControl = UITools.FindAncestor<ListView>(p);
  243. if (lvControl != null)
  244. {
  245. IChildInfo icInfo = UITools.FindVisualChild<Panel>(p) as IChildInfo;
  246. List<object> newList = new List<object>();
  247. List<int> newIntList = new List<int>();
  248. if (icInfo != null)
  249. {
  250. for (int i = 0; i < lvControl.Items.Count; i++)
  251. if (icInfo.GetChildRect(i).IntersectsWith(selectionBounds))
  252. {
  253. newList.Add(lvControl.Items[i]);
  254. newIntList.Add(i);
  255. }
  256. }
  257. else
  258. if (lvControl.View is GridView)
  259. {
  260. Point curPos = (Point)PositionCheck(GetSelectionAdorner(p), Mouse.GetPosition(p));
  261. //selectionBounds
  262. if (_firstSelectedItem == null)
  263. _firstSelectedItem = getSelectedItem(p, curPos);
  264. ListViewItem curSelectedItem = getSelectedItem(p, curPos);
  265. if (_firstSelectedItem != null && curSelectedItem != null)
  266. {
  267. int startIdx = lvControl.ItemContainerGenerator.IndexFromContainer(_firstSelectedItem);
  268. int endIdx = lvControl.ItemContainerGenerator.IndexFromContainer(curSelectedItem);
  269. for (int i = Math.Min(startIdx, endIdx); i <= Math.Max(startIdx, endIdx); i++)
  270. {
  271. //ListViewItem item = lvControl.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem;
  272. //if (lvControl.Items[i] is IExtendedListViewContentItem && item != null)
  273. //{
  274. // ExtendedListViewContentItem exItem = lvControl.Items[i] as ExtendedListViewContentItem;
  275. // exItem.Index = i*i*i;
  276. // exItem.Bounds = VisualTreeHelper.GetDescendantBounds(item);
  277. //}
  278. if (i == -1) continue;
  279. newList.Add(lvControl.Items[i]);
  280. newIntList.Add(i);
  281. }
  282. }
  283. }
  284. if (highlightOnly)
  285. HighlightItems(lvControl, newIntList);
  286. else
  287. {
  288. UnhighlightItems(lvControl);
  289. UpdateSelectedItems(lvControl, newList);
  290. }
  291. }
  292. }
  293. static void UpdatePosition(ScrollContentPresenter p, bool highlightOnly)
  294. {
  295. ScrollViewer scrollViewer = UITools.FindAncestor<ScrollViewer>(p);
  296. SelectionAdorner _adorner = GetSelectionAdorner(p);
  297. if (GetIsDragging(p))
  298. {
  299. Point startScrollbarPosition = GetStartScrollbarPosition(p);
  300. Point curScrollbarPosition = GetScrollbarPosition(p);
  301. Point startPosition = GetStartPosition(p);
  302. Point curPosition = Mouse.GetPosition(p);
  303. if (!_adorner.IsSelecting)
  304. {
  305. if (Math.Abs(startPosition.X - curPosition.X) > SystemParameters.MinimumHorizontalDragDistance ||
  306. Math.Abs(startPosition.Y - curPosition.Y) > SystemParameters.MinimumVerticalDragDistance)
  307. {
  308. _adorner.IsSelecting = true;
  309. Mouse.Capture(p);
  310. }
  311. }
  312. else
  313. {
  314. Vector offset = Point.Subtract(startScrollbarPosition, curScrollbarPosition);
  315. _adorner.StartPosition = Point.Add(startPosition, offset);
  316. _adorner.EndPosition = curPosition;
  317. UpdateSelection(p, new Rect(
  318. new Point(startPosition.X + startScrollbarPosition.X, startPosition.Y + startScrollbarPosition.Y),
  319. new Point(curPosition.X + curScrollbarPosition.X, curPosition.Y + curScrollbarPosition.Y)), highlightOnly);
  320. }
  321. }
  322. }
  323. static void EndDragging(ScrollContentPresenter p)
  324. {
  325. SelectionAdorner _adorner = GetSelectionAdorner(p);
  326. if (_adorner.IsSelecting)
  327. {
  328. UpdatePosition(p, false);
  329. _adorner.IsSelecting = false;
  330. SetIsDragging(p, false);
  331. }
  332. }
  333. static bool _itemAlreadySelected = false;
  334. static ListViewItem _itemUnderMouse = null;
  335. static ListViewItem _firstSelectedItem = null;
  336. static ScrollContentPresenter getScrollContentPresenter(object sender)
  337. {
  338. if (sender is ListView)
  339. {
  340. ItemsPresenter ip = UITools.FindVisualChild<ItemsPresenter>(sender as ListView);
  341. return UITools.FindAncestor<ScrollContentPresenter>(ip);
  342. }
  343. else
  344. if (sender is SelectionAdorner)
  345. return (ScrollContentPresenter)((SelectionAdorner)sender).AdornedElement;
  346. else return (ScrollContentPresenter)sender;
  347. }
  348. static void OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
  349. {
  350. bool isOverScrollBar = UITools.FindAncestor<ScrollBar>(e.OriginalSource as DependencyObject) != null;
  351. bool spButtonPressed = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift) ||
  352. Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
  353. ScrollContentPresenter p = getScrollContentPresenter(sender);
  354. _itemUnderMouse = getSelectedItem(p, e.GetPosition(p));
  355. if (!spButtonPressed && !isOverScrollBar)
  356. {
  357. _firstSelectedItem = _itemUnderMouse;
  358. _itemAlreadySelected = (_itemUnderMouse != null && _itemUnderMouse.IsSelected);
  359. if (!_itemAlreadySelected && e.ClickCount == 1)
  360. {
  361. BeginDragging(p);
  362. e.Handled = true;
  363. }
  364. }
  365. else if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
  366. {
  367. ListView lvSender = UITools.FindAncestor<ListView>(sender as DependencyObject);
  368. int startIdx = lvSender.SelectedIndex;
  369. int endIdx = lvSender.ItemContainerGenerator.IndexFromContainer(_itemUnderMouse);
  370. if (startIdx != -1 && endIdx != -1)
  371. {
  372. lvSender.SelectedItems.Clear();
  373. for (int i = Math.Min(startIdx, endIdx); i <= Math.Max(startIdx, endIdx); i++)
  374. lvSender.SelectedItems.Add(lvSender.Items[i]);
  375. e.Handled = true;
  376. }
  377. }
  378. }
  379. static void OnMouseMove(object sender, MouseEventArgs e)
  380. {
  381. ScrollContentPresenter p = getScrollContentPresenter(sender);
  382. if (GetIsDragging(p))
  383. if (e.LeftButton == MouseButtonState.Pressed)
  384. UpdatePosition(p, true);
  385. }
  386. static void OnMouseUp(object sender, MouseButtonEventArgs e)
  387. {
  388. ScrollContentPresenter p = getScrollContentPresenter(sender);
  389. if (GetIsDragging(p))
  390. {
  391. EndDragging(p);
  392. Mouse.Capture(null);
  393. UITools.FindAncestor<ListView>(p).Focus();
  394. ListViewItem curSelectedItem = getSelectedItem(p, Mouse.GetPosition(p));
  395. if (curSelectedItem != null && curSelectedItem.Equals(_itemUnderMouse))
  396. {
  397. UITools.FindAncestor<ListBox>(p).SelectedItems.Clear();
  398. _itemUnderMouse.IsSelected = true;
  399. }
  400. }
  401. if (_firstSelectedItem == null && GetStartPosition(p).Equals(Mouse.GetPosition(p)))
  402. UITools.FindAncestor<ListBox>(p).SelectedItems.Clear();
  403. _firstSelectedItem = null;
  404. SetIsDragging(p, false);
  405. }
  406. #endregion
  407. #region Data
  408. #endregion
  409. }
  410. }