如何用WPF的DrawingContext绘制一个长尾词温度计图示?

2026-03-31 10:041阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1239个文字,预计阅读时间需要5分钟。

如何用WPF的DrawingContext绘制一个长尾词温度计图示?

使用WPF和DrawingContext绘制温度计框架,兼容.NET 4.0以上版本;在Visual Studio 2022中开发;项目遵循MIT开源许可;定义Interval步长、MaxValue最大温度值、MinValue最小温度值和CurrentGeometry当前温度几何形状。

WPF 使用 DrawingContext 绘制温度计

框架使用大于等于.NET40

Visual Studio 2022;

项目使用MIT开源许可协议;

定义Interval步长、MaxValue最大温度值、MinValue最小温度值。

CurrentGeometry重新绘制当前刻度的Path值。

CurrentValue当前值如果发生变化时则去重新CurrentGeometry

OnRender绘制如下

  • RoundedRectangle温度计的外边框。
  • 使用方法DrawText单字绘制华氏温度文本Y轴变化。
  • 使用方法DrawText单字绘制摄氏温度文本Y轴变化。
  • 使用方法DrawText绘制温度计两侧的刻度数值。
  • 使用方法DrawLine绘制温度计两侧的刻度线。

实现代码

1) 准备Thermometer.cs如下:

