WPF 仪表盘,自定义控件仪表盘,纯开源代码

直接上图,先看效果

在这里插入图片描述

代码

 public partial class MeterPlate : UserControl
    {
        public MeterPlate()
        {
            InitializeComponent();

            Loaded += MeterPlate_Loaded;
        }
        private static double StartAngle = -135.5;
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(MeterPlate),
                new PropertyMetadata(default(double), new PropertyChangedCallback(OnValuePropertyChanged)));


        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }
        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register("Minimum", typeof(double), typeof(MeterPlate),
                new PropertyMetadata(double.NaN, new PropertyChangedCallback(OnPropertyChanged)));


        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(double), typeof(MeterPlate),
                new PropertyMetadata(double.NaN, new PropertyChangedCallback(OnPropertyChanged)));


        public Brush PlateBackground
        {
            get { return (Brush)GetValue(PlateBackgroundProperty); }
            set { SetValue(PlateBackgroundProperty, value); }
        }
        public static readonly DependencyProperty PlateBackgroundProperty =
            DependencyProperty.Register("PlateBackground", typeof(Brush), typeof(MeterPlate), null);


        public Brush PlateBorderBrush
        {
            get { return (Brush)GetValue(PlateBorderBrushProperty); }
            set { SetValue(PlateBorderBrushProperty, value); }
        }
        public static readonly DependencyProperty PlateBorderBrushProperty =
            DependencyProperty.Register("PlateBorderBrush", typeof(Brush), typeof(MeterPlate), null);


        public Thickness PlateBorderThickness
        {
            get { return (Thickness)GetValue(PlateBorderThicknessProperty); }
            set { SetValue(PlateBorderThicknessProperty, value); }
        }
        public static readonly DependencyProperty PlateBorderThicknessProperty =
            DependencyProperty.Register("PlateBorderThickness", typeof(Thickness), typeof(MeterPlate), null);


        public static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as MeterPlate).DrawScale();
        }

        public static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MeterPlate dashboard = d as MeterPlate;
            dashboard.DrawAngle();
            //double step = 270.0 / (dashboard.Maximum - dashboard.Minimum);
            //DoubleAnimation da = new DoubleAnimation(dashboard.Value * step - 45, new Duration(TimeSpan.FromMilliseconds(200)));
            //dashboard.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da);


            dashboard.arckd.EndAngle = StartAngle + (-StartAngle * 2d) * ((double)dashboard.Value / dashboard.Maximum);
            dashboard.valueTxt.Text = dashboard.Value.ToString();
        }


        private void MeterPlate_Loaded(object sender, RoutedEventArgs e)
        {
            this.DrawScale();
        }
        /// <summary>
        /// 画表盘的刻度
        /// </summary>
        private void DrawScale()
        {
            this.canvasPlate.Children.Clear();

            for (double i = 0; i <= this.Maximum - this.Minimum; i++)
            {
                //添加刻度线
                Line lineScale = new Line();

                if (i % 10 == 0)
                {
                    //注意Math.Cos和Math.Sin的参数是弧度,记得将角度转为弧度制
                    lineScale.X1 = 200 - 170 * Math.Cos(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180);
                    lineScale.Y1 = 200 - 170 * Math.Sin(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180);
                    lineScale.Stroke = new SolidColorBrush(Colors.White);
                    lineScale.StrokeThickness = 2;

                    //添加刻度值
                    TextBlock txtScale = new TextBlock();
                    txtScale.Text = (i + this.Minimum).ToString();
                    txtScale.Width = 34;
                    txtScale.TextAlignment = TextAlignment.Center;
                    txtScale.Foreground = new SolidColorBrush(Colors.White);
                    txtScale.RenderTransform = new RotateTransform() { Angle = 45, CenterX = 17, CenterY = 8 };
                    txtScale.FontSize = 18;

                    Canvas.SetLeft(txtScale, 200 - 155 * Math.Cos(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180) - 17);
                    Canvas.SetTop(txtScale, 200 - 155 * Math.Sin(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180) - 10);

                    this.canvasPlate.Children.Add(txtScale);
                }
                else
                {
                    lineScale.X1 = 200 - 180 * Math.Cos(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180);
                    lineScale.Y1 = 200 - 180 * Math.Sin(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180);
                    lineScale.Stroke = new SolidColorBrush(Colors.White);
                    lineScale.StrokeThickness = 1;
                    lineScale.Opacity = 0.5;
                }

                lineScale.X2 = 200 - 190 * Math.Cos(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180);
                lineScale.Y2 = 200 - 190 * Math.Sin(i * (270 / (this.Maximum - this.Minimum)) * Math.PI / 180);
                this.canvasPlate.Children.Add(lineScale);
            }
        }

        private void DrawAngle()
        {
            double step = 270.0 / (this.Maximum - this.Minimum);
            DoubleAnimation da = new DoubleAnimation(this.Value * step - 45, new Duration(TimeSpan.FromMilliseconds(200)));
            this.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da);
        }
    }

