MouseDragElementBehaviorEx.cs 13 KB

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