DraggAnimatedPanel.cs 8.9 KB

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