终端一体化运控平台
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 

224 рядки
7.0 KiB

  1. using Microsoft.Xaml.Behaviors;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Windows.Media;
  8. using System.Windows.Shapes;
  9. using System.Windows;
  10. using BPA.Helper;
  11. using System.Windows.Media.Animation;
  12. namespace BPASmartClient.CustomResource.UserControls
  13. {
  14. public class EllipseProgressBehavior : Behavior<Ellipse>
  15. {
  16. /// <summary>
  17. /// 标识 EndAngle 依赖属性。
  18. /// </summary>
  19. public static readonly DependencyProperty EndAngleProperty =
  20. DependencyProperty.Register(nameof(EndAngle), typeof(double), typeof(EllipseProgressBehavior),
  21. new PropertyMetadata(default(double), OnEndAngleChanged));
  22. /// <summary>
  23. /// 标识 Progress 依赖属性。
  24. /// </summary>
  25. public static readonly DependencyProperty ProgressProperty =
  26. DependencyProperty.Register("Progress", typeof(double), typeof(EllipseProgressBehavior),
  27. new PropertyMetadata(0d, OnProgressChanged));
  28. /// <summary>
  29. /// 标识 StartAngle 依赖属性。
  30. /// </summary>
  31. public static readonly DependencyProperty StartAngleProperty =
  32. DependencyProperty.Register(nameof(StartAngle), typeof(double), typeof(EllipseProgressBehavior),
  33. new PropertyMetadata(default(double), OnStartAngleChanged));
  34. private double _normalizedMaxAngle;
  35. private double _normalizedMinAngle;
  36. /// <summary>
  37. /// 获取或设置EndAngle的值
  38. /// </summary>
  39. public double EndAngle
  40. {
  41. get => (double)GetValue(EndAngleProperty);
  42. set => SetValue(EndAngleProperty, value);
  43. }
  44. /// <summary>
  45. /// 获取或设置Progress的值
  46. /// </summary>
  47. public double Progress
  48. {
  49. get => (double)GetValue(ProgressProperty);
  50. set => SetValue(ProgressProperty, value);
  51. }
  52. /// <summary>
  53. /// 获取或设置StartAngle的值
  54. /// </summary>
  55. public double StartAngle
  56. {
  57. get => (double)GetValue(StartAngleProperty);
  58. set => SetValue(StartAngleProperty, value);
  59. }
  60. protected virtual double GetTotalLength()
  61. {
  62. if (AssociatedObject == null || AssociatedObject.ActualHeight == 0)
  63. {
  64. return 0;
  65. }
  66. return (AssociatedObject.ActualHeight - AssociatedObject.StrokeThickness) * Math.PI *
  67. (_normalizedMaxAngle - _normalizedMinAngle) / 360;
  68. }
  69. protected override void OnAttached()
  70. {
  71. base.OnAttached();
  72. UpdateAngle();
  73. UpdateStrokeDashArray();
  74. AssociatedObject.SizeChanged += (s, e) => { UpdateStrokeDashArray(); };
  75. }
  76. /// <summary>
  77. /// EndAngle 属性更改时调用此方法。
  78. /// </summary>
  79. /// <param name="oldValue">EndAngle 属性的旧值。</param>
  80. /// <param name="newValue">EndAngle 属性的新值。</param>
  81. protected virtual void OnEndAngleChanged(double oldValue, double newValue)
  82. {
  83. UpdateAngle();
  84. UpdateStrokeDashArray();
  85. }
  86. protected virtual void OnProgressChanged(double oldValue, double newValue) => UpdateStrokeDashArray();
  87. /// <summary>
  88. /// StartAngle 属性更改时调用此方法。
  89. /// </summary>
  90. /// <param name="oldValue">StartAngle 属性的旧值。</param>
  91. /// <param name="newValue">StartAngle 属性的新值。</param>
  92. protected virtual void OnStartAngleChanged(double oldValue, double newValue)
  93. {
  94. UpdateAngle();
  95. UpdateStrokeDashArray();
  96. }
  97. private static double Mod(double number, double divider)
  98. {
  99. var result = number % divider;
  100. result = result < 0 ? result + divider : result;
  101. return result;
  102. }
  103. private static void OnEndAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
  104. {
  105. var oldValue = (double)args.OldValue;
  106. var newValue = (double)args.NewValue;
  107. if (oldValue == newValue)
  108. {
  109. return;
  110. }
  111. var target = obj as EllipseProgressBehavior;
  112. target?.OnEndAngleChanged(oldValue, newValue);
  113. }
  114. private static void OnProgressChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
  115. {
  116. var target = obj as EllipseProgressBehavior;
  117. var oldValue = (double)args.OldValue;
  118. var newValue = (double)args.NewValue;
  119. if (oldValue != newValue)
  120. {
  121. target.OnProgressChanged(oldValue, newValue);
  122. }
  123. }
  124. private static void OnStartAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
  125. {
  126. var oldValue = (double)args.OldValue;
  127. var newValue = (double)args.NewValue;
  128. if (oldValue == newValue)
  129. {
  130. return;
  131. }
  132. var target = obj as EllipseProgressBehavior;
  133. target?.OnStartAngleChanged(oldValue, newValue);
  134. }
  135. private void UpdateAngle()
  136. {
  137. UpdateNormalizedAngles();
  138. if (AssociatedObject == null)
  139. {
  140. return;
  141. }
  142. AssociatedObject.RenderTransformOrigin = new Point(0.5, 0.5);
  143. if (AssociatedObject.RenderTransform is RotateTransform transform)
  144. {
  145. transform.Angle = _normalizedMinAngle - 90;
  146. }
  147. else
  148. {
  149. AssociatedObject.RenderTransform = new RotateTransform { Angle = _normalizedMinAngle - 90 };
  150. }
  151. }
  152. private void UpdateNormalizedAngles()
  153. {
  154. var result = Mod(StartAngle, 360);
  155. if (result >= 180)
  156. {
  157. result -= 360;
  158. }
  159. _normalizedMinAngle = result;
  160. result = Mod(EndAngle, 360);
  161. if (result < 180)
  162. {
  163. result += 360;
  164. }
  165. if (result > _normalizedMinAngle + 360)
  166. {
  167. result -= 360;
  168. }
  169. _normalizedMaxAngle = result;
  170. }
  171. private void UpdateStrokeDashArray()
  172. {
  173. if (AssociatedObject == null || AssociatedObject.StrokeThickness == 0)
  174. {
  175. return;
  176. }
  177. //if (target.ActualHeight == 0 || target.ActualWidth == 0)
  178. // return;
  179. var totalLength = GetTotalLength();
  180. if (totalLength == 0)
  181. {
  182. return;
  183. }
  184. totalLength /= AssociatedObject.StrokeThickness;
  185. var progressLenth = Progress * totalLength / 100;
  186. var result = new DoubleCollection { progressLenth, double.MaxValue };
  187. AssociatedObject.StrokeDashArray = result;
  188. }
  189. }
  190. }