MouseDragElementBehavior.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. using System.Windows;
  2. using System.Windows.Input;
  3. using System.Windows.Media;
  4. using HandyControl.Data;
  5. namespace HandyControl.Interactivity;
  6. public class MouseDragElementBehavior : Behavior<FrameworkElement>
  7. {
  8. public static readonly DependencyProperty ConstrainToParentBoundsProperty =
  9. DependencyProperty.Register("ConstrainToParentBounds", typeof(bool), typeof(MouseDragElementBehavior),
  10. new PropertyMetadata(ValueBoxes.FalseBox, OnConstrainToParentBoundsChanged));
  11. public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double),
  12. typeof(MouseDragElementBehavior), new PropertyMetadata(double.PositiveInfinity, OnXChanged));
  13. public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double),
  14. typeof(MouseDragElementBehavior), new PropertyMetadata(double.PositiveInfinity, OnYChanged));
  15. // Fields
  16. private Transform _cachedRenderTransform;
  17. private Point _relativePosition;
  18. private bool _settingPosition;
  19. // Properties
  20. public bool ConstrainToParentBounds
  21. {
  22. get => (bool) GetValue(ConstrainToParentBoundsProperty);
  23. set => SetValue(ConstrainToParentBoundsProperty, ValueBoxes.BooleanBox(value));
  24. }
  25. private Rect ElementBounds
  26. {
  27. get
  28. {
  29. var layoutRect = ExtendedVisualStateManager.GetLayoutRect(AssociatedObject);
  30. return new Rect(new Point(0.0, 0.0), new Size(layoutRect.Width, layoutRect.Height));
  31. }
  32. }
  33. private FrameworkElement ParentElement =>
  34. AssociatedObject.Parent as FrameworkElement;
  35. private Transform RenderTransform
  36. {
  37. get
  38. {
  39. if (_cachedRenderTransform == null ||
  40. !ReferenceEquals(_cachedRenderTransform, AssociatedObject.RenderTransform))
  41. {
  42. var transform = CloneTransform(AssociatedObject.RenderTransform);
  43. RenderTransform = transform;
  44. }
  45. return _cachedRenderTransform;
  46. }
  47. set
  48. {
  49. if (!Equals(_cachedRenderTransform, value))
  50. {
  51. _cachedRenderTransform = value;
  52. AssociatedObject.RenderTransform = value;
  53. }
  54. }
  55. }
  56. private UIElement RootElement
  57. {
  58. get
  59. {
  60. DependencyObject associatedObject = AssociatedObject;
  61. for (var obj3 = associatedObject; obj3 != null; obj3 = VisualTreeHelper.GetParent(associatedObject))
  62. associatedObject = obj3;
  63. return associatedObject as UIElement;
  64. }
  65. }
  66. public double X
  67. {
  68. get =>
  69. (double) GetValue(XProperty);
  70. set => SetValue(XProperty, value);
  71. }
  72. public double Y
  73. {
  74. get =>
  75. (double) GetValue(YProperty);
  76. set => SetValue(YProperty, value);
  77. }
  78. // Events
  79. public event MouseEventHandler DragBegun;
  80. public event MouseEventHandler DragFinished;
  81. public event MouseEventHandler Dragging;
  82. // Methods
  83. private void ApplyTranslation(double x, double y)
  84. {
  85. if (ParentElement != null)
  86. {
  87. var point = TransformAsVector(RootElement.TransformToVisual(ParentElement), x, y);
  88. x = point.X;
  89. y = point.Y;
  90. if (ConstrainToParentBounds)
  91. {
  92. var parentElement = ParentElement;
  93. var rect = new Rect(0.0, 0.0, parentElement.ActualWidth, parentElement.ActualHeight);
  94. var transform2 = AssociatedObject.TransformToVisual(parentElement);
  95. var elementBounds = ElementBounds;
  96. var rect3 = transform2.TransformBounds(elementBounds);
  97. rect3.X += x;
  98. rect3.Y += y;
  99. if (!RectContainsRect(rect, rect3))
  100. {
  101. if (rect3.X < rect.Left)
  102. {
  103. var num = rect3.X - rect.Left;
  104. x -= num;
  105. }
  106. else if (rect3.Right > rect.Right)
  107. {
  108. var num2 = rect3.Right - rect.Right;
  109. x -= num2;
  110. }
  111. if (rect3.Y < rect.Top)
  112. {
  113. var num3 = rect3.Y - rect.Top;
  114. y -= num3;
  115. }
  116. else if (rect3.Bottom > rect.Bottom)
  117. {
  118. var num4 = rect3.Bottom - rect.Bottom;
  119. y -= num4;
  120. }
  121. }
  122. }
  123. ApplyTranslationTransform(x, y);
  124. }
  125. }
  126. internal void ApplyTranslationTransform(double x, double y)
  127. {
  128. var renderTransform = RenderTransform;
  129. var transform2 = renderTransform as TranslateTransform;
  130. if (transform2 == null)
  131. {
  132. var group = renderTransform as TransformGroup;
  133. var transform3 = renderTransform as MatrixTransform;
  134. if (group != null)
  135. {
  136. if (group.Children.Count > 0)
  137. transform2 = group.Children[group.Children.Count - 1] as TranslateTransform;
  138. if (transform2 == null)
  139. {
  140. transform2 = new TranslateTransform();
  141. group.Children.Add(transform2);
  142. }
  143. }
  144. else
  145. {
  146. if (transform3 != null)
  147. {
  148. var matrix = transform3.Matrix;
  149. matrix.OffsetX += x;
  150. matrix.OffsetY += y;
  151. var transform4 = new MatrixTransform
  152. {
  153. Matrix = matrix
  154. };
  155. RenderTransform = transform4;
  156. return;
  157. }
  158. var group2 = new TransformGroup();
  159. transform2 = new TranslateTransform();
  160. if (renderTransform != null)
  161. group2.Children.Add(renderTransform);
  162. group2.Children.Add(transform2);
  163. RenderTransform = group2;
  164. }
  165. }
  166. transform2.X += x;
  167. transform2.Y += y;
  168. }
  169. internal static Transform CloneTransform(Transform transform)
  170. {
  171. if (transform == null)
  172. return null;
  173. if (transform is ScaleTransform transform2)
  174. return new ScaleTransform
  175. {
  176. CenterX = transform2.CenterX,
  177. CenterY = transform2.CenterY,
  178. ScaleX = transform2.ScaleX,
  179. ScaleY = transform2.ScaleY
  180. };
  181. if (transform is RotateTransform transform3)
  182. return new RotateTransform
  183. {
  184. Angle = transform3.Angle,
  185. CenterX = transform3.CenterX,
  186. CenterY = transform3.CenterY
  187. };
  188. if (transform is SkewTransform transform4)
  189. return new SkewTransform
  190. {
  191. AngleX = transform4.AngleX,
  192. AngleY = transform4.AngleY,
  193. CenterX = transform4.CenterX,
  194. CenterY = transform4.CenterY
  195. };
  196. if (transform is TranslateTransform transform5)
  197. return new TranslateTransform
  198. {
  199. X = transform5.X,
  200. Y = transform5.Y
  201. };
  202. if (transform is MatrixTransform transform6)
  203. return new MatrixTransform { Matrix = transform6.Matrix };
  204. if (!(transform is TransformGroup group))
  205. return null;
  206. var group2 = new TransformGroup();
  207. foreach (var transform12 in group.Children)
  208. group2.Children.Add(CloneTransform(transform12));
  209. return group2;
  210. }
  211. internal void EndDrag()
  212. {
  213. AssociatedObject.MouseMove -= OnMouseMove;
  214. AssociatedObject.LostMouseCapture -= OnLostMouseCapture;
  215. AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonUpEvent,
  216. new MouseButtonEventHandler(OnMouseLeftButtonUp));
  217. }
  218. private static Point GetTransformOffset(GeneralTransform transform)
  219. {
  220. return transform.Transform(new Point(0.0, 0.0));
  221. }
  222. internal void HandleDrag(Point newPositionInElementCoordinates)
  223. {
  224. var x = newPositionInElementCoordinates.X - _relativePosition.X;
  225. var y = newPositionInElementCoordinates.Y - _relativePosition.Y;
  226. var point = TransformAsVector(AssociatedObject.TransformToVisual(RootElement), x, y);
  227. _settingPosition = true;
  228. ApplyTranslation(point.X, point.Y);
  229. UpdatePosition();
  230. _settingPosition = false;
  231. }
  232. protected override void OnAttached()
  233. {
  234. AssociatedObject.AddHandler(UIElement.MouseLeftButtonDownEvent,
  235. new MouseButtonEventHandler(OnMouseLeftButtonDown), false);
  236. }
  237. private static void OnConstrainToParentBoundsChanged(object sender, DependencyPropertyChangedEventArgs args)
  238. {
  239. var behavior = (MouseDragElementBehavior) sender;
  240. behavior.UpdatePosition(new Point(behavior.X, behavior.Y));
  241. }
  242. protected override void OnDetaching()
  243. {
  244. AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonDownEvent,
  245. new MouseButtonEventHandler(OnMouseLeftButtonDown));
  246. }
  247. private void OnLostMouseCapture(object sender, MouseEventArgs e)
  248. {
  249. EndDrag();
  250. DragFinished?.Invoke(this, e);
  251. }
  252. private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  253. {
  254. StartDrag(e.GetPosition(AssociatedObject));
  255. DragBegun?.Invoke(this, e);
  256. }
  257. private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  258. {
  259. AssociatedObject.ReleaseMouseCapture();
  260. }
  261. private void OnMouseMove(object sender, MouseEventArgs e)
  262. {
  263. HandleDrag(e.GetPosition(AssociatedObject));
  264. Dragging?.Invoke(this, e);
  265. }
  266. private static void OnXChanged(object sender, DependencyPropertyChangedEventArgs args)
  267. {
  268. var behavior = (MouseDragElementBehavior) sender;
  269. behavior.UpdatePosition(new Point((double) args.NewValue, behavior.Y));
  270. }
  271. private static void OnYChanged(object sender, DependencyPropertyChangedEventArgs args)
  272. {
  273. var behavior = (MouseDragElementBehavior) sender;
  274. behavior.UpdatePosition(new Point(behavior.X, (double) args.NewValue));
  275. }
  276. private static bool RectContainsRect(Rect rect1, Rect rect2)
  277. {
  278. if (rect1.IsEmpty || rect2.IsEmpty)
  279. return false;
  280. return rect1.X <= rect2.X && rect1.Y <= rect2.Y && rect1.X + rect1.Width >= rect2.X + rect2.Width &&
  281. rect1.Y + rect1.Height >= rect2.Y + rect2.Height;
  282. }
  283. internal void StartDrag(Point positionInElementCoordinates)
  284. {
  285. _relativePosition = positionInElementCoordinates;
  286. AssociatedObject.CaptureMouse();
  287. AssociatedObject.MouseMove += OnMouseMove;
  288. AssociatedObject.LostMouseCapture += OnLostMouseCapture;
  289. AssociatedObject.AddHandler(UIElement.MouseLeftButtonUpEvent,
  290. new MouseButtonEventHandler(OnMouseLeftButtonUp), false);
  291. }
  292. private static Point TransformAsVector(GeneralTransform transform, double x, double y)
  293. {
  294. var point = transform.Transform(new Point(0.0, 0.0));
  295. var point2 = transform.Transform(new Point(x, y));
  296. return new Point(point2.X - point.X, point2.Y - point.Y);
  297. }
  298. private void UpdatePosition()
  299. {
  300. var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement));
  301. X = transformOffset.X;
  302. Y = transformOffset.Y;
  303. }
  304. private void UpdatePosition(Point point)
  305. {
  306. if (!_settingPosition && AssociatedObject != null)
  307. {
  308. var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement));
  309. var x = double.IsNaN(point.X) ? 0.0 : point.X - transformOffset.X;
  310. var y = double.IsNaN(point.Y) ? 0.0 : point.Y - transformOffset.Y;
  311. ApplyTranslation(x, y);
  312. }
  313. }
  314. }