PageRenderTime 37ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/BaconographyWP8Core/Common/FixedLongListSelector.cs

https://github.com/hippiehunter/Baconography
C# | 272 lines | 239 code | 32 blank | 1 comment | 59 complexity | de26df0398a2ebe31f9b71fd34428dd1 MD5 | raw file
  1. using BaconographyPortable.Messages;
  2. using BaconographyPortable.ViewModel;
  3. using BaconographyWP8Core.Common;
  4. using GalaSoft.MvvmLight.Messaging;
  5. using Microsoft.Phone.Controls;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using System.Windows;
  12. using System.Windows.Controls;
  13. using System.Windows.Controls.Primitives;
  14. using System.Windows.Input;
  15. using System.Windows.Media;
  16. namespace BaconographyWP8.Common
  17. {
  18. public class FixedLongListSelector : Microsoft.Phone.Controls.LongListSelector
  19. {
  20. bool viewportChanged = false;
  21. bool isMoving = false;
  22. double manipulationStart = 0;
  23. double manipulationEnd = 0;
  24. private Dictionary<object, ContentPresenter> items = new Dictionary<object, ContentPresenter>();
  25. public FixedLongListSelector()
  26. {
  27. SelectionChanged += FixedLongListSelector_SelectionChanged;
  28. ManipulationStateChanged += listbox_ManipulationStateChanged;
  29. MouseMove += listbox_MouseMove;
  30. Tap += FixedLongListSelector_Tap;
  31. ItemRealized += OnItemRealized;
  32. ItemUnrealized += OnItemUnRealized;
  33. Compression += FixedLongListSelector_Compression;
  34. }
  35. void FixedLongListSelector_Compression(object sender, CompressionEventArgs e)
  36. {
  37. if (e.Type == CompressionType.Top)
  38. PulledDown = true;
  39. else
  40. PulledDown = false;
  41. }
  42. void FixedLongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
  43. {
  44. SelectedItem = base.SelectedItem;
  45. }
  46. public static readonly DependencyProperty SelectedItemProperty =
  47. DependencyProperty.Register(
  48. "SelectedItem",
  49. typeof(object),
  50. typeof(FixedLongListSelector),
  51. new PropertyMetadata(null, OnSelectedItemChanged)
  52. );
  53. public static readonly DependencyProperty PulledDownProperty =
  54. DependencyProperty.Register(
  55. "PulledDown",
  56. typeof(bool),
  57. typeof(FixedLongListSelector),
  58. new PropertyMetadata(false, OnPulledDownChanged)
  59. );
  60. private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  61. {
  62. var selector = (FixedLongListSelector)d;
  63. selector.SelectedItem = e.NewValue;
  64. }
  65. public new object SelectedItem
  66. {
  67. get { return GetValue(SelectedItemProperty); }
  68. set { SetValue(SelectedItemProperty, value); }
  69. }
  70. private static void OnPulledDownChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  71. {
  72. var selector = (FixedLongListSelector)d;
  73. selector.PulledDown = (bool)e.NewValue;
  74. }
  75. public bool PulledDown
  76. {
  77. get { return (bool)GetValue(PulledDownProperty); }
  78. set { SetValue(PulledDownProperty, value); }
  79. }
  80. void OnItemRealized(object sender, Microsoft.Phone.Controls.ItemRealizationEventArgs e)
  81. {
  82. viewportChanged = true;
  83. if (e.ItemKind == LongListSelectorItemKind.Item)
  84. {
  85. object o = e.Container.DataContext;
  86. items[o] = e.Container;
  87. }
  88. }
  89. void OnItemUnRealized(object sender, Microsoft.Phone.Controls.ItemRealizationEventArgs e)
  90. {
  91. viewportChanged = true;
  92. if (e.ItemKind == LongListSelectorItemKind.Item)
  93. {
  94. object o = e.Container.DataContext;
  95. items.Remove(o);
  96. }
  97. }
  98. void FixedLongListSelector_Tap(object sender, System.Windows.Input.GestureEventArgs e)
  99. {
  100. var pos = e.GetPosition(null);
  101. var orientationManager = Styles.Resources["orientationManager"] as OrientationManager;
  102. var val = pos.Y;
  103. if (orientationManager != null
  104. && (orientationManager.Orientation == PageOrientation.Landscape
  105. || orientationManager.Orientation == PageOrientation.LandscapeLeft
  106. || orientationManager.Orientation == PageOrientation.LandscapeRight))
  107. val = pos.X;
  108. if (!isMoving)
  109. manipulationStart = val;
  110. else
  111. manipulationEnd = val;
  112. isMoving = true;
  113. }
  114. OrientationManager _orientationManager;
  115. void listbox_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
  116. {
  117. var pos = e.GetPosition(null);
  118. var orientationManager = _orientationManager == null ? (_orientationManager = Styles.Resources["orientationManager"] as OrientationManager) : _orientationManager;
  119. var val = pos.Y;
  120. if (orientationManager != null
  121. && (orientationManager.Orientation == PageOrientation.Landscape
  122. || orientationManager.Orientation == PageOrientation.LandscapeLeft
  123. || orientationManager.Orientation == PageOrientation.LandscapeRight))
  124. val = pos.X;
  125. if (!isMoving)
  126. {
  127. manipulationStart = val;
  128. }
  129. else
  130. {
  131. manipulationEnd = val;
  132. if (ManipulationState == System.Windows.Controls.Primitives.ManipulationState.Manipulating)
  133. {
  134. DoInterimManipulation();
  135. }
  136. }
  137. isMoving = true;
  138. }
  139. const int pullDownOffset = 95;
  140. void DoInterimManipulation()
  141. {
  142. var total = manipulationStart - manipulationEnd;
  143. var viewport = FindViewport(this);
  144. if (viewport != null)
  145. {
  146. var firstVisibleItem = GetFirstVisibleItem();
  147. if (firstVisibleItem != null && ItemsSource.Count > 0 && firstVisibleItem == ItemsSource[0])
  148. {
  149. if (Math.Abs(total) > pullDownOffset)
  150. {
  151. var orientationManager = _orientationManager == null ? (_orientationManager = Styles.Resources["orientationManager"] as OrientationManager) : _orientationManager;
  152. var adjustedTotal = -total;
  153. if (orientationManager != null)
  154. {
  155. if(orientationManager.Orientation == PageOrientation.LandscapeLeft)
  156. {
  157. adjustedTotal = total;
  158. }
  159. }
  160. if(adjustedTotal > pullDownOffset)
  161. Compression(this, new CompressionEventArgs(CompressionType.Top));
  162. else
  163. Compression(this, new CompressionEventArgs(CompressionType.None));
  164. }
  165. else
  166. Compression(this, new CompressionEventArgs(CompressionType.None));
  167. }
  168. else
  169. {
  170. Compression(this, new CompressionEventArgs(CompressionType.None));
  171. }
  172. }
  173. }
  174. void listbox_ManipulationStateChanged(object sender, EventArgs e)
  175. {
  176. if (ManipulationState == System.Windows.Controls.Primitives.ManipulationState.Idle)
  177. {
  178. isMoving = false;
  179. viewportChanged = false;
  180. }
  181. else if (ManipulationState == System.Windows.Controls.Primitives.ManipulationState.Manipulating)
  182. {
  183. viewportChanged = false;
  184. DoInterimManipulation();
  185. }
  186. else if (ManipulationState == System.Windows.Controls.Primitives.ManipulationState.Animating)
  187. {
  188. if (PulledDown)
  189. {
  190. // User released, do refresh
  191. var redditVM = DataContext as RedditViewModel;
  192. var message = new RefreshSubredditMessage();
  193. if (redditVM != null)
  194. {
  195. message.Subreddit = redditVM.SelectedSubreddit;
  196. Messenger.Default.Send<RefreshSubredditMessage>(message);
  197. }
  198. Compression(this, new CompressionEventArgs(CompressionType.None));
  199. }
  200. }
  201. }
  202. public event OnCompression Compression;
  203. #region LLS Util
  204. public static ViewportControl FindViewport(DependencyObject parent)
  205. {
  206. var childCount = VisualTreeHelper.GetChildrenCount(parent);
  207. for (var i = 0; i < childCount; i++)
  208. {
  209. var elt = VisualTreeHelper.GetChild(parent, i);
  210. if (elt is ViewportControl) return (ViewportControl)elt;
  211. var result = FindViewport(elt);
  212. if (result != null) return result;
  213. }
  214. return null;
  215. }
  216. public object GetFirstVisibleItem()
  217. {
  218. var viewPort = FindViewport(this);
  219. if (items.Count > 0 && viewPort != null)
  220. {
  221. var offset = viewPort.Viewport.Top;
  222. return items.Where(x => Canvas.GetTop(x.Value) + x.Value.ActualHeight > offset)
  223. .OrderBy(x => Canvas.GetTop(x.Value)).First().Key;
  224. }
  225. else
  226. return null;
  227. }
  228. #endregion
  229. }
  230. public class CompressionEventArgs : EventArgs
  231. {
  232. public CompressionType Type { get; protected set; }
  233. public CompressionEventArgs(CompressionType type)
  234. {
  235. Type = type;
  236. }
  237. }
  238. public enum CompressionType { None, Top, Bottom, Left, Right };
  239. public delegate void OnCompression(object sender, CompressionEventArgs e);
  240. }