using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace WPFDevelopers.Controls {     public class Thermometer : Control     {         public static readonly DependencyProperty MaxValueProperty =             DependencyProperty.Register("MaxValue", typeof(double), typeof(Thermometer), new UIPropertyMetadata(40.0));         public static readonly DependencyProperty MinValueProperty =             DependencyProperty.Register("MinValue", typeof(double), typeof(Thermometer), new UIPropertyMetadata(-10.0));         /// <summary>         ///     当前值         /// </summary>         public static readonly DependencyProperty CurrentValueProperty =             DependencyProperty.Register("CurrentValue", typeof(double), typeof(Thermometer),                 new UIPropertyMetadata(OnCurrentValueChanged));         /// <summary>         ///     步长         /// </summary>         public static readonly DependencyProperty IntervalProperty =             DependencyProperty.Register("Interval", typeof(double), typeof(Thermometer), new UIPropertyMetadata(10.0));         /// <summary>         ///     当前值的图形坐标点         /// </summary>         public static readonly DependencyProperty CurrentGeometryProperty =             DependencyProperty.Register("CurrentGeometry", typeof(Geometry), typeof(Thermometer), new PropertyMetadata(                 Geometry.Parse(@"M 2 132.8                               a 4 4 0 0 1 4 -4                               h 18                               a 4 4 0 0 1 4 4                               v 32.2                               a 4 4 0 0 1 -4 4                               h -18                               a 4 4 0 0 1 -4 -4 z")));         /// <summary>         ///     构造函数         /// </summary>         static Thermometer()         {             DefaultStyleKeyProperty.OverrideMetadata(typeof(Thermometer),                 new FrameworkPropertyMetadata(typeof(Thermometer)));         }         public double MaxValue         {             get => (double)GetValue(MaxValueProperty);             set => SetValue(MaxValueProperty, value);         }         public double MinValue         {             get => (double)GetValue(MinValueProperty);             set => SetValue(MinValueProperty, value);         }         public double CurrentValue         {             get => (double)GetValue(CurrentValueProperty);             set             {                 SetValue(CurrentValueProperty, value);                 PaintPath();             }         }         public double Interval         {             get => (double)GetValue(IntervalProperty);             set => SetValue(IntervalProperty, value);         }         public Geometry CurrentGeometry         {             get => (Geometry)GetValue(CurrentGeometryProperty);             set => SetValue(CurrentGeometryProperty, value);         }         private static void OnCurrentValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)         {             var thermometer = d as Thermometer;             thermometer.CurrentValue = Convert.ToDouble(e.NewValue);         }         public override void OnApplyTemplate()         {             base.OnApplyTemplate();             PaintPath();         }         protected override void OnRender(DrawingContext drawingContext)         {             var brush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#82848A"));             var rect = new Rect();             rect.Width = 30;             rect.Height = 169;             drawingContext.DrawRoundedRectangle(Brushes.Transparent,                 new Pen(brush, 2d),                 rect, 8d, 8d);             #region 华氏温度             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("华",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D),                 new Point(-49, 115));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("氏",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D),                 new Point(-49, 115 + 14));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("温",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D),                 new Point(-49, 115 + 28));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("度",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D),                 new Point(-49, 115 + 42));             #endregion             #region 摄氏温度             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("摄",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D), new Point(75, 115));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("氏",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D), new Point(75, 115 + 14));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("温",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D), new Point(75, 115 + 28));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("度",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D), new Point(75, 115 + 42));             #endregion             #region 画刻度             var total_Value = MaxValue - MinValue;             var cnt = total_Value / Interval;             var one_value = 161d / cnt;             for (var i = 0; i <= cnt; i++)             {                 var formattedText = DrawingContextHelper.GetFormattedText($"{MaxValue - i * Interval}",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D);                 drawingContext.DrawText(formattedText,                     new Point(43, i * one_value - formattedText.Height / 2d)); //减去字体高度的一半                 formattedText = DrawingContextHelper.GetFormattedText($"{(MaxValue - i * Interval) * 1.8d + 32d}",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D);                 drawingContext.DrawText(formattedText, new Point(-13, i * one_value - formattedText.Height / 2d));                 if (i != 0 && i != 5)                 {                     drawingContext.DrawLine(new Pen(Brushes.Black, 1d),                         new Point(4, i * one_value), new Point(6, i * one_value));                     drawingContext.DrawLine(new Pen(Brushes.Black, 1d),                         new Point(24, i * one_value), new Point(26, i * one_value));                 }             }             #endregion         }         /// <summary>         ///     动态计算当前值图形坐标点         /// </summary>         private void PaintPath()         {             var one_value = 161d / ((MaxValue - MinValue) / Interval);             var width = 26d;             var height = 169d - (MaxValue - CurrentValue) * (one_value / Interval);             var x = 2d;             var y = 169d - (169d - (MaxValue - CurrentValue) * (one_value / Interval));             CurrentGeometry = Geometry.Parse($@"M 2 {y + 4}                               a 4 4 0 0 1 4 -4                               h {width - 8}                               a 4 4 0 0 1 4 4                               v {height - 8}                               a 4 4 0 0 1 -4 4                               h -{width - 8}                               a 4 4 0 0 1 -4 -4 z");         }     } }

2) 使用ThermometerExample.xaml.cs如下:

<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.ThermometerExample"              xmlns="schemas.microsoft.com/winfx/2006/xaml/presentation"              xmlns:x="schemas.microsoft.com/winfx/2006/xaml"              xmlns:mc="schemas.openxmlformats.org/markup-compatibility/2006"               xmlns:d="schemas.microsoft.com/expression/blend/2008"               xmlns:wpfdev="github.com/WPFDevelopersOrg/WPFDevelopers"              xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"              mc:Ignorable="d"               d:DesignHeight="450" d:DesignWidth="800">     <Grid>         <Border Background="{DynamicResource BackgroundSolidColorBrush}"                  CornerRadius="12"                 Width="400" Height="400"                 Effect="{StaticResource NormalShadowDepth}">             <Grid>                 <Grid.ColumnDefinitions>                     <ColumnDefinition/>                     <ColumnDefinition/>                 </Grid.ColumnDefinitions>                 <Slider x:Name="PART_Slider" IsSnapToTickEnabled="True"                 Value="10"                 Minimum="-10"                 Maximum="40"                  Orientation="Vertical"                 Height="300"/>                 <Grid VerticalAlignment="Center"                       Margin="160,0,0,0">                     <Path Fill="{StaticResource PrimaryMouseOverSolidColorBrush}"                            Stroke="{StaticResource PrimaryMouseOverSolidColorBrush}"                           StrokeThickness="1" Opacity=".6"                           Data="{Binding ElementName=PART_Thermometer, Path=CurrentGeometry,Mode=TwoWay}"/>                     <wpfdev:Thermometer x:Name="PART_Thermometer"                                         CurrentValue="{Binding ElementName=PART_Slider,Path=Value,Mode=TwoWay}"/>                 </Grid>                 <TextBlock Text="{Binding ElementName=PART_Thermometer,Path=CurrentValue,StringFormat={}{0}℃}"                             FontSize="24" Grid.Column="1"                            Foreground="{StaticResource PrimaryPressedSolidColorBrush}" FontFamily="Bahnschrift"                            HorizontalAlignment="Center" VerticalAlignment="Center"/>             </Grid>         </Border>     </Grid> </UserControl>

实现效果

如何用WPF的DrawingContext绘制一个长尾词温度计图示?

到此这篇关于WPF利用DrawingContext实现绘制温度计的文章就介绍到这了,更多相关WPF DrawingContext温度计内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!

本文共计1239个文字,预计阅读时间需要5分钟。

如何用WPF的DrawingContext绘制一个长尾词温度计图示?

使用WPF和DrawingContext绘制温度计框架,兼容.NET 4.0以上版本;在Visual Studio 2022中开发;项目遵循MIT开源许可;定义Interval步长、MaxValue最大温度值、MinValue最小温度值和CurrentGeometry当前温度几何形状。

WPF 使用 DrawingContext 绘制温度计

框架使用大于等于.NET40

Visual Studio 2022;

项目使用MIT开源许可协议;

定义Interval步长、MaxValue最大温度值、MinValue最小温度值。

CurrentGeometry重新绘制当前刻度的Path值。

CurrentValue当前值如果发生变化时则去重新CurrentGeometry

OnRender绘制如下

  • RoundedRectangle温度计的外边框。
  • 使用方法DrawText单字绘制华氏温度文本Y轴变化。
  • 使用方法DrawText单字绘制摄氏温度文本Y轴变化。
  • 使用方法DrawText绘制温度计两侧的刻度数值。
  • 使用方法DrawLine绘制温度计两侧的刻度线。

实现代码

1) 准备Thermometer.cs如下:

