WPF 使用 DrawingContext 绘制温度计

 WPF 使用 DrawingContext 绘制温度计

控件名:Thermometer

作者: WPFDevelopersOrg

原文链接:    https://github.com/WPFDevelopersOrg/WPFDevelopers

  • 框架使用大于等于.NET40

  • Visual Studio 2022;

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

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

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

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

  • OnRender 绘制如下

    • RoundedRectangle温度计的外边框。

    • 使用方法DrawText 单字绘制 华氏温度文本Y轴变化。

    • 使用方法DrawText 单字绘制 摄氏温度文本Y轴变化。

    • 使用方法DrawText 绘制温度计两侧的刻度数值。

    • 使用方法DrawLine 绘制温度计两侧的刻度线。

ac1c5cbdcabfb8787e0de0cffe2122b6.png

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.8a 4 4 0 0 1 4 -4h 18a 4 4 0 0 1 4 4v 32.2a 4 4 0 0 1 -4 4h -18a 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 -4h {width - 8}a 4 4 0 0 1 4 4v {height - 8}a 4 4 0 0 1 -4 4h -{width - 8}a 4 4 0 0 1 -4 -4 z");}}
}

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

<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.ThermometerExample"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:wpfdev="https://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>

 鸣谢 - 帅嘉欣

aa6ff06a881ddffd6acced90cc87198f.gif

Github|ThermometerExample[1]
码云|ThermometerExample[2]

参考资料

[1]

Github|ThermometerExample: https://github.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Samples/ExampleViews/ThermometerExample.xaml

[2]

码云|ThermometerExample: https://gitee.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Samples/ExampleViews/ThermometerExample.xaml

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/282422.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

装win10系统

一、使用U盘介质安装win10系统&#xff08;官方方式&#xff09; 官方安装工具下载地址&#xff1a;https://www.microsoft.com/zh-cn/software-download/windows10 1、进入官方安装工具下载页面&#xff0c;点击立即下载工具&#xff0c;下载安装工具。2、下载完成后&#xff…

C#构造函数、操作符重载以及自定义类型转换

构造器 构造器&#xff08;构造函数&#xff09;是将类型的实例初始化的特殊方法。构造器可分为实例构造器和类型构造器&#xff0c;本节将详细介绍有关内容。 实例构造器 顾名思义&#xff0c;实例构造器的作用就是对类型的实例进行初始化。如果类没有显示定义任何构造器&…

「Dotnet 工具箱」 自动生成并绑定 Https 证书

这里是 Dotnet 工具箱&#xff0c;定期分享 Dotnet 有趣&#xff0c;有用的工具&#xff0c;不要忘记关注。介绍LettuceEncrypt 是一个使用 C# 开发的免费的工具&#xff0c;它和证书颁发机构 &#xff08;CA&#xff09;集成&#xff0c;比如 Lets Encrypt&#xff0c;它使用了…

1115: 零起点学算法22——华氏摄氏温度转换

1115: 零起点学算法22——华氏摄氏温度转换 Time Limit: 1 Sec Memory Limit: 64 MB 64bit IO Format: %lldSubmitted: 3522 Accepted: 1456[Submit][Status][Web Board]Description 输入一个华氏温度&#xff0c;根据公式C(5/9)(F-32)计算对应的摄氏温度。 Input 输入一个…

Navicat Premium 12 的安装破解

Navicat 这款软件可以说 是数据库可视化操作的神器, 有绿色的 (最原始版本, 好像现在已经不维护了) , 有金色的 (改良收费版 ) , 还有彩色的 (最新版) , 这里 , 推荐使用彩色版 (也就是截止目前最新的版本 12.0.27). 操作的话, 感觉相比于小绿和小金有很大改进 , 很棒 , 在此给…

Vuejs——组件——slot内容分发

2019独角兽企业重金招聘Python工程师标准>>> ①概述&#xff1a; 简单来说&#xff0c;假如父组件需要在子组件内放一些DOM&#xff0c;那么这些DOM是显示、不显示、在哪个地方显示、如何显示&#xff0c;就是slot分发负责的活。 ②默认情况下 父组件在子组件内套的…

turtle库基础练习

画一组同切圆 import turtleturtle.shape(turtle)turtle.circle(10) turtle.circle(20) turtle.circle(30) turtle.circle(40) turtle.circle(50) turtle.circle(60) turtle.circle(70) turtle.circle(80)turtle.hideturtle() turtle.done() 画一组同心圆 import turtleturtle.…

检查你的项目的引用包依赖关系

2019独角兽企业重金招聘Python工程师标准>>> 随着着开发的进展,你的项目越来越大,引用的第三方包越来越多,但如何查看都依赖了哪些包,甚至传递依赖又是怎样? 首先解决这个问题的前提,你的项目需要是maven项目,然后可以做如下设置: 选中项目&#xff0c;右键->ru…

