DraggAnimatedPanel.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*Developed by (doiTTeam)=>doiTTeam.mail = [email protected]*/
  2. using System;
  3. using System.Linq;
  4. using System.Runtime.CompilerServices;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Documents;
  8. using System.Windows.Input;
  9. using System.Windows.Media;
  10. using System.Windows.Media.Animation;
  11. using System.Windows.Navigation;
  12. namespace DraggAnimatedPanel
  13. {
  14. /// <summary>
  15. /// Description of DraggAnimatedPanel.
  16. /// </summary>
  17. public partial class DraggAnimatedPanel : WrapPanel
  18. {
  19. #region private vars
  20. Size _calculatedSize;
  21. bool _isNotFirstArrange = false;
  22. int columns, rows;
  23. #endregion
  24. static DraggAnimatedPanel()
  25. {
  26. DefaultStyleKeyProperty.OverrideMetadata(typeof(DraggAnimatedPanel), new FrameworkPropertyMetadata(typeof(DraggAnimatedPanel)));
  27. }
  28. public DraggAnimatedPanel() : base()
  29. {
  30. this.AddHandler(Mouse.MouseMoveEvent, new MouseEventHandler(OnMouseMove), false);
  31. this.MouseLeftButtonUp += OnMouseUp;
  32. this.LostMouseCapture += OnLostMouseCapture;
  33. }
  34. UIElement GetChildThatHasMouseOver()
  35. {
  36. return GetParent(Mouse.DirectlyOver as DependencyObject, (ve) => Children.Contains(ve as UIElement)) as UIElement;
  37. }
  38. Point GetItemVisualPoint(UIElement element)
  39. {
  40. TransformGroup group = (TransformGroup)element.RenderTransform;
  41. TranslateTransform trans = (TranslateTransform)group.Children[0];
  42. return new Point(trans.X, trans.Y);
  43. }
  44. int GetIndexFromPoint(double x, double y)
  45. {
  46. int columnIndex = (int)Math.Truncate(x / itemContainterWidth);
  47. int rowIndex = (int)Math.Truncate(y / itemContainterHeight);
  48. return columns * rowIndex + columnIndex;
  49. }
  50. int GetIndexFromPoint(Point p)
  51. {
  52. return GetIndexFromPoint(p.X, p.Y);
  53. }
  54. #region dependency properties
  55. public static readonly DependencyProperty ItemsWidthProperty =
  56. DependencyProperty.Register(
  57. "ItemsWidth",
  58. typeof(double),
  59. typeof(DraggAnimatedPanel),
  60. new FrameworkPropertyMetadata(150d));
  61. public static readonly DependencyProperty ItemsHeightProperty =
  62. DependencyProperty.Register(
  63. "ItemsHeight",
  64. typeof(double),
  65. typeof(DraggAnimatedPanel),
  66. new FrameworkPropertyMetadata(60d));
  67. public static readonly DependencyProperty ItemSeparationProperty =
  68. DependencyProperty.Register(
  69. "ItemSeparation",
  70. typeof(Thickness),
  71. typeof(DraggAnimatedPanel),
  72. new FrameworkPropertyMetadata());
  73. // Using a DependencyProperty as the backing store for AnimationMilliseconds. This enables animation, styling, binding, etc...
  74. public static readonly DependencyProperty AnimationMillisecondsProperty =
  75. DependencyProperty.Register("AnimationMilliseconds", typeof(int), typeof(DraggAnimatedPanel), new FrameworkPropertyMetadata(200));
  76. public static readonly DependencyProperty SwapCommandProperty =
  77. DependencyProperty.Register(
  78. "SwapCommand",
  79. typeof(ICommand),
  80. typeof(DraggAnimatedPanel),
  81. new FrameworkPropertyMetadata(null));
  82. #endregion
  83. #region properties
  84. public double ItemsWidth
  85. {
  86. get { return (double)GetValue(ItemsWidthProperty); }
  87. set { SetValue(ItemsWidthProperty, value); }
  88. }
  89. public double ItemsHeight
  90. {
  91. get { return (double)GetValue(ItemsHeightProperty); }
  92. set { SetValue(ItemsHeightProperty, value); }
  93. }
  94. public Thickness ItemSeparation
  95. {
  96. get { return (Thickness)this.GetValue(ItemSeparationProperty); }
  97. set { this.SetValue(ItemSeparationProperty, value); }
  98. }
  99. public int AnimationMilliseconds
  100. {
  101. get { return (int)GetValue(AnimationMillisecondsProperty); }
  102. set { SetValue(AnimationMillisecondsProperty, value); }
  103. }
  104. private double itemContainterHeight
  105. {
  106. get { return ItemSeparation.Top + ItemsHeight + ItemSeparation.Bottom; }
  107. }
  108. private double itemContainterWidth
  109. {
  110. get { return ItemSeparation.Left + ItemsWidth + ItemSeparation.Right; }
  111. }
  112. public ICommand SwapCommand
  113. {
  114. get { return (ICommand)GetValue(SwapCommandProperty); }
  115. set { SetValue(SwapCommandProperty, value); }
  116. }
  117. #endregion
  118. #region transformation things
  119. private void AnimateAll()
  120. {
  121. //Apply exactly the same algorithm, but instide of Arrange a call AnimateTo method
  122. double colPosition = 0;
  123. double rowPosition = 0;
  124. foreach (UIElement child in Children)
  125. {
  126. if (child != _draggedElement)
  127. AnimateTo(child, colPosition + ItemSeparation.Left, rowPosition + ItemSeparation.Top, _isNotFirstArrange ? AnimationMilliseconds : 0);
  128. //drag will locate dragged element
  129. colPosition += itemContainterWidth;
  130. if (colPosition + 1 > _calculatedSize.Width)
  131. {
  132. colPosition = 0;
  133. rowPosition += itemContainterHeight;
  134. }
  135. }
  136. }
  137. private void AnimateTo(UIElement child, double x, double y, int duration)
  138. {
  139. TransformGroup group = (TransformGroup)child.RenderTransform;
  140. TranslateTransform trans = (TranslateTransform)group.Children.First((groupElement) => groupElement is TranslateTransform);
  141. trans.BeginAnimation(TranslateTransform.XProperty, MakeAnimation(x, duration));
  142. trans.BeginAnimation(TranslateTransform.YProperty, MakeAnimation(y, duration));
  143. }
  144. private DoubleAnimation MakeAnimation(double to, int duration)
  145. {
  146. DoubleAnimation anim = new DoubleAnimation(to, TimeSpan.FromMilliseconds(duration));
  147. anim.AccelerationRatio = 0.2;
  148. anim.DecelerationRatio = 0.7;
  149. return anim;
  150. }
  151. #endregion
  152. #region measure
  153. protected override Size MeasureOverride(Size availableSize)
  154. {
  155. Size itemContainerSize = new Size(itemContainterWidth, itemContainterHeight);
  156. int count = 0; //for not call it again
  157. foreach (UIElement child in Children)
  158. {
  159. child.Measure(itemContainerSize);
  160. count++;
  161. }
  162. if (availableSize.Width < itemContainterWidth)
  163. _calculatedSize = new Size(itemContainterWidth, count * itemContainterHeight); //the size of nX1
  164. else
  165. {
  166. columns = (int)Math.Truncate(availableSize.Width / itemContainterWidth);
  167. rows = count / columns;
  168. if (count % columns != 0)
  169. rows++;
  170. _calculatedSize = new Size(columns * itemContainterWidth, rows * itemContainterHeight);
  171. }
  172. return _calculatedSize;
  173. }
  174. #endregion
  175. #region arrange
  176. protected override Size ArrangeOverride(Size finalSize)
  177. {
  178. Size _finalItemSize = new Size(ItemsWidth, ItemsHeight);
  179. //if is animated then arrange elements to 0,0, and then put them on its location using the transform
  180. foreach (UIElement child in InternalChildren)
  181. {
  182. // If this is the first time we've seen this child, add our transforms
  183. if (child.RenderTransform as TransformGroup == null)
  184. {
  185. child.RenderTransformOrigin = new Point(0.5, 0.5);
  186. TransformGroup group = new TransformGroup();
  187. child.RenderTransform = group;
  188. group.Children.Add(new TranslateTransform());
  189. }
  190. //locate all children in 0,0 point//TODO: use infinity and then scale each element to items size
  191. child.Arrange(new Rect(new Point(0, 0), _finalItemSize)); //when use transformations change to childs.DesireSize
  192. }
  193. AnimateAll();
  194. if (!_isNotFirstArrange)
  195. _isNotFirstArrange = true;
  196. return _calculatedSize;
  197. }
  198. #endregion
  199. #region Static
  200. //this can be an extension method
  201. public static DependencyObject GetParent(DependencyObject o, Func<DependencyObject, bool> matchFunction)
  202. {
  203. DependencyObject t = o;
  204. do
  205. {
  206. t = VisualTreeHelper.GetParent(t);
  207. } while (t != null && !matchFunction.Invoke(t));
  208. return t;
  209. }
  210. #endregion
  211. //TODO: Add IsEditing property
  212. //TODO: Add Scale transform to items for fill items area
  213. }
  214. }