终端一体化运控平台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

308 lines
12 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Data;
  10. using System.Windows.Documents;
  11. using System.Windows.Input;
  12. using System.Windows.Media;
  13. using System.Windows.Media.Animation;
  14. using System.Windows.Media.Imaging;
  15. using System.Windows.Navigation;
  16. using System.Windows.Shapes;
  17. namespace BPASmartClient.CustomResource.UserControls
  18. {
  19. /// <summary>
  20. /// Instrument.xaml 的交互逻辑
  21. /// </summary>
  22. public partial class Instrument : UserControl
  23. {
  24. static bool ValueRefreshFlag = false;//值刷新标志
  25. #region 给仪表盘定义依赖属性
  26. #region Value:当前值 依赖属性
  27. //定义一个包装器
  28. /// <summary>
  29. /// 当前值
  30. /// </summary>
  31. public float Value
  32. {
  33. get { return (float)this.GetValue(ValueProperty); }
  34. set { this.SetValue(ValueProperty, value); }
  35. }
  36. //定义一个依赖属性 Register有三个参数,第一个是该属性的名称,第二个是该属性接受什么类型的数据,第三个是该属性属于哪个对象
  37. public static readonly DependencyProperty ValueProperty =
  38. DependencyProperty.Register("Value", typeof(float), typeof(Instrument),
  39. new PropertyMetadata(0.0f, new PropertyChangedCallback((d, e) =>
  40. {
  41. if (ValueRefreshFlag) (d as Instrument).ValueRefresh();
  42. else (d as Instrument).Refresh();
  43. })));
  44. //当 Value 的值更改的时候调用该委托
  45. public static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  46. {
  47. (d as Instrument).Refresh();
  48. }
  49. #endregion
  50. #region Minimum:最小值 依赖属性
  51. /// <summary>
  52. /// 最小值
  53. /// </summary>
  54. public float Minimum
  55. {
  56. get { return (float)GetValue(MinimumProperty); }
  57. set { SetValue(MinimumProperty, value); }
  58. }
  59. public static readonly DependencyProperty MinimumProperty =
  60. DependencyProperty.Register("Minimum", typeof(float), typeof(Instrument),
  61. new PropertyMetadata(0.0f, new PropertyChangedCallback(OnPropertyChanged)));
  62. #endregion
  63. #region Maximum:最大值 依赖属性
  64. /// <summary>
  65. /// 最大值
  66. /// </summary>
  67. public float Maximum
  68. {
  69. get { return (float)GetValue(MaximumProperty); }
  70. set { SetValue(MaximumProperty, value); }
  71. }
  72. public static readonly DependencyProperty MaximumProperty =
  73. DependencyProperty.Register("Maximum", typeof(float), typeof(Instrument),
  74. new PropertyMetadata(100.0f, new PropertyChangedCallback(OnPropertyChanged)));
  75. #endregion
  76. #region Interval:分段间隔数 依赖属性
  77. /// <summary>
  78. /// 分段间隔数
  79. /// </summary>
  80. public int Interval
  81. {
  82. get { return (int)GetValue(IntervalProperty); }
  83. set { SetValue(IntervalProperty, value); }
  84. }
  85. public static readonly DependencyProperty IntervalProperty =
  86. DependencyProperty.Register("Interval", typeof(int), typeof(Instrument),
  87. new PropertyMetadata(10, new PropertyChangedCallback(OnPropertyChanged)));
  88. #endregion
  89. #region PlateBackground:仪表背景色 依赖属性
  90. /// <summary>
  91. /// 仪表背景色
  92. /// </summary>
  93. public Brush PlateBackground
  94. {
  95. get { return (Brush)GetValue(PlateBackgroundProperty); }
  96. set { SetValue(PlateBackgroundProperty, value); }
  97. }
  98. public static readonly DependencyProperty PlateBackgroundProperty =
  99. DependencyProperty.Register("PlateBackground", typeof(Brush), typeof(Instrument), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(60, 60, 60))));
  100. #endregion
  101. #region ScaleTextSize:数值大小 依赖属性
  102. /// <summary>
  103. /// 数值大小
  104. /// </summary>
  105. public int ScaleTextSize
  106. {
  107. get { return (int)GetValue(ScaleTextSizeProperty); }
  108. set { SetValue(ScaleTextSizeProperty, value); }
  109. }
  110. public static readonly DependencyProperty ScaleTextSizeProperty =
  111. DependencyProperty.Register("ScaleTextSize", typeof(int), typeof(Instrument),
  112. new PropertyMetadata(14, new PropertyChangedCallback(OnPropertyChanged)));
  113. #endregion
  114. #region ScaleBrush:数值刻度颜色 依赖属性
  115. /// <summary>
  116. /// 数值刻度颜色
  117. /// </summary>
  118. public Brush ScaleBrush
  119. {
  120. get { return (Brush)GetValue(ScaleBrushProperty); }
  121. set { SetValue(ScaleBrushProperty, value); }
  122. }
  123. public static readonly DependencyProperty ScaleBrushProperty =
  124. DependencyProperty.Register("ScaleBrush", typeof(Brush), typeof(Instrument),
  125. new PropertyMetadata(new SolidColorBrush(Color.FromRgb(3, 182, 200)), new PropertyChangedCallback(OnPropertyChanged)));
  126. #endregion
  127. #region PointerColor:指针颜色 依赖属性
  128. public Brush PointerColor
  129. {
  130. get { return (Brush)GetValue(PointerColorProperty); }
  131. set { SetValue(PointerColorProperty, value); }
  132. }
  133. public static readonly DependencyProperty PointerColorProperty =
  134. DependencyProperty.Register("PointerColor", typeof(Brush), typeof(Instrument),
  135. new PropertyMetadata(new SolidColorBrush(Color.FromRgb(3, 182, 200)), new PropertyChangedCallback(OnPropertyChanged)));
  136. #endregion
  137. #region Unit:单位 依赖属性
  138. public string Unit
  139. {
  140. get { return (string)GetValue(UnitProperty); }
  141. set { SetValue(UnitProperty, value); }
  142. }
  143. public static readonly DependencyProperty UnitProperty =
  144. DependencyProperty.Register("Unit", typeof(string), typeof(Instrument),
  145. new PropertyMetadata("kg", new PropertyChangedCallback(OnPropertyChanged)));
  146. #endregion
  147. #region ScaleBrush:数值刻度颜色 依赖属性
  148. #endregion
  149. #endregion
  150. #region 值刷新
  151. private void ValueRefresh()
  152. {
  153. if (!ValueRefreshFlag) return;
  154. double radius = this.backEllipse.Width / 2;//获取仪表半径
  155. //指针当前值
  156. double step = 270.0 / (this.Maximum - this.Minimum);
  157. //this.rtPointer.Angle = this.Value * step - 45;
  158. double value = double.IsNaN(this.Value) ? 0 : this.Value;
  159. //指针动画显示
  160. DoubleAnimation da = new DoubleAnimation((value - this.Minimum) * step - 45, new Duration(TimeSpan.FromMilliseconds(500)));//指定动画的值
  161. this.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da);//指定动画对象
  162. //指针绘制
  163. string sData = "M{0} {1},{1} {2},{1} {3}";
  164. sData = string.Format(sData, radius * 0.3, radius, radius - 5, radius + 5);
  165. var converter = TypeDescriptor.GetConverter(typeof(Geometry));
  166. Task.Run(new Action(() =>
  167. {
  168. Application.Current.Dispatcher.Invoke(new Action(() =>
  169. {
  170. this.pointer.Data = (Geometry)converter.ConvertFrom(sData);
  171. }));
  172. }));
  173. }
  174. #endregion
  175. #region 外观刷新
  176. private void Refresh()
  177. {
  178. double radius = this.backEllipse.Width / 2;//获取仪表半径
  179. if (double.IsNaN(radius)) return;
  180. if (this.Value < this.Minimum) return;
  181. if (this.Value > this.Maximum) return;
  182. this.mainCanvas.Children.Clear();//清空仪表画布
  183. double step = 270.0 / (this.Maximum - this.Minimum);//获取大刻度的角度
  184. //小刻度绘制
  185. for (int i = 0; i < this.Maximum - this.Minimum; i++)
  186. {
  187. Line lineScale = new Line();
  188. //接近圆心的点的坐标
  189. lineScale.X1 = radius - (radius - 13) * Math.Cos((i * step - 45) * Math.PI / 180);
  190. lineScale.Y1 = radius - (radius - 13) * Math.Sin((i * step - 45) * Math.PI / 180);
  191. //接近边框的点的坐标
  192. lineScale.X2 = radius - (radius - 8) * Math.Cos((i * step - 45) * Math.PI / 180);
  193. lineScale.Y2 = radius - (radius - 8) * Math.Sin((i * step - 45) * Math.PI / 180);
  194. lineScale.Stroke = this.ScaleBrush;//设置线条颜色
  195. lineScale.StrokeThickness = 1;//设置线条厚度
  196. this.mainCanvas.Children.Add(lineScale);
  197. }
  198. //大刻度绘制
  199. step = 270.0 / Interval;
  200. int TextScale = (int)this.Minimum;
  201. for (int i = 0; i <= Interval; i++)
  202. {
  203. Line lineScale = new Line();
  204. //接近圆心的点的坐标
  205. lineScale.X1 = radius - (radius - 20) * Math.Cos((i * step - 45) * Math.PI / 180);
  206. lineScale.Y1 = radius - (radius - 20) * Math.Sin((i * step - 45) * Math.PI / 180);
  207. //接近边框的点的坐标
  208. lineScale.X2 = radius - (radius - 8) * Math.Cos((i * step - 45) * Math.PI / 180);
  209. lineScale.Y2 = radius - (radius - 8) * Math.Sin((i * step - 45) * Math.PI / 180);
  210. lineScale.Stroke = this.ScaleBrush;//设置线条颜色
  211. lineScale.StrokeThickness = 1;//设置线条厚度
  212. this.mainCanvas.Children.Add(lineScale);
  213. //数值设置
  214. TextBlock textScale = new TextBlock();
  215. textScale.Width = 34;
  216. textScale.TextAlignment = TextAlignment.Center;
  217. textScale.FontSize = this.ScaleTextSize;
  218. textScale.Text = Math.Truncate((TextScale + (this.Maximum - this.Minimum) / Interval * i)).ToString();
  219. textScale.Foreground = this.ScaleBrush;
  220. Canvas.SetLeft(textScale, radius - (radius - 36) * Math.Cos((i * step - 45) * Math.PI / 180) - 17);//设置X轴坐标
  221. Canvas.SetTop(textScale, radius - (radius - 36) * Math.Sin((i * step - 45) * Math.PI / 180) - 10);//设置Y轴坐标
  222. this.mainCanvas.Children.Add(textScale);
  223. }
  224. //圆弧绘制
  225. string sData = "M{0} {1} A{0} {0} 0 1 1 {1} {2}";
  226. sData = string.Format(sData, radius / 2, radius, radius * 1.5);
  227. var converter = TypeDescriptor.GetConverter(typeof(Geometry));
  228. this.Circle.Data = (Geometry)converter.ConvertFrom(sData);
  229. ValueRefreshFlag = true;
  230. //指针当前值
  231. //step = 270.0 / (this.Maximum - this.Minimum);
  232. ////this.rtPointer.Angle = this.Value * step - 45;
  233. //double value = double.IsNaN(this.Value) ? 0 : this.Value;
  234. ////指针动画显示
  235. //DoubleAnimation da = new DoubleAnimation((value - this.Minimum) * step - 45, new Duration(TimeSpan.FromMilliseconds(500)));//指定动画的值
  236. //this.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da);//指定动画对象
  237. ////指针绘制
  238. //sData = "M{0} {1},{1} {2},{1} {3}";
  239. //sData = string.Format(sData, radius * 0.3, radius, radius - 5, radius + 5);
  240. //this.pointer.Data = (Geometry)converter.ConvertFrom(sData);
  241. }
  242. #endregion
  243. public Instrument()
  244. {
  245. InitializeComponent();
  246. this.SizeChanged += Instrument_SizeChanged;
  247. this.Loaded += Instrument_Loaded;
  248. }
  249. private void Instrument_Loaded(object sender, RoutedEventArgs e)
  250. {
  251. Refresh();
  252. ValueRefresh();
  253. }
  254. private void Instrument_SizeChanged(object sender, SizeChangedEventArgs e)
  255. {
  256. double minSize = Math.Min(this.RenderSize.Width, this.RenderSize.Height);
  257. this.backEllipse.Width = minSize;
  258. this.backEllipse.Height = minSize;
  259. }
  260. }
  261. }