git 项目操作

1 创建本地仓库,克隆远程项目代码到本地仓库2. 当我们在本地写了一些代码之后 , 查看本地仓库状态3. 提交改变到待提交区 git add .4. 提交代码到待推送区 git commit -m "新建项目kuman"5. 将本地代码推送到远程代码仓库 git push origin master:nanle 注: 将本地m…

(二)SpringBoot功能

web开发 spring boot web开发非常的简单&#xff0c;其中包括常用的json输出、filters、property、log等 json 接口开发 在以前的spring 开发的时候需要我们提供json接口的时候需要做那些配置呢 就这样我们会经常由于配置错误&#xff0c;导致406错误等等&#xff0c;spring bo…

----斐波那契数列---eval函数----类递归思想 栈 进出 思想

------------ 斐波那契 数列 ---------------【1&#xff0c;1,2,3,5,8,13,21,34&#xff0c;...】 1 列表方法实现 # l[1,1] # # # while len(l)<20: # # l.append(l[-1]l[-2]) # # print(l) # # while len(l)!4: # l.append(l[-1]l[-2]) # print(l) # 2 …

HybridTime - Accessible Global Consistency with High Clock Uncertainty

Amazon’s Dynamo [9] and Facebook’s Cassandra [13], relax the consistency model&#xff0c;and offer only eventual consistency. Others such as HBase [1] and BigTable [4] offer strong consistency only for operations touching a single partition, but not acr…

公司目前实行的git团队协作方案

1. git init 新建本地仓库2. git clone 项目地址 获取远程master代码3. 在本地master代码上进行开发, 并将修改提交到待推送区4. 开发完, 在本地master分支基础上创建ready分支5. 在本地ready分支上(本地测试分支), 拉取并合并远程nanle分支最新代码(远程测试分支)6. 将本地re…

bzoj3122 [Sdoi2013]随机数生成器(bsgs+扩欧+数列)

Description Input 输入含有多组数据&#xff0c;第一行一个正整数T&#xff0c;表示这个测试点内的数据组数。 接下来T行&#xff0c;每行有五个整数p&#xff0c;a&#xff0c;b&#xff0c;X1&#xff0c;t&#xff0c;表示一组数据。保证X1和t都是合法的页码。 注意&…

挑选合适自己的一门编程语言

2019独角兽企业重金招聘Python工程师标准>>> 导读想学编程的原因有很多&#xff0c;你也许是想要做一个程序&#xff0c;又或者你只是想投身于这个行业&#xff0c;所以&#xff0c;在选择你的第一门编程语言之前&#xff0c;问问你自己&#xff1a;你想要在哪里运行…

css 实现章节名称不换行,多余部分用 ... 代替

修改之前:修改之后: 代码: <p style "white-space: nowrap;text-overflow: ellipsis;overflow: hidden;"><? $d[name] ?></p> <i><? $d[pen_name] ?></i> <i><?phpforeach ($d[tags] as $t) {echo $t[tag_name];…

.NET 反向代理-YARP 部署Https(SSL)

相关文章&#xff1a;.NET 反向代理-YARP.NET 反向代理-YARP 根据域名转发分享一个基于Abp 和Yarp 开发的API网关项目使用 Yarp 做网关YARP&#xff08;Yet Another Reverse Proxy&#xff09;是使用 .NET 构建的高度可定制的反向代理C# 开源一个基于 yarp 的 API 网关 Demo&am…

shell脚本--cut命令

bash&shell系列文章&#xff1a;http://www.cnblogs.com/f-ck-need-u/p/7048359.html 1.1 选项说明 cut命令将行按指定的分隔符分割成多列&#xff0c;它的弱点在于不好处理多个分隔符重复的情况&#xff0c;因此经常结合tr的压缩功能。 -b&#xff1a;按字节筛选&#xff…

Windows 下 Redis 的下载和安装

一 安装redis 1. 下载redis https://github.com/MicrosoftArchive/redis/releases 注: 如果上面网址下载不了, 就到这里下载 https://download.csdn.net/download/m_nanle_xiaobudiu/104370342. 解压压缩文件夹3. 运行redis服务端到此 , redis已经可以正常使用了,但是为了方便…

什么是行内块元素?

2019独角兽企业重金招聘Python工程师标准>>> 我们都知道行内元素和块级元素&#xff0c;在实际开发中&#xff0c;经常会听到行内块元素&#xff0c;那么什么是行内块元素呢&#xff1f; 行内块元素实际就是把块元素以行的形式展现,保留了块元素可以设置的对应CSS属…