Bootstrap

WPF绘制仪表

1,效果:

2,代码:

2.1,资源字典:BaseStyle.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <!--外轮廓颜色-->
    <SolidColorBrush x:Key="ColorBrush">
        <SolidColorBrush.Color>#190E1C</SolidColorBrush.Color>
    </SolidColorBrush>
    <!--外轮廓进度颜色-->
    <SolidColorBrush x:Key="ColorBrush1" Color="#2B1A51"></SolidColorBrush>
    <!--中心圆盘颜色-->
    <Color x:Key="ColorLight2" >#23153B</Color>
    <Color x:Key="ColorLight1">#23153B</Color>
    <Color x:Key="ColorLight">#45246B </Color>
    <!--指针颜色-->
    <Color x:Key="LightBlueColor1">#00C9FF</Color >
    <Color x:Key="LightBlueColor2">#00C9FF</Color>
    <Color x:Key="LightBlueColor3">#00C9F0</Color>
</ResourceDictionary>
2.2,自定义圆弧类Arc
//WPF未提供圆弧Shape,故根据Ellipse实现过程自定义一个圆弧类
 class Arc : Shape
    {
        private Rect _rect = Rect.Empty;
        public double StartAngle
        {
            get { return (double)GetValue(StartAngleProperty); }
            set { SetValue(StartAngleProperty, value); }
        }
        // Using a DependencyProperty as the backing store for StartAngle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StartAngleProperty =
            DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc), new FrameworkPropertyMetadata((double)-135, FrameworkPropertyMetadataOptions.AffectsRender));
        public double EndAngle
        {
            get { return (double)GetValue(EndAngleProperty); }
            set { SetValue(EndAngleProperty, value); }
        }
        // Using a DependencyProperty as the backing store for EndAngle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EndAngleProperty =
            DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc), new FrameworkPropertyMetadata((double)135, FrameworkPropertyMetadataOptions.AffectsRender));
        public double ArcThickness
        {
            get { return (double)GetValue(ArcThicknessProperty); }
            set { SetValue(ArcThicknessProperty, value); }
        }
        // Using a DependencyProperty as the backing store for ArcThickness.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ArcThicknessProperty =
            DependencyProperty.Register("ArcThickness", typeof(double), typeof(Arc), new FrameworkPropertyMetadata((double)10, FrameworkPropertyMetadataOptions.AffectsRender));
        public override Geometry RenderedGeometry => DefiningGeometry;
        public override Transform GeometryTransform => Transform.Identity;
        protected override Geometry DefiningGeometry
        {
            get
            {
                if (_rect.IsEmpty)
                {
                    return Geometry.Empty;
                }
                PathGeometry path = new PathGeometry();
                PathFigure figure = new PathFigure();
                figure.IsClosed = false;
                //根据起始角度算出起始点
                //可绘图的区域为_rec
                double offsetAngle = 270;
                double diameter = _rect.Width > _rect.Height ? _rect.Height : _rect.Width;
                Point centerPoint = new Point(_rect.X + _rect.Width / 2, _rect.Y + _rect.Height / 2);
                double xoffset = diameter * Math.Cos((StartAngle + offsetAngle) / 180 * Math.PI) / 2;
                double yoffset = diameter * Math.Sin((StartAngle + offsetAngle) / 180 * Math.PI) / 2;
                Point startPoint = new Point(centerPoint.X + xoffset, centerPoint.Y + yoffset);
                double xoffset2 = diameter * Math.Cos((EndAngle + offsetAngle) / 180 * Math.PI) / 2;
                double yoffset2 = diameter * Math.Sin((EndAngle + offsetAngle) / 180 * Math.PI) / 2;
                Point endPoint = new Point(centerPoint.X + xoffset2, centerPoint.Y + yoffset2);
                figure.StartPoint = startPoint;
                ArcSegment arc = new ArcSegment
                {
                    Point = endPoint,
                    Size = new Size(diameter / 2, diameter / 2),
                    SweepDirection = SweepDirection.Clockwise
                };
                if (EndAngle - StartAngle < 180)
                {
                    arc.IsLargeArc = false;
                }
                else
                {
                    arc.IsLargeArc = true;
                }
                figure.Segments.Add(arc);
                path.Figures.Add(figure);
                return path;
            }
        }
        static Arc()
        {
            Shape.StretchProperty.OverrideMetadata(typeof(Arc), new FrameworkPropertyMetadata(Stretch.Fill));
        }
        protected override Size MeasureOverride(Size constraint)
        {
            double width = constraint.Width;
            double height = constraint.Height;
            if (double.IsInfinity(width) && double.IsInfinity(height))
            {
                return GetNaturalSize();
            }
            if (base.Stretch == Stretch.UniformToFill)
            {
                width = ((!double.IsInfinity(width) && !double.IsInfinity(height)) ? Math.Max(width, height) : Math.Min(width, height));
                return new Size(width, width);
            }
            return constraint;
        }
        protected override Size ArrangeOverride(Size finalSize)
        {
            double strokeThickness = ArcThickness;
            double num = strokeThickness / 2.0;
            _rect = new Rect(num, num, Math.Max(0.0, finalSize.Width - strokeThickness), Math.Max(0.0, finalSize.Height - strokeThickness));
            switch (base.Stretch)
            {
                case Stretch.None:
                    {
                        ref Rect rect = ref _rect;
                        double width = (_rect.Height = 0.0);
                        rect.Width = width;
                        break;
                    }
                case Stretch.Uniform:
                    if (_rect.Width > _rect.Height)
                    {
                        _rect.Width = _rect.Height;
                    }
                    else
                    {
                        _rect.Height = _rect.Width;
                    }
                    break;
                case Stretch.UniformToFill:
                    if (_rect.Width < _rect.Height)
                    {
                        _rect.Width = _rect.Height;
                    }
                    else
                    {
                        _rect.Height = _rect.Width;
                    }
                    break;
            }
            return finalSize;
            // return base.ArrangeOverride(finalSize);
        }
        protected override void OnRender(DrawingContext drawingContext)
        {
            if (!_rect.IsEmpty)
            {
                Pen pen = new Pen();
                pen.Brush = Stroke;
                pen.Thickness = ArcThickness;
                pen.StartLineCap = StrokeStartLineCap;
                pen.EndLineCap = StrokeEndLineCap;
                drawingContext.DrawGeometry(base.Fill, pen, RenderedGeometry);
            }
        }
        Size GetNaturalSize()
        {
            double strokeThickness = GetStrokeThickness();
            return new Size(strokeThickness * 2, strokeThickness * 2);
        }
        double GetStrokeThickness()
        {
            if (double.IsNaN(ArcThickness) || double.IsInfinity(ArcThickness))
            {
                return 0.0;
            }
            else
            {
                return ArcThickness;
            }
        }
    }
