using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Animation; using System.Windows.Media; using System.Windows.Shapes; using HandyControl.Expression.Shapes; namespace HandyControl.Controls { public class Dashboard : System.Windows.Controls.Control { public const string ArcName = "arckd"; public const string ValueTxtName = "valueTxt"; public const string CanvasName = "canvasPlate"; public const string ZZRotateName = "rtPointer"; private static double StartAngle = -135.5; static Dashboard() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Dashboard), new FrameworkPropertyMetadata(typeof(Dashboard))); } Arc arckd; TextBlock valueTxt; Canvas canvasPlate; RotateTransform rtPointer; public override void OnApplyTemplate() { base.OnApplyTemplate(); if (arckd == null) arckd = GetTemplateChild(ArcName) as Arc; if (valueTxt == null) valueTxt = GetTemplateChild(ValueTxtName) as TextBlock; if (canvasPlate == null) canvasPlate = GetTemplateChild(CanvasName) as Canvas; if (rtPointer == null) rtPointer = GetTemplateChild(ZZRotateName) as RotateTransform; DrawScale(); DrawAngle(); arckd.EndAngle = StartAngle + (-StartAngle * 2d) * ((double)Value / Maximum); valueTxt.Text = Value.ToString(); } public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(Dashboard), new PropertyMetadata(default(double), new PropertyChangedCallback(OnValuePropertyChanged))); public double Minimum { get { return (double)GetValue(MinimumProperty); } set { SetValue(MinimumProperty, value); } } public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(Dashboard), new PropertyMetadata(double.NaN, new PropertyChangedCallback(OnPropertyChanged))); public double Maximum { get { return (double)GetValue(MaximumProperty); } set { SetValue(MaximumProperty, value); } } public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(Dashboard), new PropertyMetadata(double.NaN, new PropertyChangedCallback(OnPropertyChanged))); public Brush PlateBackground { get { return (Brush)GetValue(PlateBackgroundProperty); } set { SetValue(PlateBackgroundProperty, value); } } public static readonly DependencyProperty PlateBackgroundProperty = DependencyProperty.Register("PlateBackground", typeof(Brush), typeof(Dashboard), null); public string Unit { get { return (string)GetValue(UnitProperty); } set { SetValue(UnitProperty, value); } } // Using a DependencyProperty as the backing store for Unit. This enables animation, styling, binding, etc... public static readonly DependencyProperty UnitProperty = DependencyProperty.Register("Unit", typeof(string), typeof(Dashboard), new PropertyMetadata("km/h")); public Brush PlateBorderBrush { get { return (Brush)GetValue(PlateBorderBrushProperty); } set { SetValue(PlateBorderBrushProperty, value); } } public static readonly DependencyProperty PlateBorderBrushProperty = DependencyProperty.Register("PlateBorderBrush", typeof(Brush), typeof(Dashboard), null); public Thickness PlateBorderThickness { get { return (Thickness)GetValue(PlateBorderThicknessProperty); } set { SetValue(PlateBorderThicknessProperty, value); } } public static readonly DependencyProperty PlateBorderThicknessProperty = DependencyProperty.Register("PlateBorderThickness", typeof(Thickness), typeof(Dashboard), null); public static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as Dashboard).DrawScale(); } public static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Dashboard dashboard = d as Dashboard; dashboard.DrawAngle(); if (dashboard.arckd == null) return; dashboard.arckd.EndAngle = StartAngle + (-StartAngle * 2d) * ((double)dashboard.Value / dashboard.Maximum); dashboard.valueTxt.Text = dashboard.Value.ToString(); } /// /// 画表盘的刻度 /// private void DrawScale() { if (this.canvasPlate == null) return; this.canvasPlate.Children.Clear(); for (double i = 0; i <= this.Maximum - this.Minimum; i++) { //添加刻度线 Line lineScale = new Line(); if (i % 10 == 0) { //注意Math.Cos和Math.Sin的参数是弧度,记得将角度转为弧度制 lineScale.X1 = 200 - 170 * Math.Cos(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180); lineScale.Y1 = 200 - 170 * Math.Sin(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180); lineScale.Stroke = new SolidColorBrush(Colors.White); lineScale.StrokeThickness = 2; //添加刻度值 TextBlock txtScale = new TextBlock(); txtScale.Text = (i + this.Minimum).ToString(); txtScale.Width = 34; txtScale.TextAlignment = TextAlignment.Center; txtScale.Foreground = new SolidColorBrush(Colors.White); txtScale.RenderTransform = new RotateTransform() { Angle = 45, CenterX = 17, CenterY = 8 }; txtScale.FontSize = 18; Canvas.SetLeft(txtScale, 200 - 155 * Math.Cos(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180) - 17); Canvas.SetTop(txtScale, 200 - 155 * Math.Sin(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180) - 10); this.canvasPlate.Children.Add(txtScale); } else { lineScale.X1 = 200 - 180 * Math.Cos(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180); lineScale.Y1 = 200 - 180 * Math.Sin(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180); lineScale.Stroke = new SolidColorBrush(Colors.White); lineScale.StrokeThickness = 1; lineScale.Opacity = 0.5; } lineScale.X2 = 200 - 190 * Math.Cos(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180); lineScale.Y2 = 200 - 190 * Math.Sin(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180); this.canvasPlate.Children.Add(lineScale); } } private void DrawAngle() { if (rtPointer == null) return; double step = 270.0 / (this.Maximum - this.Minimum); DoubleAnimation da = new DoubleAnimation(this.Value * step - 45, new Duration(TimeSpan.FromMilliseconds(200))); this.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da); } } }