using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace WPFDevelopers.Controls {     public class Thermometer : Control     {         public static readonly DependencyProperty MaxValueProperty =             DependencyProperty.Register("MaxValue", typeof(double), typeof(Thermometer), new UIPropertyMetadata(40.0));         public static readonly DependencyProperty MinValueProperty =             DependencyProperty.Register("MinValue", typeof(double), typeof(Thermometer), new UIPropertyMetadata(-10.0));         /// <summary>         ///     当前值         /// </summary>         public static readonly DependencyProperty CurrentValueProperty =             DependencyProperty.Register("CurrentValue", typeof(double), typeof(Thermometer),                 new UIPropertyMetadata(OnCurrentValueChanged));         /// <summary>         ///     步长         /// </summary>         public static readonly DependencyProperty IntervalProperty =             DependencyProperty.Register("Interval", typeof(double), typeof(Thermometer), new UIPropertyMetadata(10.0));         /// <summary>         ///     当前值的图形坐标点         /// </summary>         public static readonly DependencyProperty CurrentGeometryProperty =             DependencyProperty.Register("CurrentGeometry", typeof(Geometry), typeof(Thermometer), new PropertyMetadata(                 Geometry.Parse(@"M 2 132.8                               a 4 4 0 0 1 4 -4                               h 18                               a 4 4 0 0 1 4 4                               v 32.2                               a 4 4 0 0 1 -4 4                               h -18                               a 4 4 0 0 1 -4 -4 z")));         /// <summary>         ///     构造函数         /// </summary>         static Thermometer()         {             DefaultStyleKeyProperty.OverrideMetadata(typeof(Thermometer),                 new FrameworkPropertyMetadata(typeof(Thermometer)));         }         public double MaxValue         {             get => (double)GetValue(MaxValueProperty);             set => SetValue(MaxValueProperty, value);         }         public double MinValue         {             get => (double)GetValue(MinValueProperty);             set => SetValue(MinValueProperty, value);         }         public double CurrentValue         {             get => (double)GetValue(CurrentValueProperty);             set             {                 SetValue(CurrentValueProperty, value);                 PaintPath();             }         }         public double Interval         {             get => (double)GetValue(IntervalProperty);             set => SetValue(IntervalProperty, value);         }         public Geometry CurrentGeometry         {             get => (Geometry)GetValue(CurrentGeometryProperty);             set => SetValue(CurrentGeometryProperty, value);         }         private static void OnCurrentValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)         {             var thermometer = d as Thermometer;             thermometer.CurrentValue = Convert.ToDouble(e.NewValue);         }         public override void OnApplyTemplate()         {             base.OnApplyTemplate();             PaintPath();         }         protected override void OnRender(DrawingContext drawingContext)         {             var brush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#82848A"));             var rect = new Rect();             rect.Width = 30;             rect.Height = 169;             drawingContext.DrawRoundedRectangle(Brushes.Transparent,                 new Pen(brush, 2d),                 rect, 8d, 8d);             #region 华氏温度             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("华",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D),                 new Point(-49, 115));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("氏",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D),                 new Point(-49, 115 + 14));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("温",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D),                 new Point(-49, 115 + 28));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("度",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D),                 new Point(-49, 115 + 42));             #endregion             #region 摄氏温度             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("摄",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D), new Point(75, 115));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("氏",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D), new Point(75, 115 + 14));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("温",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D), new Point(75, 115 + 28));             drawingContext.DrawText(                 DrawingContextHelper.GetFormattedText("度",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D), new Point(75, 115 + 42));             #endregion             #region 画刻度             var total_Value = MaxValue - MinValue;             var cnt = total_Value / Interval;             var one_value = 161d / cnt;             for (var i = 0; i <= cnt; i++)             {                 var formattedText = DrawingContextHelper.GetFormattedText($"{MaxValue - i * Interval}",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), FlowDirection.LeftToRight,                     14D);                 drawingContext.DrawText(formattedText,                     new Point(43, i * one_value - formattedText.Height / 2d)); //减去字体高度的一半                 formattedText = DrawingContextHelper.GetFormattedText($"{(MaxValue - i * Interval) * 1.8d + 32d}",                     (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#82848A"), textSize: 14D);                 drawingContext.DrawText(formattedText, new Point(-13, i * one_value - formattedText.Height / 2d));                 if (i != 0 && i != 5)                 {                     drawingContext.DrawLine(new Pen(Brushes.Black, 1d),                         new Point(4, i * one_value), new Point(6, i * one_value));                     drawingContext.DrawLine(new Pen(Brushes.Black, 1d),                         new Point(24, i * one_value), new Point(26, i * one_value));                 }             }             #endregion         }         /// <summary>         ///     动态计算当前值图形坐标点         /// </summary>         private void PaintPath()         {             var one_value = 161d / ((MaxValue - MinValue) / Interval);             var width = 26d;             var height = 169d - (MaxValue - CurrentValue) * (one_value / Interval);             var x = 2d;             var y = 169d - (169d - (MaxValue - CurrentValue) * (one_value / Interval));             CurrentGeometry = Geometry.Parse($@"M 2 {y + 4}                               a 4 4 0 0 1 4 -4                               h {width - 8}                               a 4 4 0 0 1 4 4                               v {height - 8}                               a 4 4 0 0 1 -4 4                               h -{width - 8}                               a 4 4 0 0 1 -4 -4 z");         }     } }

2) 使用ThermometerExample.xaml.cs如下:

<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.ThermometerExample"              xmlns="schemas.microsoft.com/winfx/2006/xaml/presentation"              xmlns:x="schemas.microsoft.com/winfx/2006/xaml"              xmlns:mc="schemas.openxmlformats.org/markup-compatibility/2006"               xmlns:d="schemas.microsoft.com/expression/blend/2008"               xmlns:wpfdev="github.com/WPFDevelopersOrg/WPFDevelopers"              xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"              mc:Ignorable="d"               d:DesignHeight="450" d:DesignWidth="800">     <Grid>         <Border Background="{DynamicResource BackgroundSolidColorBrush}"                  CornerRadius="12"                 Width="400" Height="400"                 Effect="{StaticResource NormalShadowDepth}">             <Grid>                 <Grid.ColumnDefinitions>                     <ColumnDefinition/>                     <ColumnDefinition/>                 </Grid.ColumnDefinitions>                 <Slider x:Name="PART_Slider" IsSnapToTickEnabled="True"                 Value="10"                 Minimum="-10"                 Maximum="40"                  Orientation="Vertical"                 Height="300"/>                 <Grid VerticalAlignment="Center"                       Margin="160,0,0,0">                     <Path Fill="{StaticResource PrimaryMouseOverSolidColorBrush}"                            Stroke="{StaticResource PrimaryMouseOverSolidColorBrush}"                           StrokeThickness="1" Opacity=".6"                           Data="{Binding ElementName=PART_Thermometer, Path=CurrentGeometry,Mode=TwoWay}"/>                     <wpfdev:Thermometer x:Name="PART_Thermometer"                                         CurrentValue="{Binding ElementName=PART_Slider,Path=Value,Mode=TwoWay}"/>                 </Grid>                 <TextBlock Text="{Binding ElementName=PART_Thermometer,Path=CurrentValue,StringFormat={}{0}℃}"                             FontSize="24" Grid.Column="1"                            Foreground="{StaticResource PrimaryPressedSolidColorBrush}" FontFamily="Bahnschrift"                            HorizontalAlignment="Center" VerticalAlignment="Center"/>             </Grid>         </Border>     </Grid> </UserControl>

实现效果

如何用WPF的DrawingContext绘制一个长尾词温度计图示?

到此这篇关于WPF利用DrawingContext实现绘制温度计的文章就介绍到这了,更多相关WPF DrawingContext温度计内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!