WPF 自定义控件 动画仪表盘控件 Gauge

WPF 自制动画 仪表盘控件 Gauge

WPF 自定义控件 动画仪表盘控件 Gauge_第1张图片
Xaml代码:

<Style TargetType="{x:Type ctrl:ArcGauge}">
        "Background" Value="#646464"/>
        "Foreground" Value="Black"/>
        "Template">
            
                "{x:Type ctrl:ArcGauge}">
                    "10">
                        "{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}">
                            "#FF3B3B3B"/>
                            "0.5,0.5" Margin="2">
                                
                                    
                                        "{Binding Path=Angle,ElementName=PointRotate}"/>
                                    
                                
                                "16" Height="14" Fill="Orange" VerticalAlignment="Top" >
                                    
                                        "12"/>
                                    
                                
                            
                          
                            x:Name="bdGrid" Margin="12" UseLayoutRounding="True" ClipToBounds="True">
                                
                                    
                                        
                                            "#4D000000"/>
                                        
                                    
                                

                                
                                    
                                        
                                        "2*"/>
                                        
                                    
                                    
                                        
                                        "2*"/>
                                        
                                    
                                    "#464646" StrokeThickness="1" Grid.Column="1" Grid.Row="1"/>
                                    "#959595" Margin="4" StrokeThickness="6" Grid.Column="1" Grid.Row="1"/>
                                    "#464646" Margin="14" StrokeThickness="1" Grid.Column="1" Grid.Row="1"/>
                                

                                
                                    
                                        
                                        
                                    
                                    "M5,0 5,0 10,120 0,120z" Fill="#0FA9CE" Stretch="Uniform" Margin="0 30 0 0" RenderTransformOrigin="0.5,1" HorizontalAlignment="Center">
                                        
                                            
                                                x:Name="PointRotate"/>
                                            
                                        
                                    
                                


                                "28" Height="28" Fill="Black">
                                    
                                        "#0FA9CE" ShadowDepth="0" Direction="0" BlurRadius="16"/>
                                    
                                

                                "Bottom" BorderBrush="#10ABD1" BorderThickness="2" Margin="0 0 0 12" Background="Black" Padding="8 2" HorizontalAlignment="Center">
                                    "{Binding Value,RelativeSource={RelativeSource Mode=TemplatedParent}}" FontSize="16" Width="30" TextAlignment="Center" Foreground="White" FontWeight="Bold"/>
                                
                            
                        
                    
                
            
        
    Style>

C#代码:

public class ArcGauge : Control
    {
        public ArcGauge()
        {
            Width = 200;
            Height = 200;
            SetCurrentValue(ValueProperty, 0d);
            SetCurrentValue(MinValueProperty, 0d);
            SetCurrentValue(MaxValueProperty, 100d);
        }

        private void InitTick()
        {
            // 画大刻度
            for (int i = 0; i < 9; i++)
            {
                Line line = new Line();
                line.X1 = 0;
                line.Y1 = 0;
                line.X2 = 0;
                line.Y2 = 12;
                line.Stroke = Brushes.White;
                line.StrokeThickness = 2;
                line.HorizontalAlignment = HorizontalAlignment.Center;
                line.RenderTransformOrigin = new Point(0.5, 0.5);
                line.RenderTransform = new RotateTransform() { Angle = -140 + i * 35 };
                bdGrid.Children.Add(line);
                DrawText();
            }

            // 画小刻度
            for (int i = 0; i < 8; i++)
            {
                var start = -140 + 35 * i + 3.5;
                for (int j = 0; j < 9; j++)
                {
                    Line line = new Line();
                    line.X1 = 0;
                    line.Y1 = 0;
                    line.X2 = 0;
                    line.Y2 = 6;
                    line.Stroke = Brushes.White;
                    line.StrokeThickness = 1;
                    line.HorizontalAlignment = HorizontalAlignment.Center;
                    line.RenderTransformOrigin = new Point(0.5, 0.5);
                    line.RenderTransform = new RotateTransform() { Angle = start + j * 3.5 };
                    bdGrid.Children.Add(line);
                }
            }
        }

        List<TextBlock> textLabels = new List<TextBlock>();
        private void DrawText()
        {
            foreach (var item in textLabels)
            {
                bdGrid.Children.Remove(item);
            }
            textLabels.Clear();

            var per = MaxValue / 8;
            for (int i = 0; i < 9; i++)
            {
                TextBlock textBlock = new TextBlock();
                textBlock.Text = $"{MinValue + (per * i)}";
                textBlock.HorizontalAlignment = HorizontalAlignment.Center;
                textBlock.RenderTransformOrigin = new Point(0.5, 0.5);
                textBlock.RenderTransform = new RotateTransform() { Angle = -140 + i * 35 };
                textBlock.Margin = new Thickness(12);
                textBlock.Foreground = Brushes.White;
                bdGrid.Children.Add(textBlock);
                textLabels.Add(textBlock);
            }
        }

        static ArcGauge()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ArcGauge), new FrameworkPropertyMetadata(typeof(ArcGauge)));
        }

        RotateTransform rotateTransform;
        Grid bdGrid;
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            rotateTransform = GetTemplateChild("PointRotate") as RotateTransform;
            bdGrid = GetTemplateChild("bdGrid") as Grid;
            Refresh();
            InitTick();
        }
        
        [Category("值设定")]
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));

        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as ArcGauge)?.Refresh();

        [Category("值设定")]
        public double MinValue
        {
            get { return (double)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }
        public static readonly DependencyProperty MinValueProperty =
            DependencyProperty.Register("MinValue", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));

        [Category("值设定")]
        public double MaxValue
        {
            get { return (double)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));


        private void Refresh()
        {
            if (rotateTransform == null)
                return;
            DoubleAnimation da = new DoubleAnimation();
            da.Duration = new Duration(TimeSpan.FromMilliseconds(350));
            da.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };

            if (Value > MaxValue)
            {
                rotateTransform.Angle = 140;
                da.To = 140;
            }
            else if (Value < MinValue)
            {
                rotateTransform.Angle = -140;
                da.To = -140;
            }
            else
            {
                var range = MaxValue - MinValue;
                var process = Value / range;
                var tAngle = process * 280 - 140;
                rotateTransform.Angle = tAngle;
                da.To = tAngle;
            }

            rotateTransform.BeginAnimation(RotateTransform.AngleProperty, da);
        }
    }

Ps:其他的颜色主题,范围标记啥的,可以自己完善一下,先暂时实现主要功能。

你可能感兴趣的:(自定义控件,WPF技术,c#,wpf,microsoft)