Dashboard.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using System.Collections.Generic;
  5. using Microsoft.Expression.Shapes;
  6. using System.Windows.Media;
  7. using System.Windows.Media.Animation;
  8. namespace CustomUI
  9. {
  10. /// <summary>
  11. /// 刻度盘控件
  12. /// </summary>
  13. [TemplatePart(Name = "PART_IncreaseCircle", Type = typeof(Arc))]
  14. public class Dashboard : Control
  15. {
  16. private Arc PART_IncreaseCircle;
  17. /// <summary>
  18. /// 保存角度变化前的角度值(用于动画)
  19. /// </summary>
  20. private double OldAngle;
  21. #region Constructors
  22. static Dashboard()
  23. {
  24. DefaultStyleKeyProperty.OverrideMetadata(typeof(Dashboard), new FrameworkPropertyMetadata(typeof(Dashboard)));
  25. }
  26. #endregion
  27. #region 依赖属性
  28. #region Angle 刻度盘起始角度
  29. /// <summary>
  30. /// 刻度盘起始角度依赖属性
  31. /// </summary>
  32. public static readonly DependencyProperty StartAngleProperty =
  33. DependencyProperty.Register(
  34. "StartAngle",
  35. typeof(double),
  36. typeof(Dashboard),
  37. new PropertyMetadata(0d));
  38. /// <summary>
  39. /// 刻度盘起始角度
  40. /// </summary>
  41. public double StartAngle
  42. {
  43. get { return (double)GetValue(StartAngleProperty); }
  44. set { SetValue(StartAngleProperty, value); }
  45. }
  46. #endregion
  47. #region Angle 刻度盘结束角度依赖属性
  48. /// <summary>
  49. /// 刻度盘结束角度依赖属性
  50. /// </summary>
  51. public static readonly DependencyProperty EndAngleProperty =
  52. DependencyProperty.Register(
  53. "EndAngle",
  54. typeof(double),
  55. typeof(Dashboard),
  56. new PropertyMetadata(0d));
  57. /// <summary>
  58. /// 刻度盘结束角度依赖属性
  59. /// </summary>
  60. public double EndAngle
  61. {
  62. get { return (double)GetValue(EndAngleProperty); }
  63. set { SetValue(EndAngleProperty, value); }
  64. }
  65. #endregion
  66. #region Minimum 最小值
  67. /// <summary>
  68. /// 最小值依赖属性,用于Binding
  69. /// </summary>
  70. public static readonly DependencyProperty MinimumProperty =
  71. DependencyProperty.Register(
  72. "Minimum",
  73. typeof(double),
  74. typeof(Dashboard),
  75. new PropertyMetadata(0.0));
  76. /// <summary>
  77. /// 获取或设置最小值.
  78. /// </summary>
  79. /// <value>最小值.</value>
  80. public double Minimum
  81. {
  82. get { return (double)GetValue(MinimumProperty); }
  83. set { SetValue(MinimumProperty, value); }
  84. }
  85. #endregion
  86. #region Maximum 最大值
  87. /// <summary>
  88. /// 最大值依赖属性,用于Binding
  89. /// </summary>
  90. public static readonly DependencyProperty MaximumProperty =
  91. DependencyProperty.Register(
  92. "Maximum",
  93. typeof(double),
  94. typeof(Dashboard),
  95. new PropertyMetadata(300.0));
  96. /// <summary>
  97. /// 获取或设置最大值.
  98. /// </summary>
  99. /// <value>最大值.</value>
  100. public double Maximum
  101. {
  102. get { return (double)GetValue(MaximumProperty); }
  103. set { SetValue(MaximumProperty, value); }
  104. }
  105. #endregion
  106. #region Value 当前值
  107. /// <summary>
  108. /// 最大值依赖属性,用于Binding
  109. /// </summary>
  110. public static readonly DependencyProperty ValueProperty =
  111. DependencyProperty.Register(
  112. "Value",
  113. typeof(double),
  114. typeof(Dashboard),
  115. new PropertyMetadata(0.0, new PropertyChangedCallback(OnValuePropertyChanged)));
  116. /// <summary>
  117. /// 获取或设置当前值
  118. /// </summary>
  119. public double Value
  120. {
  121. get { return (double)GetValue(ValueProperty); }
  122. set { SetValue(ValueProperty, value); }
  123. }
  124. private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  125. {
  126. Dashboard dashboard = d as Dashboard;
  127. dashboard.OldAngle = dashboard.Angle;
  128. dashboard.SetAngle();
  129. dashboard.TransformAngle();
  130. }
  131. #endregion
  132. #region LongTickCount 长刻度个数
  133. public static readonly DependencyProperty LongTickCountProperty =
  134. DependencyProperty.Register(
  135. "LongTickCount",
  136. typeof(int),
  137. typeof(Dashboard),
  138. new PropertyMetadata(10));
  139. /// <summary>
  140. /// 获取或设置长刻度个数,用于设置刻度盘显示几个长刻度
  141. /// </summary>
  142. public int LongTickCount
  143. {
  144. get { return (int)GetValue(LongTickCountProperty); }
  145. set { SetValue(LongTickCountProperty, value); }
  146. }
  147. #endregion
  148. #region ShortTickCount 短刻度个数
  149. public static readonly DependencyProperty ShortTickCountProperty =
  150. DependencyProperty.Register(
  151. "ShortTickCount",
  152. typeof(int),
  153. typeof(Dashboard),
  154. new PropertyMetadata(3));
  155. /// <summary>
  156. /// 获取或设置两个长刻度之间的短刻度的个数
  157. /// </summary>
  158. public int ShortTickCount
  159. {
  160. get { return (int)GetValue(ShortTickCountProperty); }
  161. set { SetValue(ShortTickCountProperty, value); }
  162. }
  163. #endregion
  164. #region TickDurtion 刻度改变时的动画显示时长
  165. public static readonly DependencyProperty TickDurtionProperty = DependencyProperty.Register("TickDurtion"
  166. , typeof(Duration)
  167. , typeof(Dashboard),
  168. new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(400))));
  169. /// <summary>
  170. /// 刻度改变时的动画显示时长
  171. /// </summary>
  172. public Duration TickDurtion
  173. {
  174. get { return (Duration)GetValue(TickDurtionProperty); }
  175. set { SetValue(TickDurtionProperty, value); }
  176. }
  177. #endregion
  178. #region Skin 刻度盘样式
  179. public static readonly DependencyProperty SkinProperty = DependencyProperty.Register("Skin",
  180. typeof(DashboardSkinEnum),
  181. typeof(Dashboard),
  182. new PropertyMetadata(DashboardSkinEnum.Speed));
  183. /// <summary>
  184. /// 刻度盘样式
  185. /// </summary>
  186. public DashboardSkinEnum Skin
  187. {
  188. get { return (DashboardSkinEnum)GetValue(SkinProperty); }
  189. set { SetValue(SkinProperty, value); }
  190. }
  191. #endregion
  192. #region ShortTicksBrush 短刻度颜色
  193. public static readonly DependencyProperty ShortTicksBrushProperty = DependencyProperty.Register("ShortTicksBrush"
  194. , typeof(Brush)
  195. , typeof(Dashboard));
  196. /// <summary>
  197. /// 短刻度颜色
  198. /// </summary>
  199. public Brush ShortTicksBrush
  200. {
  201. get { return (Brush)GetValue(ShortTicksBrushProperty); }
  202. set { SetValue(ShortTicksBrushProperty, value); }
  203. }
  204. #endregion
  205. #region LongTicksBrush 长刻度颜色
  206. public static readonly DependencyProperty LongTicksBrushProperty = DependencyProperty.Register("LongTicksBrush"
  207. , typeof(Brush)
  208. , typeof(Dashboard));
  209. /// <summary>
  210. /// 长刻度颜色
  211. /// </summary>
  212. public Brush LongTicksBrush
  213. {
  214. get { return (Brush)GetValue(LongTicksBrushProperty); }
  215. set { SetValue(LongTicksBrushProperty, value); }
  216. }
  217. #endregion
  218. #region Content
  219. public object Content
  220. {
  221. get { return (object)GetValue(ContentProperty); }
  222. set { SetValue(ContentProperty, value); }
  223. }
  224. public static readonly DependencyProperty ContentProperty =
  225. DependencyProperty.Register("Content", typeof(object), typeof(Dashboard));
  226. #endregion
  227. #region ContentTemplate
  228. public DataTemplate ContentTemplate
  229. {
  230. get { return (DataTemplate)GetValue(ContentTemplateProperty); }
  231. set { SetValue(ContentTemplateProperty, value); }
  232. }
  233. public static readonly DependencyProperty ContentTemplateProperty =
  234. DependencyProperty.Register("ContentTemplate", typeof(DataTemplate), typeof(Dashboard));
  235. #endregion
  236. #endregion
  237. #region Private依赖属性
  238. #region Angle 刻度盘当前值所对应的角度
  239. /// <summary>
  240. /// 刻度盘当前值所对应的角度依赖属性
  241. /// </summary>
  242. public static readonly DependencyProperty AngleProperty =
  243. DependencyProperty.Register(
  244. "Angle",
  245. typeof(double),
  246. typeof(Dashboard),
  247. new PropertyMetadata(0d));
  248. /// <summary>
  249. /// 刻度盘当前值所对应的角度
  250. /// </summary>
  251. public double Angle
  252. {
  253. get { return (double)GetValue(AngleProperty); }
  254. private set { SetValue(AngleProperty, value); }
  255. }
  256. #endregion
  257. #region ShortTicks 短刻度线集合
  258. /// <summary>
  259. /// 短刻度线依赖属性,用于Binding
  260. /// </summary>
  261. public static readonly DependencyProperty ShortTicksProperty =
  262. DependencyProperty.Register(
  263. "ShortTicks",
  264. typeof(IList<object>),
  265. typeof(Dashboard),
  266. new PropertyMetadata(null));
  267. /// <summary>
  268. /// 获取或设置短刻度线,用于绑定PathListBox的ItemsSource
  269. /// </summary>
  270. /// <value>短刻度线.</value>
  271. public IList<object> ShortTicks
  272. {
  273. get { return (IList<object>)GetValue(ShortTicksProperty); }
  274. private set { SetValue(ShortTicksProperty, value); }
  275. }
  276. #endregion
  277. #region LongTicks 长刻度线集合
  278. /// <summary>
  279. /// 长刻度线依赖属性,用于Binding
  280. /// </summary>
  281. public static readonly DependencyProperty LongTicksProperty =
  282. DependencyProperty.Register(
  283. "LongTicks",
  284. typeof(IList<object>),
  285. typeof(Dashboard),
  286. new PropertyMetadata(null));
  287. /// <summary>
  288. /// 获取或设置长刻度线,用于绑定PathListBox的ItemsSource
  289. /// </summary>
  290. /// <value>长刻度线.</value>
  291. public IList<object> LongTicks
  292. {
  293. get { return (IList<object>)GetValue(LongTicksProperty); }
  294. private set { SetValue(LongTicksProperty, value); }
  295. }
  296. #endregion
  297. #region LongTicks 长刻度线上显示的数字
  298. /// <summary>
  299. /// 长刻度线依赖属性,用于Binding
  300. /// </summary>
  301. public static readonly DependencyProperty NumberListProperty =
  302. DependencyProperty.Register(
  303. "NumberList",
  304. typeof(IList<object>),
  305. typeof(Dashboard),
  306. new PropertyMetadata(null));
  307. /// <summary>
  308. /// 获取或设置长刻度线,用于绑定PathListBox的ItemsSource
  309. /// </summary>
  310. /// <value>长刻度线.</value>
  311. public IList<object> NumberList
  312. {
  313. get { return (IList<object>)GetValue(NumberListProperty); }
  314. private set { SetValue(NumberListProperty, value); }
  315. }
  316. #endregion
  317. #endregion
  318. #region 重载
  319. public override void OnApplyTemplate()
  320. {
  321. base.OnApplyTemplate();
  322. this.PART_IncreaseCircle = GetTemplateChild("PART_IncreaseCircle") as Arc;
  323. this.SetTicks();
  324. this.SetAngle();
  325. this.TransformAngle();
  326. }
  327. #endregion
  328. #region Private方法
  329. /// <summary>
  330. /// 设置刻度线
  331. /// </summary>
  332. private void SetTicks()
  333. {
  334. List<object> numbers = new List<object>();
  335. List<object> shortticks = new List<object>();
  336. List<object> longticks = new List<object>();
  337. for (int i = 0; i < this.LongTickCount; i++)
  338. {
  339. numbers.Add(Math.Round(this.Minimum + (this.Maximum - this.Minimum) / (this.LongTickCount - 1) * i));
  340. longticks.Add(new object());
  341. }
  342. for (int i = 0; i < (this.LongTickCount - 1) * (this.ShortTickCount + 1) + 1; i++)
  343. {
  344. shortticks.Add(new object());
  345. }
  346. this.ShortTicks = shortticks;
  347. this.LongTicks = longticks;
  348. this.NumberList = numbers;
  349. }
  350. /// <summary>
  351. /// 根据当前值设置圆弧的EndAngle
  352. /// </summary>
  353. private void SetAngle()
  354. {
  355. if(this.Value < this.Minimum)
  356. {
  357. this.Angle = this.StartAngle;
  358. return;
  359. }
  360. if(this.Value > this.Maximum)
  361. {
  362. this.Angle = this.EndAngle;
  363. return;
  364. }
  365. var diff = this.Maximum - this.Minimum;
  366. var valueDiff = this.Value - this.Minimum;
  367. this.Angle = this.StartAngle + (this.EndAngle - this.StartAngle) / diff * valueDiff;
  368. }
  369. /// <summary>
  370. /// 角度值变化动画
  371. /// </summary>
  372. private void TransformAngle()
  373. {
  374. if (this.PART_IncreaseCircle != null)
  375. {
  376. DoubleAnimation doubleAnimation = new DoubleAnimation(this.OldAngle, this.Angle, this.TickDurtion);
  377. this.PART_IncreaseCircle.BeginAnimation(Arc.EndAngleProperty, doubleAnimation);
  378. }
  379. }
  380. #endregion
  381. }
  382. }