wpf 仪表盘

1 、效果如图

 

2 代码编写

A 、 前台页面  新建一个前台页面 Insrunment.xaml

   <Grid>
        <Ellipse  Fill="{Binding PlateBackground, RelativeSource={ RelativeSource AncestorType=UserControl,Mode=FindAncestor}}"   Name="backEill" Width="250" Height="250"/>
        <Canvas  Name="mainCanvas" Width="{Binding Width,ElementName=backEill}" Height="{Binding Height,ElementName=backEill}"/>
        <!--内部的圆圈没刻度的-->
        <Path Data="" Stroke="White" StrokeThickness="4" Name="circle" RenderTransformOrigin="0.5,0.5" StrokeStartLineCap="Round" 
              StrokeEndLineCap="Round" Width="{Binding Width, ElementName=backEill}" Height="{Binding Height, ElementName=backEill}">

            <Path.RenderTransform>
                <RotateTransform  Angle="-45"/>
            </Path.RenderTransform>
        </Path>
        <!--指针-->
        <Path Data="" Fill="Green" Name="point"  RenderTransformOrigin="0.5,0.5" 
              Width="{Binding Width,ElementName=backEill }" Height="{Binding Height,ElementName=backEill}">
            <Path.RenderTransform>
                <RotateTransform Angle="-45"  x:Name="rtpoint"/>
            </Path.RenderTransform>

        </Path>
        <!--圆心-->
        <Border Width="20" Height="20" CornerRadius="10">
            <Border.Background>
                <RadialGradientBrush>
                    <GradientStop Color="White" Offset="0.583" />
                    <GradientStop Color="#FF97B5BD" Offset="1" />
                </RadialGradientBrush>
            </Border.Background>
        </Border>
    </Grid>

 B、 后台代码

 /// <summary>
    /// Insrunment.xaml 的交互逻辑
    /// </summary>
    public partial class Insrunment : UserControl
    {

        public int Value
        {
            get { return (int)this.GetValue(ValueProperty); }
            set { this.SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(int), typeof(Insrunment),
            new PropertyMetadata(default(int), new PropertyChangedCallback(OnPropertyChanged)));

        /// <summary>
        /// 大刻度
        /// </summary>
        public int BigScaleValue
        {
            get { return (int)GetValue(BigScaleValueProperty); }
            set { SetValue(BigScaleValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BigScaleValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BigScaleValueProperty =
            DependencyProperty.Register("BigScaleValue", typeof(int), typeof(Insrunment), new PropertyMetadata(default(int), new PropertyChangedCallback(OnPropertyChanged)));

        // 代码片段propdp
        public int MinValue
        {
            get { return (int)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }
        public static readonly DependencyProperty MinValueProperty =
            DependencyProperty.Register("MinValue", typeof(int), typeof(Insrunment), new PropertyMetadata(default(int), new PropertyChangedCallback(OnPropertyChanged)));

        public int MaxValue
        {
            get { return (int)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaxValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(int), typeof(Insrunment), new PropertyMetadata(default(int), new PropertyChangedCallback(OnPropertyChanged)));



        //底盘颜色
        public Brush PlateBackground
        {
            get { return (Brush)GetValue(PlateBackgroundProperty); }
            set { SetValue(PlateBackgroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PlateBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PlateBackgroundProperty =
            DependencyProperty.Register("PlateBackground", typeof(Brush), typeof(Insrunment), new PropertyMetadata(default(Brush)));




        /// <summary>
        /// 字体大小
        /// </summary>
        public int ScaleTextSize
        {
            get { return (int)GetValue(ScaleTextSizeProperty); }
            set { SetValue(ScaleTextSizeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleTextSize.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleTextSizeProperty =
            DependencyProperty.Register("ScaleTextSize", typeof(int), typeof(Insrunment), new PropertyMetadata(default(int), new PropertyChangedCallback(OnPropertyChanged)));


        /// <summary>
        /// 刻度颜色
        /// </summary>
        public Brush ScaleColor
        {
            get { return (Brush)GetValue(ScaleColorProperty); }
            set { SetValue(ScaleColorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleColor.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleColorProperty =
            DependencyProperty.Register("ScaleColor", typeof(Brush), typeof(Insrunment), new PropertyMetadata(default(Brush), new PropertyChangedCallback(OnPropertyChanged)));
        /// <summary>
        /// 变化的时候调用下面方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        public static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as Insrunment).Refresh();
        }
        public Insrunment()
        {
            InitializeComponent();
            this.SizeChanged += Insrunment_SizeChanged;
        }

        void Insrunment_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            double min = Math.Min(this.RenderSize.Width, this.RenderSize.Height);
            this.Width = min;
            this.Height = min;
        }

        //https://blog.csdn.net/weixin_45178215/article/details/118379606?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&utm_relevant_index=1
        private void Refresh()
        {

            double radius = this.backEill.Width / 2;
            if (double.IsNaN(radius))
            {
                return;
            }
            if (MaxValue == 0)
            {
                return;
            }

            if (ScaleTextSize == 0)
            {
                return;
            }
            this.mainCanvas.Children.Clear();

            //int min = 0, max = 100;

            double setp = 270.0 / (MaxValue - MinValue);

            //刻度 就是算一个圆上的坐标 可以百度搜索查看公式, 用正弦 余弦计算而出来的
            //sinA=(y2-y1)/r  ==>y2=y1+r*sinA
            // cosA=(x2-x1)/r=>x2=x1+rcosA;
            //弧度=角度*π/180
            // x2 = x1 + rcos(角度*π/180);
            //y2=r*sinA(弧度*π/180)+y1;

            for (int i = 0; i < MaxValue - MinValue; i++)
            {
                Line lineScal = new Line();
                //lineScal.X1 = 100;
                //lineScal.Y1 = 100;
                //lineScal.X2 = 200;
                //lineScal.Y2 = 200;
                // -45  逆时针旋转
                //里面的点 -13  -20 的话就靠近右边
                lineScal.X1 = radius - (radius - 13) * Math.Cos((i * setp - 45) * Math.PI / 180);
                lineScal.Y1 = radius - (radius - 13) * Math.Sin((i * setp - 45) * Math.PI / 180);

                // 外面的点
                lineScal.X2 = radius - (radius - 8) * Math.Cos((i * setp - 45) * Math.PI / 180);
                lineScal.Y2 = radius - (radius - 8) * Math.Sin((i * setp - 45) * Math.PI / 180);

                lineScal.Stroke = ScaleColor;
                lineScal.StrokeThickness = 2;

                this.mainCanvas.Children.Add(lineScal);
            }

            // 大刻度
            // int scalSie = 10;//BigScaleValue
            setp = 270.0 / BigScaleValue;

            //刻度文字
            int scaleText = MinValue;
            for (int i = 0; i <= BigScaleValue; i++)
            {
                Line lineScal = new Line();
                //里面的点 -13  -20 的话就靠近右边
                lineScal.X1 = radius - (radius - 20) * Math.Cos((i * setp - 45) * Math.PI / 180);
                lineScal.Y1 = radius - (radius - 20) * Math.Sin((i * setp - 45) * Math.PI / 180);

                // 外面的点
                lineScal.X2 = radius - (radius - 8) * Math.Cos((i * setp - 45) * Math.PI / 180);
                lineScal.Y2 = radius - (radius - 8) * Math.Sin((i * setp - 45) * Math.PI / 180);

                lineScal.Stroke = ScaleColor;
                lineScal.StrokeThickness = 2;

                this.mainCanvas.Children.Add(lineScal);

                //数字刻度
                TextBlock text = new TextBlock();
                text.Width = 34;
                text.TextAlignment = TextAlignment.Center;
                text.FontSize = ScaleTextSize;
                scaleText = MinValue + (MaxValue - MinValue) / BigScaleValue * i;
                text.Text = scaleText.ToString();
                text.Foreground = ScaleColor;

                Canvas.SetLeft(text, radius - (radius - 36) * Math.Cos((i * setp - 45) * Math.PI / 180) - 17);
                Canvas.SetTop(text, radius - (radius - 36) * Math.Sin((i * setp - 45) * Math.PI / 180) - 10);

                this.mainCanvas.Children.Add(text);
            }

            //内部的弧线
            string data = "M{0} {1} A{0} {0} 0 1 1  {1} {2}";
            data = string.Format(data, radius / 2, radius, radius * 1.5);
            var conver = TypeDescriptor.GetConverter(typeof(Geometry));
            this.circle.Data = (Geometry)conver.ConvertFrom(data);


            //具体指针到某个方向
            setp = 270.0 / (MaxValue - MinValue);
            // this.rtpoint.Angle = this.Value * setp - 45;

            DoubleAnimation da = new DoubleAnimation(((int)(this.Value - this.MinValue) * setp) - 45, new Duration(TimeSpan.FromMilliseconds(200)));
            rtpoint.BeginAnimation(RotateTransform.AngleProperty, da);
            //指针
            data = "M{0} {1} ,{1} {2}, {1} {3}";
            data = string.Format(data, radius * 0.3, radius, radius - 5, radius + 5);
            this.point.Data = (Geometry)conver.ConvertFrom(data);

        }

    }

C 、调用

             xmlns:zxc="clr-namespace:WPF4"

 <zxc:Insrunment  Value="{Binding InermentValue}" MinValue="0" MaxValue="100"  BigScaleValue="10" PlateBackground="Orange"  ScaleTextSize="16" ScaleColor="White"/>

  

 

posted @ 2024-05-18 14:07  陌念  阅读(109)  评论(0)    收藏  举报