界面代码

 <UserControl.Resources>
        <ResourceDictionary Source="pack://application:,,,/WINOWE.Control;component/BaseStyle.xaml" />
    </UserControl.Resources>
    <Grid>
        <Viewbox>
            <Border CornerRadius="200" ClipToBounds="True" 
                BorderBrush="{Binding PlateBorderBrush ,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor}}" 
                BorderThickness="{Binding PlateBorderThickness,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor}}" 
                Background="{Binding PlateBackground,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}">
                <Grid>
                    <Border>
                       
                    </Border>
                    <Canvas Name="canvasPlate" Width="400" Height="400"  Background="Transparent" Margin="14">
                        <Canvas.RenderTransform>
                            <RotateTransform Angle="-45" CenterX="200" CenterY="200"/>
                        </Canvas.RenderTransform>
                    </Canvas>
                    <ed:Arc ArcThickness="24" Opacity="0.1" 
        ArcThicknessUnit="Pixel"
        EndAngle="135.5"
        Fill="{DynamicResource ColorBrush}"
        StartAngle="-135.5"
        Stretch="None"
        StrokeEndLineCap="Round"
        StrokeStartLineCap="Round" />
                    <ed:Arc ArcThickness="24" Opacity="0.8" x:Name="arckd"
                            Fill="{DynamicResource ColorBrush1}"
        ArcThicknessUnit="Pixel"
        EndAngle="50"
        StartAngle="-135.5"
        Stretch="None"
        StrokeEndLineCap="Round"
        StrokeStartLineCap="Round" >
                        <!--<ed:Arc.Fill>
                            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                                <LinearGradientBrush.GradientStops>
                                    <GradientStop  Offset="0.1" Color="Transparent"/>
                                    <GradientStop  Offset="0.5" Color="{DynamicResource ColorLight}"/>
                                    <GradientStop  Offset="1" Color="{DynamicResource ColorLight1}"/>
                                </LinearGradientBrush.GradientStops>
                            </LinearGradientBrush>
                        </ed:Arc.Fill>-->
                    </ed:Arc>
                    <!--<Path Data="M100 200 A100 100 0 1 1 200 300" Stroke="#4169E1" Opacity="0.7" StrokeThickness="10" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
                        <Path.RenderTransform>
                            <RotateTransform Angle="-45" CenterX="200" CenterY="200"/>
                        </Path.RenderTransform>
                    </Path>-->
                    <!--  刻度盘当前值对应的圆弧  -->

                    <Border Width="240" Height="240" CornerRadius="120"  Opacity="0.5"  Margin="14">
                        <Border.Background>
                            <RadialGradientBrush RadiusX="1" RadiusY="1">
                                <GradientStop Color="{DynamicResource ColorLight2}" Offset="0.2"/>
                                <GradientStop Color="{DynamicResource ColorLight1}" Offset="0.3"/>
                                <GradientStop Color="{DynamicResource ColorLight}" Offset="0.5"/>
                            </RadialGradientBrush>
                        </Border.Background>
                    </Border>
                    <Path Name="pointer" Data="M200 205,40 200,200 195,200 205" 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>
                            <RotateTransform x:Name="rtPointer" Angle="-45"/>
                        </Path.RenderTransform>
                    </Path>
                    <Border Width="80" Height="80" CornerRadius="40"  Margin="14">
                        <Border.Background>
                            <RadialGradientBrush RadiusX="1" RadiusY="1">
                                <GradientStop Color="{DynamicResource ColorLight2}" Offset="0.2"/>
                                <GradientStop Color="{DynamicResource ColorLight1}" Offset="0.3"/>
                                <GradientStop Color="{DynamicResource ColorLight}" Offset="0.5"/>
                            </RadialGradientBrush>
                        </Border.Background>
                        <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
                            <TextBlock x:Name="valueTxt" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                            <TextBlock Text="km/h" FontSize="12" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        </StackPanel>
                    </Border>
                </Grid>
            </Border>
        </Viewbox>
    </Grid>

用法

 <dashboard:MeterPlate Name="meterPlate" Maximum="180" Minimum="0" Value="150" Margin="20"/>

gitee源代码下载:https://gitee.com/lm961031/wpf.-dashboard
csdn源代码下载:https://download.csdn.net/download/qq_42707143/87719177?spm=1001.2014.3001.5503

对你有用的话就点个关注和赞吧

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
WPF工控软件自定义控件是指在基于.NET6框架下使用WPF MVVM进行UI设计时,开发者可以自定义控件来满足特定的功能需求。这些自定义控件可以根据项目的需求进行设计和修改,以提供更好的用户体验和功能支持。 如果你对WPF工控软件自定义控件感兴趣,我建议你可以下载并编译相关的示例代码,并尝试修改它们以适应你的项目需求。你可以在这个链接上找到相关界面的示例代码:https://blog.csdn.net/u010186391/article/details/125601226。通过实际操作和修改示例代码,你可以更好地理解和应用WPF自定义控件、样式、MVVM和异步线程等方面的知识。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [NET6+WPF+MVVM ](https://download.csdn.net/download/u010186391/85926327)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [C# WPF 自定义控件 滑块控件 开关控件 ToggleButton Switcher](https://blog.csdn.net/shizu11zz/article/details/120459009)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值