2.3,自定义仪表控件xaml
<UserControl x:Class="MyWpfControlLibrary.MeterPlate"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:MyWpfControlLibrary"
             mc:Ignorable="d" 
             d:DesignHeight="400" d:DesignWidth="400" x:Name="meterPlate">
    <UserControl.Resources>
        <ResourceDictionary Source="pack://application:,,,/MyWpfControlLibrary;component/basestyle.xaml"></ResourceDictionary>
    </UserControl.Resources>
    <Viewbox>
        <Grid>
            <Border x:Name="border01" Background="{Binding ElementName=meterPlate, Path=PlateBackground}" CornerRadius="200" BorderThickness="{Binding ElementName=meterPlate, Path=PlateBorderThickness}"  BorderBrush="{Binding ElementName=meterPlate, Path=PlateBorderBrush}" ClipToBounds="True" >
                <Grid>
                    <Canvas Name="canvasPlate" Width="400" Height="400"  Background="Transparent" >
                    </Canvas>
                    <local:Arc x:Name="arc01" Opacity="0.3" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StartAngle="{Binding ElementName=meterPlate, Path=StartAngle}" EndAngle="{Binding ElementName=meterPlate, Path=EndAngle}"    Stroke="{DynamicResource ColorBrush}" ArcThickness="{Binding ElementName=meterPlate, Path=ArcThickness}" ></local:Arc>
                    <local:Arc  ArcThickness="{Binding ElementName=meterPlate, Path=ArcThickness}" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StartAngle="{Binding ElementName=meterPlate, Path=StartAngle}"  Opacity="0.8"  x:Name="arckd"  EndAngle="110" Stroke="{DynamicResource ColorBrush1}"></local:Arc>
                    <Border  Width="200" Height="200" CornerRadius="100" Opacity="0.5" >
                        <Border.Background>
                            <RadialGradientBrush RadiusX="1" RadiusY="1">
                                <GradientStop Color="{DynamicResource  ColorLight2}" Offset="0.3"></GradientStop>
                                <GradientStop Color="{DynamicResource ColorLight1}" Offset="0.4"></GradientStop>
                                <GradientStop Color="{DynamicResource ColorLight}" Offset="1"></GradientStop>
                            </RadialGradientBrush>
                        </Border.Background>
                    </Border>
                    <Path  HorizontalAlignment="Center" VerticalAlignment="Center"  Data="M0 -5,160 0,0 5 z" RenderTransformOrigin="0.5,0.5" Margin="14">
                        <Path.Fill>
                            <RadialGradientBrush RadiusX="1" RadiusY="1">
                                <GradientStop Color="{DynamicResource LightBlueColor1}" Offset="0.3"/>
                                <GradientStop Color="{DynamicResource LightBlueColor2}" Offset="0.4"/>
                                <GradientStop Color="{DynamicResource LightBlueColor3}" Offset="1"/>
                            </RadialGradientBrush>
                        </Path.Fill>
                        <Path.RenderTransform>
                            <TransformGroup>
                                <TranslateTransform X="80"></TranslateTransform>
                                <RotateTransform x:Name="rtPointer" />
                            </TransformGroup>
                        </Path.RenderTransform>
                    </Path>
                    <Border Width="100" Height="100" CornerRadius="50"  Margin="14">
                        <Border.Background>
                            <RadialGradientBrush RadiusX="1" RadiusY="1">
                                <GradientStop Color="{DynamicResource ColorLight}" Offset="0.5"/>
                                <GradientStop Color="{DynamicResource  ColorLight1}" Offset="0.3"/>
                                <GradientStop Color="{DynamicResource ColorLight2}" Offset="0.1"/>
                            </RadialGradientBrush>
                        </Border.Background>
                        <StackPanel Panel.ZIndex="999" Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
                            <TextBlock x:Name="txtCurValue" Foreground="White"  Text="{Binding ElementName=meterPlate, Path=Value}" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                            <TextBlock Foreground="White" Text="km/h" FontSize="12" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        </StackPanel>
                    </Border>
                </Grid>
            </Border>
        </Grid>
    </Viewbox>
