Silverlight学习笔记十六自定义控件之一个漂亮的Gauge(仪表盘)
我们可以在Silverlight可以自己定义我们需要的控件。这一节是自定义的Gauge控件(仪表)。呵呵翻译的不是很好。
下面是演示效果:
一.自定义控件步骤:
步骤1:CircularGaugeControl用于定义控件的属性
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace CircularGauge
{
/// <summary>
/// 自定义控件-测量仪表(Gauge)
/// </summary>
[TemplatePart(Name = "LayoutRoot", Type = typeof(Grid))]
[TemplatePart(Name = "Pointer", Type = typeof(Path))]
[TemplatePart(Name = "RangeIndicatorLight", Type = typeof(Ellipse))]
[TemplatePart(Name = "PointerCap", Type = typeof(Ellipse))]
public class CircularGaugeControl : Control
{
#region 私有变量
private Grid rootGrid;
private Path rangeIndicator;
private Path pointer;
private Ellipse pointerCap;
private Ellipse lightIndicator;
private bool isInitialValueSet = false;
private Double arcradius1;
private Double arcradius2;
private int animatingSpeedFactor = 6;
#endregion
#region 注入属性
/// <summary>
/// 获取或设置当前属性的值
/// </summary>
public static readonly DependencyProperty CurrentValueProperty =
DependencyProperty.Register("CurrentValue", typeof(double), typeof(CircularGaugeControl),
new PropertyMetadata(Double.MinValue, new PropertyChangedCallback(CircularGaugeControl.OnCurrentValuePropertyChanged)));
/// <summary>
/// 获取或设置当前属性的最小值
/// </summary>
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置当前属性的最大值
/// </summary>
public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置仪表半径的值
/// </summary>
public static readonly DependencyProperty RadiusProperty =
DependencyProperty.Register("Radius", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置指针半径的值
/// </summary>
public static readonly DependencyProperty PointerCapRadiusProperty =
DependencyProperty.Register("PointerCapRadius", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置指针的长度
/// </summary>
public static readonly DependencyProperty PointerLengthProperty =
DependencyProperty.Register("PointerLength", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置刻度的半径
/// </summary>
public static readonly DependencyProperty ScaleRadiusProperty =
DependencyProperty.Register("ScaleRadius", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置刻度的起始角度
/// </summary>
public static readonly DependencyProperty ScaleStartAngleProperty =
DependencyProperty.Register("ScaleStartAngle", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置刻度的摆动角度
/// </summary>
public static readonly DependencyProperty ScaleSweepAngleProperty =
DependencyProperty.Register("ScaleSweepAngle", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置主要的分布点个数
/// </summary>
public static readonly DependencyProperty MajorDivisionsCountProperty =
DependencyProperty.Register("MajorDivisionsCount", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 获取或设置辅助的分布点个数
/// </summary>
public static readonly DependencyProperty MinorDivisionsCountProperty =
DependencyProperty.Register("MinorDivisionsCount", typeof(double), typeof(CircularGaugeControl), null);
/// <summary>
/// 优化
/// </summary>
public static readonly DependencyProperty OptimalRangeEndValueProperty =
DependencyProperty.Register("OptimalRangeEndValue", typeof(double), typeof(CircularGaugeControl), new PropertyMetadata(new PropertyChangedCallback(CircularGaugeControl.OnOptimalRangeEndValuePropertyChanged)));
public static readonly DependencyProperty OptimalRangeStartValueProperty =
DependencyProperty.Register("OptimalRangeStartValue", typeof(double), typeof(CircularGaugeControl), new PropertyMetadata(new PropertyChangedCallback(CircularGaugeControl.OnOptimalRangeStartValuePropertyChanged)));
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty ImageOffsetProperty =
DependencyProperty.Register("ImageOffset", typeof(double), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty RangeIndicatorLightOffsetProperty =
DependencyProperty.Register("RangeIndicatorLightOffset", typeof(double), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty ImageSizeProperty =
DependencyProperty.Register("ImageSize", typeof(Size), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty RangeIndicatorRadiusProperty =
DependencyProperty.Register("RangeIndicatorRadius", typeof(double), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty RangeIndicatorThicknessProperty =
DependencyProperty.Register("RangeIndicatorThickness", typeof(double), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty ScaleLabelRadiusProperty =
DependencyProperty.Register("ScaleLabelRadius", typeof(double), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty ScaleLabelSizeProperty =
DependencyProperty.Register("ScaleLabelSize", typeof(Size), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty ScaleLabelFontSizeProperty =
DependencyProperty.Register("ScaleLabelFontSize", typeof(double), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty ScaleLabelForegroundProperty =
DependencyProperty.Register("ScaleLabelForeground", typeof(Color), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty MajorTickSizeProperty =
DependencyProperty.Register("MajorTickRectSize", typeof(Size), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty MinorTickSizeProperty =
DependencyProperty.Register("MinorTickSize", typeof(Size), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty MajorTickColorProperty =
DependencyProperty.Register("MajorTickColor", typeof(Color), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty MinorTickColorProperty =
DependencyProperty.Register("MinorTickColor", typeof(Color), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty GaugeBackgroundColorProperty =
DependencyProperty.Register("GaugeBackgroundColor", typeof(Color), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty PointerThicknessProperty =
DependencyProperty.Register("PointerThickness", typeof(double), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty ResetPointerOnStartUpProperty =
DependencyProperty.Register("ResetPointerOnStartUp", typeof(bool), typeof(CircularGaugeControl), new PropertyMetadata(false, null));
public static readonly DependencyProperty ScaleValuePrecisionProperty =
DependencyProperty.Register("ScaleValuePrecision", typeof(int), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty BelowOptimalRangeColorProperty =
DependencyProperty.Register("BelowOptimalRangeColor", typeof(Color), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty OptimalRangeColorProperty =
DependencyProperty.Register("OptimalRangeColor", typeof(Color), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty AboveOptimalRangeColorProperty =
DependencyProperty.Register("AboveOptimalRangeColor", typeof(Color), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty DialTextProperty =
DependencyProperty.Register("DialText", typeof(string), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty DialTextColorProperty =
DependencyProperty.Register("DialTextColor", typeof(Color), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty DialTextFontSizeProperty =
DependencyProperty.Register("DialTextFontSize", typeof(int), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty DialTextOffsetProperty =
DependencyProperty.Register("DialTextOffset", typeof(double), typeof(CircularGaugeControl), null);
public static readonly DependencyProperty RangeIndicatorLightRadiusProperty =
DependencyProperty.Register("RangeIndicatorLightRadius", typeof(double), typeof(CircularGaugeControl), null);
#endregion
#region 封装属性
/// <summary>
/// 获取或设置当前属性的值
/// </summary>
public double CurrentValue
{
get { return (double)GetValue(CurrentValueProperty); }
set { SetValue(CurrentValueProperty, value); }
}
/// <summary>
/// 获取或设置刻度值的最小值
/// </summary>
public double MinValue
{
get { return (double)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
/// <summary>
/// 获取或设置刻度值的最大值
/// </summary>
public double MaxValue
{
get { return (double)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}
/// <summary>
/// 获取或设置控件的半径
/// </summary>
public double Radius
{
get { return (double)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}
/// <summary>
/// 获取或设置中心圆的半径
/// </summary>
public double PointerCapRadius
{
get { return (double)GetValue(PointerCapRadiusProperty); }
set { SetValue(PointerCapRadiusProperty, value); }
}
/// <summary>
/// 获取或设置指针长度
/// </summary>
public double PointerLength
{
get { return (double)GetValue(PointerLengthProperty); }
set { SetValue(PointerLengthProperty, value); }
}
/// <summary>
/// 获取或设置指针的粗度
/// </summary>
public double PointerThickness
{
get { return (double)GetValue(PointerThicknessProperty); }
set { SetValue(PointerThicknessProperty, value); }
}
/// <summary>
/// 获取或设置刻度的半径
/// </summary>
public double ScaleRadius
{
get { return (double)GetValue(ScaleRadiusProperty); }
set { SetValue(ScaleRadiusProperty, value); }
}
/// <summary>
/// 获取或设置刻度的起始角度
/// </summary>
public double ScaleStartAngle
{
get { return (double)GetValue(ScaleStartAngleProperty); }
set { SetValue(ScaleStartAngleProperty, value); }
}
/// <summary>
/// 获取或设置刻度的摆动角度
/// </summary>
public double ScaleSweepAngle
{
get { return (double)GetValue(ScaleSweepAngleProperty); }
set { SetValue(ScaleSweepAngleProperty, value); }
}
/// <summary>
/// 获取或设置主要分布点个数
/// </summary>
public double MajorDivisionsCount
{
get { return (double)GetValue(MajorDivisionsCountProperty); }
set { SetValue(MajorDivisionsCountProperty, value); }
}
/// <summary>
/// 获取或设置辅助分布点个数
/// </summary>
public double MinorDivisionsCount
{
get { return (double)GetValue(MinorDivisionsCountProperty); }
set { SetValue(MinorDivisionsCountProperty, value); }
}
/// <summary>
/// 获取或设置控件的最佳
/// </summary>
public double OptimalRangeEndValue
{
get { return (double)GetValue(OptimalRangeEndValueProperty); }
set { SetValue(OptimalRangeEndValueProperty, value); }
}
/// <summary>
/// 获取或设置控件的最佳
/// </summary>
public double OptimalRangeStartValue
{
get { return (double)GetValue(OptimalRangeStartValueProperty); }
set { SetValue(OptimalRangeStartValueProperty, value); }
}
/// <summary>
/// /// <summary>
/// 获取或设置图片地址
/// </summary>
/// </summary>
public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
/// <summary>
/// /// <summary>
/// 获取或设置控件的相对于中心点的图片位置
/// </summary>
/// </summary>
public double ImageOffset
{
get { return (double)GetValue(ImageOffsetProperty); }
set { SetValue(ImageOffsetProperty, value); }
}
/// <summary>
/// 获取或设置控件的相对于中心点的指示灯位置
/// </summary>
public double RangeIndicatorLightOffset
{
get { return (double)GetValue(RangeIndicatorLightOffsetProperty); }
set { SetValue(RangeIndicatorLightOffsetProperty, value); }
}
/// <summary>
/// 获取或设置图片的大小
/// </summary>
public Size ImageSize
{
get { return (Size)GetValue(ImageSizeProperty); }
set { SetValue(ImageSizeProperty, value); }
}
/// <summary>
/// 获取或设置指示范围的半径
/// </summary>
public double RangeIndicatorRadius
{
get { return (double)GetValue(RangeIndicatorRadiusProperty); }
set { SetValue(RangeIndicatorRadiusProperty, value); }
}
/// <summary>
/// 获取或设置指示范围的粗度
/// </summary>
public double RangeIndicatorThickness
{
get { return (double)GetValue(RangeIndicatorThicknessProperty); }
set { SetValue(RangeIndicatorThicknessProperty, value); }
}
/// <summary>
/// 获取或设置刻度文本半径
/// </summary>
public double ScaleLabelRadius
{
get { return (double)GetValue(ScaleLabelRadiusProperty); }
set { SetValue(ScaleLabelRadiusProperty, value); }
}
/// <summary>
/// 设置或获取仪表的刻度文本的大小
/// </summary>
public Size ScaleLabelSize
{
get { return (Size)GetValue(ScaleLabelSizeProperty); }
set { SetValue(ScaleLabelSizeProperty, value); }
}
/// <summary>
/// 设置或获取仪表的刻度文本的字体大小
/// </summary>
public double ScaleLabelFontSize
{
get { return (double)GetValue(ScaleLabelFontSizeProperty); }
set { SetValue(ScaleLabelFontSizeProperty, value); }
}
/// <summary>
/// 设置或获取仪表的刻度文本的前景色
/// </summary>
public Color ScaleLabelForeground
{
get { return (Color)GetValue(ScaleLabelForegroundProperty); }
set { SetValue(ScaleLabelForegroundProperty, value); }
}
/// <summary>
/// 设置或获取仪表的主要刻度线的的长度
/// </summary>
public Size MajorTickSize
{
get { return (Size)GetValue(MajorTickSizeProperty); }
set { SetValue(MajorTickSizeProperty, value); }
}
/// <summary>
/// 设置或获取仪表的辅助刻度线的长度
/// </summary>
public Size MinorTickSize
{
get { return (Size)GetValue(MinorTickSizeProperty); }
set { SetValue(MinorTickSizeProperty, value); }
}
/// <summary>
/// 设置或获取仪表的主要刻度线的颜色
/// </summary>
public Color MajorTickColor
{
get { return (Color)GetValue(MajorTickColorProperty); }
set { SetValue(MajorTickColorProperty, value); }
}
/// <summary>
/// 设置或获取仪表的辅助刻度线的颜色
/// </summary>
public Color MinorTickColor
{
get { return (Color)GetValue(MinorTickColorProperty); }
set { SetValue(MinorTickColorProperty, value); }
}
/// <summary>
/// 设置或获取仪表的背景颜色
/// </summary>
public Color GaugeBackgroundColor
{
get { return (Color)GetValue(GaugeBackgroundColorProperty); }
set { SetValue(GaugeBackgroundColorProperty, value); }
}
/// <summary>
/// 设置或获取指针的起始角度
/// </summary>
public bool ResetPointerOnStartUp
{
get { return (bool)GetValue(ResetPointerOnStartUpProperty); }
set { SetValue(ResetPointerOnStartUpProperty, value); }
}
/// <summary>
/// 设置或获取刻度的精度
/// </summary>
public int ScaleValuePrecision
{
get { return (int)GetValue(ScaleValuePrecisionProperty); }
set { SetValue(ScaleValuePrecisionProperty, value); }
}
/// <summary>
/// 设置或获取左部条的颜色
/// </summary>
public Color BelowOptimalRangeColor
{
get { return (Color)GetValue(BelowOptimalRangeColorProperty); }
set { SetValue(BelowOptimalRangeColorProperty, value); }
}
/// <summary>
/// 设置或获取顶部条的颜色
/// </summary>
public Color OptimalRangeColor
{
get { return (Color)GetValue(OptimalRangeColorProperty); }
set { SetValue(OptimalRangeColorProperty, value); }
}
/// <summary>
/// 获取或设置度右边颜色
/// </summary>
public Color AboveOptimalRangeColor
{
get { return (Color)GetValue(AboveOptimalRangeColorProperty); }
set { SetValue(AboveOptimalRangeColorProperty, value); }
}
/// <summary>
/// 获取或设置文本
/// </summary>
public string DialText
{
get { return (string)GetValue(DialTextProperty); }
set { SetValue(DialTextProperty, value); }
}
/// <summary>
/// 获取或设置文本颜色
/// </summary>
public Color DialTextColor
{
get { return (Color)GetValue(DialTextColorProperty); }
set { SetValue(DialTextColorProperty, value); }
}
/// <summary>
/// 获取或设置文本位置
/// </summary>
public double DialTextOffset
{
get { return (double)GetValue(DialTextOffsetProperty); }
set { SetValue(DialTextOffsetProperty, value); }
}
/// <summary>
/// 获取或设置文本字体的大小
/// </summary>
public int DialTextFontSize
{
get { return (int)GetValue(DialTextFontSizeProperty); }
set { SetValue(DialTextFontSizeProperty, value); }
}
/// <summary>
/// 获取或设置指示灯的半径
/// </summary>
public double RangeIndicatorLightRadius
{
get { return (double)GetValue(RangeIndicatorLightRadiusProperty); }
set { SetValue(RangeIndicatorLightRadiusProperty, value); }
}
#endregion
#region 构造函数
public CircularGaugeControl()
{
DefaultStyleKey = typeof(CircularGaugeControl);
}
#endregion
#region 私有方法
private static void OnCurrentValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CircularGaugeControl gauge = d as CircularGaugeControl;
gauge.OnCurrentValueChanged(e);
}
private static void OnOptimalRangeEndValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CircularGaugeControl gauge = d as CircularGaugeControl;
if ((double)e.NewValue > gauge.MaxValue)
{
gauge.OptimalRangeEndValue = gauge.MaxValue;
}
}
private static void OnOptimalRangeStartValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CircularGaugeControl gauge = d as CircularGaugeControl;
if ((double)e.NewValue < gauge.MinValue)
{
gauge.OptimalRangeStartValue = gauge.MinValue;
}
}
public virtual void OnCurrentValueChanged(DependencyPropertyChangedEventArgs e)
{
double newValue = (double)e.NewValue;
double oldValue = (double)e.OldValue;
if (newValue > this.MaxValue)
{
newValue = this.MaxValue;
}
else if (newValue < this.MinValue)
{
newValue = this.MinValue;
}
if (oldValue > this.MaxValue)
{
oldValue = this.MaxValue;
}
else if (oldValue < this.MinValue)
{
oldValue = this.MinValue;
}
if (pointer != null)
{
double db1 = 0;
Double oldcurr_realworldunit = 0;
Double newcurr_realworldunit = 0;
Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
//Resetting the old value to min value the very first time.
if (oldValue == 0 && !isInitialValueSet)
{
oldValue = MinValue;
isInitialValueSet = true;
}
if (oldValue < 0)
{
db1 = MinValue + Math.Abs(oldValue);
oldcurr_realworldunit = ((double)(Math.Abs(db1 * realworldunit)));
}
else
{
db1 = Math.Abs(MinValue) + oldValue;
oldcurr_realworldunit = ((double)(db1 * realworldunit));
}
if (newValue < 0)
{
db1 = MinValue + Math.Abs(newValue);
newcurr_realworldunit = ((double)(Math.Abs(db1 * realworldunit)));
}
else
{
db1 = Math.Abs(MinValue) + newValue;
newcurr_realworldunit = ((double)(db1 * realworldunit));
}
Double oldcurrentvalueAngle = (ScaleStartAngle + oldcurr_realworldunit);
Double newcurrentvalueAngle = (ScaleStartAngle + newcurr_realworldunit);
//Animate the pointer from the old value to the new value
AnimatePointer(oldcurrentvalueAngle, newcurrentvalueAngle);
}
}
private void AnimatePointer(double oldcurrentvalueAngle, double newcurrentvalueAngle)
{
if (pointer != null)
{
DoubleAnimation da = new DoubleAnimation();
da.From = oldcurrentvalueAngle;
da.To = newcurrentvalueAngle;
double animDuration = Math.Abs(oldcurrentvalueAngle - newcurrentvalueAngle) * animatingSpeedFactor;
da.Duration = new Duration(TimeSpan.FromMilliseconds(animDuration));
Storyboard sb = new Storyboard();
sb.Completed += new EventHandler(sb_Completed);
sb.Children.Add(da);
Storyboard.SetTarget(da, pointer);
Storyboard.SetTargetProperty(da, new PropertyPath("(Path.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));
if (newcurrentvalueAngle != oldcurrentvalueAngle)
{
sb.Begin();
}
}
}
void MovePointer(double angleValue)
{
if (pointer != null)
{
TransformGroup tg = pointer.RenderTransform as TransformGroup;
RotateTransform rt = tg.Children[0] as RotateTransform;
rt.Angle = angleValue;
}
}
void sb_Completed(object sender, EventArgs e)
{
if (this.CurrentValue > OptimalRangeEndValue)
{
lightIndicator.Fill = GetRangeIndicatorGradEffect(AboveOptimalRangeColor);
}
else if (this.CurrentValue <= OptimalRangeEndValue && this.CurrentValue >= OptimalRangeStartValue)
{
lightIndicator.Fill = GetRangeIndicatorGradEffect(OptimalRangeColor);
}
else if (this.CurrentValue < OptimalRangeStartValue)
{
lightIndicator.Fill = GetRangeIndicatorGradEffect(BelowOptimalRangeColor);
}
}
private GradientBrush GetRangeIndicatorGradEffect(Color gradientColor)
{
LinearGradientBrush gradient = new LinearGradientBrush();
gradient.StartPoint = new Point(0, 0);
gradient.EndPoint = new Point(1, 1);
GradientStop color1 = new GradientStop();
if (gradientColor == Colors.Transparent)
{
color1.Color = gradientColor;
}
else
color1.Color = Colors.LightGray;
color1.Offset = 0.2;
gradient.GradientStops.Add(color1);
GradientStop color2 = new GradientStop();
color2.Color = gradientColor; color2.Offset = 0.5;
gradient.GradientStops.Add(color2);
GradientStop color3 = new GradientStop();
color3.Color = gradientColor; color3.Offset = 0.8;
gradient.GradientStops.Add(color3);
return gradient;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
//Get reference to known elements on the control template
rootGrid = GetTemplateChild("LayoutRoot") as Grid;
pointer = GetTemplateChild("Pointer") as Path;
pointerCap = GetTemplateChild("PointerCap") as Ellipse;
lightIndicator = GetTemplateChild("RangeIndicatorLight") as Ellipse;
//Draw scale and range indicator
DrawScale();
DrawRangeIndicator();
//Set Zindex of pointer and pointer cap to a really high number so that it stays on top of the
//scale and the range indicator
Canvas.SetZIndex(pointer, 100000);
Canvas.SetZIndex(pointerCap, 100001);
if (ResetPointerOnStartUp)
{
//Reset Pointer
MovePointer(ScaleStartAngle);
}
}
//Drawing the scale with the Scale Radius
private void DrawScale()
{
//Calculate one major tick angle
Double majorTickUnitAngle = ScaleSweepAngle / MajorDivisionsCount;
//Obtaining One minor tick angle
Double minorTickUnitAngle = ScaleSweepAngle / MinorDivisionsCount;
//Obtaining One major ticks value
Double majorTicksUnitValue = (MaxValue - MinValue) / MajorDivisionsCount;
majorTicksUnitValue = Math.Round(majorTicksUnitValue, ScaleValuePrecision);
Double minvalue = MinValue; ;
// Drawing Major scale ticks
for (Double i = ScaleStartAngle; i <= (ScaleStartAngle + ScaleSweepAngle); i = i + majorTickUnitAngle)
{
//Majortick is drawn as a rectangle
Rectangle majortickrect = new Rectangle();
majortickrect.Height = MajorTickSize.Height;
majortickrect.Width = MajorTickSize.Width;
majortickrect.Fill = new SolidColorBrush(MajorTickColor);
Point p = new Point(0.5, 0.5);
majortickrect.RenderTransformOrigin = p;
majortickrect.HorizontalAlignment = HorizontalAlignment.Center;
majortickrect.VerticalAlignment = VerticalAlignment.Center;
TransformGroup majortickgp = new TransformGroup();
RotateTransform majortickrt = new RotateTransform();
//Obtaining the angle in radians for calulating the points
Double i_radian = (i * Math.PI) / 180;
majortickrt.Angle = i;
majortickgp.Children.Add(majortickrt);
TranslateTransform majorticktt = new TranslateTransform();
//Finding the point on the Scale where the major ticks are drawn
//here drawing the points with center as (0,0)
majorticktt.X = (int)((ScaleRadius) * Math.Cos(i_radian));
majorticktt.Y = (int)((ScaleRadius) * Math.Sin(i_radian));
//Points for the textblock which hold the scale value
TranslateTransform majorscalevaluett = new TranslateTransform();
//here drawing the points with center as (0,0)
majorscalevaluett.X = (int)((ScaleLabelRadius) * Math.Cos(i_radian));
majorscalevaluett.Y = (int)((ScaleLabelRadius) * Math.Sin(i_radian));
//Defining the properties of the scale value textbox
TextBlock tb = new TextBlock();
tb.Height = ScaleLabelSize.Height;
tb.Width = ScaleLabelSize.Width;
tb.FontSize = ScaleLabelFontSize;
tb.Foreground = new SolidColorBrush(ScaleLabelForeground);
tb.TextAlignment = TextAlignment.Center;
tb.VerticalAlignment = VerticalAlignment.Center;
tb.HorizontalAlignment = HorizontalAlignment.Center;
//Writing and appending the scale value
//checking minvalue < maxvalue w.r.t scale precion value
if (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision))
{
minvalue = Math.Round(minvalue, ScaleValuePrecision);
tb.Text = minvalue.ToString();
minvalue = minvalue + majorTicksUnitValue;
}
else
{
break;
}
majortickgp.Children.Add(majorticktt);
majortickrect.RenderTransform = majortickgp;
tb.RenderTransform = majorscalevaluett;
rootGrid.Children.Add(majortickrect);
rootGrid.Children.Add(tb);
//Drawing the minor axis ticks
Double onedegree = ((i + majorTickUnitAngle) - i) / (MinorDivisionsCount);
if ((i < (ScaleStartAngle + ScaleSweepAngle)) && (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision)))
{
//Drawing the minor scale
for (Double mi = i + onedegree; mi < (i + majorTickUnitAngle); mi = mi + onedegree)
{
//here the minortick is drawn as a rectangle
Rectangle mr = new Rectangle();
mr.Height = MinorTickSize.Height;
mr.Width = MinorTickSize.Width;
mr.Fill = new SolidColorBrush(MinorTickColor);
mr.HorizontalAlignment = HorizontalAlignment.Center;
mr.VerticalAlignment = VerticalAlignment.Center;
Point p1 = new Point(0.5, 0.5);
mr.RenderTransformOrigin = p1;
TransformGroup minortickgp = new TransformGroup();
RotateTransform minortickrt = new RotateTransform();
minortickrt.Angle = mi;
minortickgp.Children.Add(minortickrt);
TranslateTransform minorticktt = new TranslateTransform();
//Obtaining the angle in radians for calulating the points
Double mi_radian = (mi * Math.PI) / 180;
//Finding the point on the Scale where the minor ticks are drawn
minorticktt.X = (int)((ScaleRadius) * Math.Cos(mi_radian));
minorticktt.Y = (int)((ScaleRadius) * Math.Sin(mi_radian));
minortickgp.Children.Add(minorticktt);
mr.RenderTransform = minortickgp;
rootGrid.Children.Add(mr);
}
}
}
}
/// <summary>
/// Obtaining the Point (x,y) in the circumference
/// </summary>
/// <param name="angle"></param>
/// <param name="radius"></param>
/// <returns></returns>
private Point GetCircumferencePoint(Double angle, Double radius)
{
Double angle_radian = (angle * Math.PI) / 180;
//Radius-- is the Radius of the gauge
Double X = (Double)((Radius) + (radius) * Math.Cos(angle_radian));
Double Y = (Double)((Radius) + (radius) * Math.Sin(angle_radian));
Point p = new Point(X, Y);
return p;
}
/// <summary>
/// Draw the range indicator
/// </summary>
private void DrawRangeIndicator()
{
Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
Double optimalStartAngle;
Double optimalEndAngle;
double db;
//Checking whether the OptimalRangeStartvalue is -ve
if (OptimalRangeStartValue < 0)
{
db = MinValue + Math.Abs(OptimalRangeStartValue);
optimalStartAngle = ((double)(Math.Abs(db * realworldunit)));
}
else
{
db = Math.Abs(MinValue) + OptimalRangeStartValue;
optimalStartAngle = ((double)(db * realworldunit));
}
//Checking whether the OptimalRangeEndvalue is -ve
if (OptimalRangeEndValue < 0)
{
db = MinValue + Math.Abs(OptimalRangeEndValue);
optimalEndAngle = ((double)(Math.Abs(db * realworldunit)));
}
else
{
db = Math.Abs(MinValue) + OptimalRangeEndValue;
optimalEndAngle = ((double)(db * realworldunit));
}
// calculating the angle for optimal Start value
Double optimalStartAngleFromStart = (ScaleStartAngle + optimalStartAngle);
// calculating the angle for optimal Start value
Double optimalEndAngleFromStart = (ScaleStartAngle + optimalEndAngle);
//Calculating the Radius of the two arc for segment
arcradius1 = (RangeIndicatorRadius + RangeIndicatorThickness);
arcradius2 = RangeIndicatorRadius;
double endAngle = ScaleStartAngle + ScaleSweepAngle;
// Calculating the Points for the below Optimal Range segment from the center of the gauge
Point A = GetCircumferencePoint(ScaleStartAngle, arcradius1);
Point B = GetCircumferencePoint(ScaleStartAngle, arcradius2);
Point C = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
Point D = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
bool isReflexAngle = Math.Abs(optimalStartAngleFromStart - ScaleStartAngle) > 180.0;
DrawSegment(A, B, C, D, isReflexAngle, BelowOptimalRangeColor); // Calculating the Points for the Optimal Range segment from the center of the gauge
Point A1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
Point B1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
Point C1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
Point D1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
bool isReflexAngle1 = Math.Abs(optimalEndAngleFromStart - optimalStartAngleFromStart) > 180.0;
DrawSegment(A1, B1, C1, D1, isReflexAngle1, OptimalRangeColor);
// Calculating the Points for the Above Optimal Range segment from the center of the gauge
Point A2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
Point B2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
Point C2 = GetCircumferencePoint(endAngle, arcradius2);
Point D2 = GetCircumferencePoint(endAngle, arcradius1);
bool isReflexAngle2 = Math.Abs(endAngle - optimalEndAngleFromStart) > 180.0;
DrawSegment(A2, B2, C2, D2, isReflexAngle2, AboveOptimalRangeColor);
}
//Drawing the segment with two arc and two line
private void DrawSegment(Point p1, Point p2, Point p3, Point p4, bool reflexangle, Color clr)
{
// Segment Geometry
PathSegmentCollection segments = new PathSegmentCollection();
// First line segment from pt p1 - pt p2
segments.Add(new LineSegment() { Point = p2 });
//Arc drawn from pt p2 - pt p3 with the RangeIndicatorRadius
segments.Add(new ArcSegment()
{
Size = new Size(arcradius2, arcradius2),
Point = p3,
SweepDirection = SweepDirection.Clockwise,
IsLargeArc = reflexangle
});
// Second line segment from pt p3 - pt p4
segments.Add(new LineSegment() { Point = p4 });
//Arc drawn from pt p4 - pt p1 with the Radius of arcradius1
segments.Add(new ArcSegment()
{
Size = new Size(arcradius1, arcradius1),
Point = p1,
SweepDirection = SweepDirection.Counterclockwise,
IsLargeArc = reflexangle
});
// Defining the segment path properties
Color rangestrokecolor;
if (clr == Colors.Transparent)
{
rangestrokecolor = clr;
}
else
rangestrokecolor = Colors.White;
rangeIndicator = new Path()
{
StrokeLineJoin = PenLineJoin.Round,
Stroke = new SolidColorBrush(rangestrokecolor),
//Color.FromArgb(0xFF, 0xF5, 0x9A, 0x86)
Fill = new SolidColorBrush(clr),
Opacity = 0.65,
StrokeThickness = 0.25,
Data = new PathGeometry()
{
Figures = new PathFigureCollection()
{
new PathFigure()
{
IsClosed = true,
StartPoint = p1,
Segments = segments
}
}
}
};
//Set Z index of range indicator
rangeIndicator.SetValue(Canvas.ZIndexProperty, 150);
// Adding the segment to the root grid
rootGrid.Children.Add(rangeIndicator);
}
#endregion
}
}
步骤2.定义一系列需要绑定的类用于将值转换器与绑定关联
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Globalization;
namespace CircularGauge
{
#region 自定义绑定
#region ColorToSolidColorBrushConverter
public class ColorToSolidColorBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Color c = (Color)value;
return new SolidColorBrush(c);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
#endregion
#region ImageOffsetConverter
public class ImageOffsetConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double d = (double)value;
TranslateTransform tt = new TranslateTransform();
tt.Y = d;
return tt;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
#endregion
#region RadiusToDiameterConverter
public class RadiusToDiameterConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double d = (double)value;
return (d * 2);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
#endregion
#region PointerCenterConverter
public class PointerCenterConverter : IValueConverter
{
#region IValueConverter 成员
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double d = (double)value;
TransformGroup tg = new TransformGroup();
RotateTransform rt = new RotateTransform();
TranslateTransform tt = new TranslateTransform();
tt.X = d / 2;
tg.Children.Add(rt);
tg.Children.Add(tt);
return tg;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
#endregion
#region ColorToSolidColorBrushConverter
public class RangeIndicatorLightPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double d = (double)value;
TransformGroup tg = new TransformGroup();
RotateTransform rt = new RotateTransform();
TranslateTransform tt = new TranslateTransform();
tt.Y = d;
tg.Children.Add(rt);
tg.Children.Add(tt);
return tg;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
#endregion
#region SizeConverter
public class SizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double d = 0;
Size s = (Size)value;
if (parameter.ToString() == "Height") d = s.Height;
else if (parameter.ToString() == "Width") d = s.Width;
return d;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
#endregion
#region GlassEffectWidthConverter
public class GlassEffectWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double dbl = (double)value;
return (dbl * 2) * 0.94;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
#endregion
#region GlassEffectWidthConverter
public class BackgroundColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Color c = (Color)value;
RadialGradientBrush radBrush = new RadialGradientBrush();
GradientStop g1 = new GradientStop();
g1.Offset = 0.982;
g1.Color = c;
GradientStop g2 = new GradientStop();
g2.Color = Color.FromArgb(0xFF, 0xAF, 0xB2, 0xB0);
radBrush.GradientStops.Add(g1);
radBrush.GradientStops.Add(g2);
return radBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
#endregion
#endregion
}
步骤3.generic.xaml用于定义样式
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CircularGauge">
<local:ImageOffsetConverter x:Key="imageOffsetConverter" />
<local:RadiusToDiameterConverter x:Key="radiusToDiameterConverter"/>
<local:PointerCenterConverter x:Key="pointerCenterConverter"/>
<local:RangeIndicatorLightPositionConverter x:Key="rangeIndicatorLightPositionConverter"/>
<local:SizeConverter x:Key="sizeConverter" />
<local:BackgroundColorConverter x:Key="backgroundColorConverter" />
<local:ColorToSolidColorBrushConverter x:Key="colorToSolidColorBrushConverter" />
<local:GlassEffectWidthConverter x:Key="glassEffectWidthConverter" />
<Style TargetType="local:CircularGaugeControl" >
<Setter Property="ResetPointerOnStartUp" Value="True" />
<Setter Property="ScaleValuePrecision" Value="5" />
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AFD6" Offset="0.321"/>
<GradientStop Color="#FF8399A9" Offset="0.674"/>
<GradientStop Color="#FF718597" Offset="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="RangeIndicatorThickness" Value="5"/>
<Setter Property="GaugeBackgroundColor" Value="Black" />
<Setter Property="BelowOptimalRangeColor" Value="Yellow" />
<Setter Property="OptimalRangeColor" Value="Green" />
<Setter Property="AboveOptimalRangeColor" Value="Red" />
<Setter Property="DialTextColor" Value="White" />
<Setter Property="DialTextFontSize" Value="8" />
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="local:CircularGaugeControl">
<Grid x:Name="LayoutRoot"
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius,
Converter={StaticResource radiusToDiameterConverter}}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}" >
<Ellipse x:Name="OuterFrame"
StrokeThickness="16"
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=GaugeBackgroundColor, Converter={StaticResource backgroundColorConverter}}">
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF636060" Offset="1"/>
<GradientStop Color="#FF5F5C5C" Offset="0"/>
<GradientStop Color="#FFEEDEDE" Offset="0.35"/>
<GradientStop Color="#FFA09595" Offset="0.705"/>
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Image Source="{TemplateBinding ImageSource}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=ImageSize, Converter={StaticResource sizeConverter}, ConverterParameter=Width }"
Height="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=ImageSize, Converter={StaticResource sizeConverter}, ConverterParameter=Height }"
RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=ImageOffset, Converter={StaticResource imageOffsetConverter}}">
</Image>
<TextBlock Text="{TemplateBinding DialText}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=DialTextColor, Converter={StaticResource colorToSolidColorBrushConverter}}"
FontSize="{TemplateBinding DialTextFontSize}"
FontWeight="Bold"
RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=DialTextOffset, Converter={StaticResource rangeIndicatorLightPositionConverter}}">
</TextBlock>
<Path x:Name="Pointer" Stroke="#FFE91C1C" StrokeThickness="2"
Width="{TemplateBinding PointerLength}"
Height="{TemplateBinding PointerThickness}" HorizontalAlignment="Center"
Data="M1,1 L1,10 L156,6 z" Stretch="Fill" RenderTransformOrigin="0,0.5"
RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=PointerLength, Converter={StaticResource pointerCenterConverter}}">
<Path.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF890A0A" Offset="0.197"/>
<GradientStop Color="#FFC40808" Offset="1"/>
<GradientStop Color="#FFE32323" Offset="0.61"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
<Ellipse x:Name="PointerCap" Height="{TemplateBinding PointerCapRadius}" Width="{TemplateBinding PointerCapRadius}" StrokeThickness="4" Opacity="1" >
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF000000" Offset="0.675"/>
<GradientStop Color="#FFC1B5B5" Offset="0.031"/>
</LinearGradientBrush>
</Ellipse.Stroke>
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF152029" Offset="0.846"/>
<GradientStop Color="#FF140204" Offset="0.342"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!--Range indicator light-->
<Ellipse x:Name="RangeIndicatorLight"
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RangeIndicatorLightRadius, Converter={StaticResource radiusToDiameterConverter}}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RangeIndicatorLightRadius, Converter={StaticResource radiusToDiameterConverter}}"
RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=RangeIndicatorLightOffset, Converter={StaticResource rangeIndicatorLightPositionConverter}}">
<!--Range indicator light off position effect-->
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="LightGray" Offset="0.2" />
<GradientStop Color="Gray" Offset="0.5" />
<GradientStop Color="Black" Offset="0.8" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Path x:Name="GlassEffect" StrokeThickness="1" Stretch="Fill" VerticalAlignment="Bottom"
Height="{TemplateBinding Radius}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource glassEffectWidthConverter}}"
Opacity="0.18" Data="M265.99997,151.00005 C263.99994,194.00003 209.55908,259 135.00064,259 C60.442207,259 11,200.00003 5.9999995,157.00005 C5.0181994,148.55656 73.000877,112.00006 137.00053,112.00007 C199.00887,112.00008 266.72015,135.5164 265.99997,151.00005 z">
<Path.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#68FCFCFC"/>
<GradientStop Color="#FFF8FCF8" Offset="1"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
二.演示
1.Game.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace SLGauge
{
public class Game : INotifyPropertyChanged
{
private double score;
public double Score
{
get { return score; }
set
{
score = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Score"));
}
}
}
public Game(double d)
{
this.score = d;
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
2.MainPage.xaml
<UserControl x:Class="SLGauge.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
xmlns:gauge="clr-namespace:CircularGauge;assembly=CircularGauge"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="650">
<Grid x:Name="LayoutRoot">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF552322" Offset="1"/>
<GradientStop Color="#FFFFFFFF" Offset="0"/>
</LinearGradientBrush>
</Grid.Background>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="300" />
<RowDefinition Height="300"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="330" />
<ColumnDefinition Width="330"/>
<ColumnDefinition Width="330" />
<ColumnDefinition Width="330"/>
</Grid.ColumnDefinitions>
<gauge:CircularGaugeControl x:Name="myGauge1" Grid.Row="0" Grid.Column="0"
Radius="150"
ScaleRadius="110"
ScaleStartAngle="120"
ScaleSweepAngle="300"
PointerLength="85"
PointerCapRadius="35"
MinValue="0"
MaxValue="1000"
MajorDivisionsCount="10"
MinorDivisionsCount="5"
CurrentValue="{Binding Score}"
ImageSource="2.png"
ImageSize="60,50"
RangeIndicatorThickness="8"
RangeIndicatorRadius="120"
RangeIndicatorLightRadius="10"
RangeIndicatorLightOffset="80"
ScaleLabelRadius="90"
ScaleLabelSize="40,20"
ScaleLabelFontSize="10"
ScaleLabelForeground="LightGray"
MajorTickSize="10,3"
MinorTickSize="3,1"
MajorTickColor="LightGray"
MinorTickColor="LightGray"
ImageOffset="-50"
GaugeBackgroundColor="Black"
PointerThickness ="16"
OptimalRangeStartValue="300"
OptimalRangeEndValue="700"
DialTextOffset="40"
DialText="Black"
DialTextColor="AliceBlue"
></gauge:CircularGaugeControl>
<gauge:CircularGaugeControl x:Name="myGauge2" Grid.Column="1" Grid.Row="0"
Radius="150"
ScaleRadius="100"
ScaleStartAngle="140"
ScaleSweepAngle="270"
PointerLength="90"
PointerCapRadius="35"
MinValue="0"
MaxValue="1"
MajorDivisionsCount="10"
MinorDivisionsCount="5"
OptimalRangeEndValue="0.8"
OptimalRangeStartValue="0.5"
CurrentValue="{Binding Score}"
ImageSource="2.png"
ImageSize="60,50"
RangeIndicatorThickness="9"
RangeIndicatorRadius="80"
RangeIndicatorLightRadius="10"
RangeIndicatorLightOffset="80"
ScaleLabelRadius="115"
ScaleLabelSize="40,20"
ScaleLabelFontSize="10"
ScaleLabelForeground="White"
MajorTickSize="10,3"
MinorTickSize="3,1"
MajorTickColor="White"
MinorTickColor="LightGray"
ImageOffset="-50"
GaugeBackgroundColor="CornflowerBlue"
PointerThickness ="5"
DialTextOffset="40"
DialText="Black"
DialTextColor="DarkBlue"
>
</gauge:CircularGaugeControl>
<gauge:CircularGaugeControl x:Name="myGauge3" Grid.Column="0" Grid.Row="1"
Radius="150"
ScaleRadius="90"
ScaleStartAngle="120"
ScaleSweepAngle="300"
PointerLength="80"
PointerCapRadius="45"
MinValue="-50"
MaxValue="50"
MajorDivisionsCount="10"
MinorDivisionsCount="5"
OptimalRangeStartValue="-10"
OptimalRangeEndValue="30"
CurrentValue="{Binding Score}"
ImageSource="2.png"
ImageSize="60,50"
RangeIndicatorThickness="0"
RangeIndicatorRadius="0"
RangeIndicatorLightRadius="10"
RangeIndicatorLightOffset="80"
ScaleLabelRadius="110"
ScaleLabelSize="40,20"
ScaleLabelFontSize="10"
ScaleLabelForeground="White"
MajorTickSize="13,3"
MinorTickSize="5,1"
MajorTickColor="White"
MinorTickColor="LightGray"
ImageOffset="-50"
GaugeBackgroundColor="DarkRed"
PointerThickness ="20" DialTextOffset="40"
DialText="Dark Red"
DialTextColor="DarkRed"
></gauge:CircularGaugeControl>
<gauge:CircularGaugeControl x:Name="myGauge4" Grid.Column="1" Grid.Row="1"
Radius="150"
ScaleRadius="110"
ScaleStartAngle="120"
ResetPointerOnStartUp="True"
ScaleSweepAngle="300"
PointerLength="85"
PointerCapRadius="35"
MinValue="0"
MaxValue="1000"
MajorDivisionsCount="10"
MinorDivisionsCount="5"
CurrentValue="{Binding Score}"
ImageSource="2.png"
ImageSize="60,50"
RangeIndicatorThickness="0"
RangeIndicatorRadius="0"
ScaleLabelRadius="90"
ScaleLabelSize="40,20"
ScaleLabelFontSize="11"
ScaleLabelForeground="Black"
MajorTickSize="10,3"
MinorTickSize="3,1"
MajorTickColor="DarkGray"
MinorTickColor="DarkGray"
ImageOffset="-50"
GaugeBackgroundColor="DarkSlateGray"
PointerThickness ="12"
OptimalRangeStartValue="300"
OptimalRangeEndValue="700"
DialTextOffset="40"
DialText="Dark SlateGray"
DialTextColor="DarkSlateGray"
></gauge:CircularGaugeControl>
</Grid>
</Grid>
</UserControl>
4.MainPage.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace SLGauge
{
public partial class MainPage : UserControl
{
DispatcherTimer timer;
Game game1;
Game game2;
Game game3;
Game game4;
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
game1 = new Game(0);
this.myGauge1.DataContext = game1;
game2 = new Game(0);
this.myGauge2.DataContext = game2;
game3 = new Game(0);
this.myGauge3.DataContext = game3;
game4 = new Game(0);
this.myGauge4.DataContext = game4;
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(2500);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
Random r = new Random();
game1.Score = r.Next(0, 1000);
double val = r.Next(1, 10);
game2.Score = val / 10;
game3.Score = r.Next(-50, 50);
game4.Score = r.Next(0, 1000);
}
}
}