</UserControl>

效果:

2.4,仪表控件代码:
  public partial class MeterPlate : UserControl
    {
        const double OffsetAngle = 270;
        public static readonly DependencyProperty StartAngleProperty;
        public static readonly DependencyProperty EndAngleProperty;
        public static readonly DependencyProperty ValueProperty;
        public static readonly DependencyProperty MinNumProperty;
        public static readonly DependencyProperty MaxNumProperty;
        public static readonly DependencyProperty PlateBackgroundProperty;
        public static readonly DependencyProperty PlateBorderBrushProperty;
        public static readonly DependencyProperty PlateBorderThicknessProperty;
        public static readonly DependencyProperty ArcThicknessProperty;
        public static readonly DependencyProperty LowAlarmPercentProperty;
        public static readonly DependencyProperty HeightAlarmPercentProperty;
        public static readonly DependencyProperty LowAlarmColorProperty;
        public static readonly DependencyProperty HeightAlarmColorProperty;
        public MeterPlate()
        {
            InitializeComponent();
        }
        static MeterPlate()
        {
            StartAngleProperty =
            DependencyProperty.Register("StartAngle", typeof(double), typeof(MeterPlate), new FrameworkPropertyMetadata((double)-135, FrameworkPropertyMetadataOptions.AffectsRender));
            EndAngleProperty =
                DependencyProperty.Register("EndAngle", typeof(double), typeof(MeterPlate), new FrameworkPropertyMetadata((double)135, FrameworkPropertyMetadataOptions.AffectsRender));
            ValueProperty =
                 DependencyProperty.Register("Value", typeof(double), typeof(MeterPlate),
                      new FrameworkPropertyMetadata((double)45, FrameworkPropertyMetadataOptions.AffectsRender));
            MinNumProperty =
                 DependencyProperty.Register("MinNum", typeof(double), typeof(MeterPlate),
                     new FrameworkPropertyMetadata((double)0, FrameworkPropertyMetadataOptions.AffectsRender));
            MaxNumProperty =
                DependencyProperty.Register("MaxNum", typeof(double), typeof(MeterPlate),
                    new FrameworkPropertyMetadata((double)120, FrameworkPropertyMetadataOptions.AffectsRender));
            PlateBackgroundProperty =
                 DependencyProperty.Register("PlateBackground", typeof(Brush), typeof(MeterPlate), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(43, 26, 81))));
            PlateBorderBrushProperty =
                DependencyProperty.Register("PlateBorderBrush", typeof(Brush), typeof(MeterPlate), null);
            PlateBorderThicknessProperty =
                 DependencyProperty.Register("PlateBorderThickness", typeof(Thickness), typeof(MeterPlate), new PropertyMetadata(new Thickness(0)));
            ArcThicknessProperty =
            DependencyProperty.Register("ArcThickness", typeof(double), typeof(MeterPlate), new PropertyMetadata((double)30));
            LowAlarmPercentProperty =
            DependencyProperty.Register("LowAlarmPercent", typeof(double), typeof(MeterPlate), new FrameworkPropertyMetadata((double)1, FrameworkPropertyMetadataOptions.AffectsRender));
            HeightAlarmPercentProperty =
            DependencyProperty.Register(" HeightAlarmPercent", typeof(double), typeof(MeterPlate), new FrameworkPropertyMetadata((double)1, FrameworkPropertyMetadataOptions.AffectsRender));
            LowAlarmColorProperty =
            DependencyProperty.Register("LowAlarmColor", typeof(Color), typeof(MeterPlate), new FrameworkPropertyMetadata(Colors.Orange, FrameworkPropertyMetadataOptions.AffectsRender));
            HeightAlarmColorProperty =
            DependencyProperty.Register("HeightAlarmColor", typeof(Color), typeof(MeterPlate), new FrameworkPropertyMetadata(Colors.Red, FrameworkPropertyMetadataOptions.AffectsRender));
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘开始角度")]
        public double StartAngle
        {
            get { return (double)GetValue(StartAngleProperty); }
            set { SetValue(StartAngleProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘结束角度")]
        public double EndAngle
        {
            get { return (double)GetValue(EndAngleProperty); }
            set { SetValue(EndAngleProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("当前值")]
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘最小值")]
        public double MinNum
        {
            get { return (double)GetValue(MinNumProperty); }
            set { SetValue(MinNumProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘最大值")]
        public double MaxNum
        {
            get { return (double)GetValue(MaxNumProperty); }
            set { SetValue(MaxNumProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘低值区域所占区域默认为1")]
        public double LowAlarmPercent
        {
            get { return (double)GetValue(LowAlarmPercentProperty); }
            set { SetValue(LowAlarmPercentProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘高值区域所占区域默认为1")]
        public double HeightAlarmPercent
        {
            get { return (double)GetValue(HeightAlarmPercentProperty); }
            set { SetValue(HeightAlarmPercentProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘低值区域刻度值与刻度线颜色")]
        public Color LowAlarmColor
        {
            get { return (Color)GetValue(LowAlarmColorProperty); }
            set { SetValue(LowAlarmColorProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘高值区域刻度值与刻度线颜色")]
        public Color HeightAlarmColor
        {
            get { return (Color)GetValue(HeightAlarmColorProperty); }
            set { SetValue(HeightAlarmColorProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘背景画刷")]
        public Brush PlateBackground
        {
            get { return (Brush)GetValue(PlateBackgroundProperty); }
            set { SetValue(PlateBackgroundProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘边框画刷")]
        public Brush PlateBorderBrush
        {
            get { return (Brush)GetValue(PlateBorderBrushProperty); }
            set { SetValue(PlateBorderBrushProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘边框宽度")]
        public Thickness PlateBorderThickness
        {
            get { return (Thickness)GetValue(PlateBorderThicknessProperty); }
            set { SetValue(PlateBorderThicknessProperty, value); }
        }
        [Browsable(true), Category("自定义属性"), Description("仪表盘进度条宽度")]
        public double ArcThickness
        {
            get { return (double)GetValue(ArcThicknessProperty); }
            set { SetValue(ArcThicknessProperty, value); }
        }
        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            DrawScale();
            DrawAngle();
        }
        /// <summary>
        /// 画表盘的刻度
        /// </summary>
        private void DrawScale()
        {
            double unitAngle = (EndAngle - StartAngle) / (MaxNum - MinNum);
            double realStartAngle = StartAngle + OffsetAngle;
            double outgap = arc01.ArcThickness;
            this.canvasPlate.Children.Clear();
            Point centerPoint = new Point(200, 200);
            if (!double.IsInfinity(border01.BorderThickness.Left) && !double.IsNaN(border01.BorderThickness.Left))
            {
                centerPoint = new Point(200 - border01.BorderThickness.Left, 200 - border01.BorderThickness.Left);
            }
            for (double i = 0; i <= this.MaxNum - this.MinNum; i++)
            {
                //添加刻度线
                Line lineScale = new Line();
                if (LowAlarmPercent != 0 && i <= LowAlarmPercent * 10)
                {
                    lineScale.Stroke = new SolidColorBrush(LowAlarmColor);
                }
                else if (HeightAlarmPercent != 0 && i >= (MaxNum - HeightAlarmPercent * 10))
                {
                    lineScale.Stroke = new SolidColorBrush(HeightAlarmColor);
                }
                else
                {
                    lineScale.Stroke = new SolidColorBrush(Colors.White);
                    if (i % 10 != 0)
                    {
                        lineScale.Opacity = 0.6;
                    }
                }
                if (i % 10 == 0)
                {
                    //注意Math.Cos和Math.Sin的参数是弧度,记得将角度转为弧度制
                    lineScale.X1 = centerPoint.X + (centerPoint.X - outgap - 20) * Math.Cos((i * unitAngle + realStartAngle) * Math.PI / 180);
                    lineScale.Y1 = centerPoint.Y + (centerPoint.X - outgap - 20) * Math.Sin((i * unitAngle + realStartAngle) * Math.PI / 180);
                    lineScale.StrokeThickness = 2;
                    //添加刻度值
                    TextBlock txtScale = new TextBlock();
                    txtScale.Text = (i + this.MinNum).ToString();
                    txtScale.Width = 34;
                    txtScale.TextAlignment = TextAlignment.Center;
                    if (LowAlarmPercent != 0 && i <= LowAlarmPercent * 10)
                    {
                        txtScale.Foreground = new SolidColorBrush(LowAlarmColor);
                    }
                    else if (HeightAlarmPercent != 0 && i >= (MaxNum - HeightAlarmPercent * 10))
                    {
                        txtScale.Foreground = new SolidColorBrush(HeightAlarmColor);
                    }
                    else
                    {
                        txtScale.Foreground = new SolidColorBrush(Colors.White);
                    }
                    txtScale.RenderTransform = new RotateTransform() { Angle = 0, CenterX = 17, CenterY = 8 };
                    txtScale.FontSize = 18;
                    if (i > (MaxNum - MinNum) / 2)
                    {
                        Canvas.SetLeft(txtScale, centerPoint.X + (centerPoint.X - outgap - 35) * Math.Cos((i * unitAngle + realStartAngle) * Math.PI / 180) - 20);
                        Canvas.SetTop(txtScale, centerPoint.Y + (centerPoint.X - outgap - 35) * Math.Sin((i * unitAngle + realStartAngle) * Math.PI / 180) - 10);
                    }
                    else
                    {
                        Canvas.SetLeft(txtScale, centerPoint.X + (centerPoint.X - outgap - 35) * Math.Cos((i * unitAngle + realStartAngle) * Math.PI / 180) - 17);
                        Canvas.SetTop(txtScale, centerPoint.Y + (centerPoint.X - outgap - 35) * Math.Sin((i * unitAngle + realStartAngle) * Math.PI / 180) - 10);
                    }
                    this.canvasPlate.Children.Add(txtScale);
                }
                else
                {
                    lineScale.X1 = centerPoint.X + (centerPoint.X - outgap - 10) * Math.Cos((i * unitAngle + realStartAngle) * Math.PI / 180);
                    lineScale.Y1 = centerPoint.Y + (centerPoint.X - outgap - 10) * Math.Sin((i * unitAngle + realStartAngle) * Math.PI / 180);
                    lineScale.StrokeThickness = 1;
                    // lineScale.Opacity = 0.6;
                }
                lineScale.X2 = centerPoint.X + (centerPoint.X - outgap) * Math.Cos((i * unitAngle + realStartAngle) * Math.PI / 180);
                lineScale.Y2 = centerPoint.Y + (centerPoint.X - outgap) * Math.Sin((i * unitAngle + realStartAngle) * Math.PI / 180);
                this.canvasPlate.Children.Add(lineScale);
            }
            if (LowAlarmPercent != 0 && Value <= LowAlarmPercent * 10)
            {
                txtCurValue.Foreground = new SolidColorBrush(LowAlarmColor);
            }
            else if (HeightAlarmPercent != 0 && Value >= (MaxNum - HeightAlarmPercent * 10))
            {
                txtCurValue.Foreground = new SolidColorBrush(HeightAlarmColor);
            }
            else
            {
                txtCurValue.Foreground = new SolidColorBrush(Colors.White);
            }
        }
        private void DrawAngle()
        {
            double step = (Value - MinNum) / (this.MaxNum - this.MinNum) * (EndAngle - StartAngle) + OffsetAngle + StartAngle;
            double desAngle = (Value - MinNum) / (this.MaxNum - this.MinNum) * (EndAngle - StartAngle) + StartAngle;
            if (Value < MinNum)
            {
                step = OffsetAngle + StartAngle;
                desAngle = StartAngle;
            }
            if (Value > MaxNum)
            {
                step = OffsetAngle + EndAngle;
                desAngle = EndAngle;
            }
            DoubleAnimation da = new DoubleAnimation(step, new Duration(TimeSpan.FromMilliseconds(200)));
            this.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da);
            //进度条显示
            DoubleAnimation da2 = new DoubleAnimation(desAngle, new Duration(TimeSpan.FromMilliseconds(200)));
            this.arckd.BeginAnimation(Arc.EndAngleProperty, da2);
        }
    }

3,应用:

<Window x:Class="Demo.MainWindow"
        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:local="clr-namespace:Demo"
        mc:Ignorable="d"
        xmlns:my="clr-namespace:MyWpfControlLibrary;assembly=MyWpfControlLibrary"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
      
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="300*"/>
                <RowDefinition Height="2*"/>
            </Grid.RowDefinitions>
            <my:MeterPlate StartAngle="-135" PlateBackground="SlateBlue" LowAlarmPercent="2" HeightAlarmPercent="2" MaxNum="120" MinNum="0"  EndAngle="135" Value="{Binding Value}" Margin="0,0,35,10" ></my:MeterPlate>
            <Grid Grid.Column="1" Margin="10">
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Button x:Name="btnStart" Margin="10" Content="开始" Click="btnStart_Click"></Button>
                <TextBlock Grid.Row="1" Margin="10" Text="{Binding Value}" FontSize="16" FontWeight="Bold" TextAlignment="Center"></TextBlock>

            </Grid>

        </Grid>
</Window>

效果

 测试代码:

  public partial class MainWindow : Window
    {
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(MainWindow), new PropertyMetadata((double)0
                ));
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

        }
        bool isBreak = false;
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            if (btnStart.Content.ToString().Equals("开始"))
            {
                isBreak = false;
                DoWork();
            }
            else
            {
                isBreak = true;
            }
        }
        Random random = new Random();
        async void DoWork()
        {
            btnStart.Content = "运行中";
            await Task.Run(() =>
            {
                while (true)
                {
                    if (isBreak)
                    {
                        break;
                    }
                    Dispatcher.Invoke(() =>
                    {
                        Value+=random.Next(0,20);
                        if (Value >= 120)
                        {
                            Value = 0;
                        }
                    });
                    System.Threading.Thread.Sleep(500);
                }
            });
            btnStart.Content = "停止";
            await Task.Delay(2000);
            btnStart.Content = "开始";
        }
    }

4,Demo链接:

https://download.csdn.net/download/lingxiao16888/89879311

;