183人参与 • 2025-01-01 • Windows Phone
自绘仪表盘 gauge
框架支持.net4 至 .net8;
visual studio 2022;
wpfdevelopers 1.1.0.3-preview 版本已正式发布!
该版本为预览版,欢迎各位开发者下载并体验。
来自 issue
逻辑实现
gauge
继承 rangebase
,支持设置最大值、最小值以及当前值,并且可以显示一个动态的百分比值、标题、刻度。
1. 新增 gauge.cs
依赖属性
title
:仪表盘的标题,默认值为 "wd
"。valueformat
:定义数值显示的格式( {0:0}%
),以百分比形式显示当前值。thickness
:设置仪表盘的边框,默认值 10
。public string title { get { return (string)getvalue(titleproperty); } set { setvalue(titleproperty, value); } } public string valueformat { get { return (string)getvalue(valueformatproperty); } set { setvalue(valueformatproperty, value); } } public double thickness { get { return (double)getvalue(thicknessproperty); } set { setvalue(thicknessproperty, value); } }
rangebase
依赖属性
value
:设置为 0.0
,表示当前的仪表盘值(默认 0%
)。minimum
:设置为 0.0
,表示仪表盘的最小值。maximum
:设置为 100.0
,表示仪表盘的最大值。public gauge() { setvalue(valueproperty, 0.0); setvalue(minimumproperty, 0.0); setvalue(maximumproperty, 100.0); }
2. 重写 onrender 方法绘制控件
背景:使用 ellipse
作为仪表盘的背景,背景色通过 background
属性设置,默认为 #293950
。
指针:根据当前值(value
),计算出指针的角度
,并使用 drawline
绘制红色指针。
外边框:使用渐变颜色绘制仪表盘的外边框。
刻度和标签:绘制了从最小值到最大值的刻度线,并在每个刻度绘制了对应的刻度值。
当前值显示:根据 valueformat
属性格式化显示当前值,并显示在仪表盘的底部位置。
protected override void onrender(drawingcontext drawingcontext) { base.onrender(drawingcontext); if (background == null) background = new solidcolorbrush((color)colorconverter.convertfromstring("#293950")); var width = actualwidth; var height = actualheight; var radius = math.min(width, height) / 2; drawingcontext.drawellipse(background, new pen(background, thickness), new point(width / 2, height / 2), radius, radius); var normalizedvalue = (value - minimum) / (maximum - minimum); var mappedangle = -220 + normalizedvalue * 260; var angleinradians = mappedangle * math.pi / 180; var pointerlength = radius * 0.7; var pointerx = width / 2 + pointerlength * math.cos(angleinradians); var pointery = height / 2 + pointerlength * math.sin(angleinradians); drawingcontext.drawline(new pen(brushes.red, 2), new point(width / 2, height / 2), new point(pointerx, pointery)); drawingcontext.drawellipse(brushes.white, new pen(brushes.red, 2), new point(width / 2, height / 2), width / 20, width / 20); var pathgeometry = new pathgeometry(); var startangle = -220; angleinradians = startangle * math.pi / 180; var startx = width / 2 + radius * math.cos(angleinradians); var starty = height / 2 + radius * math.sin(angleinradians); var pathfigure = new pathfigure() { startpoint = new point(startx, starty), }; var endangle = 40; angleinradians = endangle * math.pi / 180; var endx = width / 2 + radius * math.cos(angleinradians); var endy = height / 2 + radius * math.sin(angleinradians); var islargearc = (endangle - startangle > 180); var arcsegment = new arcsegment() { point = new point(endx, endy), size = new size(radius, radius), rotationangle = 0, sweepdirection = sweepdirection.clockwise, islargearc = islargearc, }; pathfigure.segments.add(arcsegment); pathgeometry.figures.add(pathfigure); if (borderbrush == null) { var gradientbrush = new lineargradientbrush { startpoint = new point(0, 0), endpoint = new point(1, 0) }; gradientbrush.gradientstops.add(new gradientstop((color)colorconverter.convertfromstring("#37d2c2"), 0.0)); gradientbrush.gradientstops.add(new gradientstop((color)colorconverter.convertfromstring("#5ad2b2"), 0.01)); gradientbrush.gradientstops.add(new gradientstop((color)colorconverter.convertfromstring("#b77d29"), 0.49)); gradientbrush.gradientstops.add(new gradientstop(colors.red, 1.0)); gradientbrush.freeze(); borderbrush = gradientbrush; } drawingcontext.drawgeometry(null, new pen(borderbrush, thickness), pathgeometry); var ticklength = radius * 0.1; var step = (maximum - minimum) / 10; for (int i = 0; i <= 10; i++) { var angle = startangle + (i * (endangle - startangle) / 10); var tickstartx = width / 2 + (radius - ticklength) * math.cos(angle * math.pi / 180); var tickstarty = height / 2 + (radius - ticklength) * math.sin(angle * math.pi / 180); var tickendx = width / 2 + (radius + thickness / 2) * math.cos(angle * math.pi / 180); var tickendy = height / 2 + (radius + thickness / 2) * math.sin(angle * math.pi / 180); drawingcontext.drawline(new pen(brushes.white, 2), new point(tickstartx, tickstarty), new point(tickendx, tickendy)); var labelvalue = minimum + step * i; var formattedtext = drawingcontexthelper.getformattedtext(labelvalue.tostring(),brushes.white, flowdirection.lefttoright,fontsize); var labelradius = radius - ticklength * 2; var labelx = width / 2 + labelradius * math.cos(angle * math.pi / 180) - formattedtext.width / 2; var labely = height / 2 + labelradius * math.sin(angle * math.pi / 180) - formattedtext.height / 2; drawingcontext.drawtext(formattedtext, new point(labelx, labely)); } var formattedvalue = "{0:0}%"; try { formattedvalue = string.format(valueformat, value); } catch (formatexception ex) { throw new invalidoperationexception("formatting failed ", ex); } var currentvaluetext = drawingcontexthelper.getformattedtext(formattedvalue, brushes.white, flowdirection.lefttoright, fontsize * 2); var valuex = width / 2 - currentvaluetext.width / 2; var valuey = height / 2 + radius * 0.4; drawingcontext.drawtext(currentvaluetext, new point(valuex, valuey)); var titlevalue = drawingcontexthelper.getformattedtext(title, brushes.white, flowdirection.lefttoright, fontsize); valuex = width / 2 - titlevalue.width / 2; valuey = height / 2 + radius * 0.8; drawingcontext.drawtext(titlevalue, new point(valuex, valuey)); }
xaml 示例
示例引入 wpfdevelopers 1.1.0.3-preview
的 nuget
正式包
<wrappanel horizontalalignment="center" verticalalignment="center"> <stackpanel verticalalignment="bottom"> <wd:gauge title="min" width="100" height="100" margin="10" horizontalalignment="center" verticalalignment="center" background="black" borderbrush="red" fontsize="8" maximum="90" minimum="30" thickness="3" valueformat="{}{0:0}值" value="{binding elementname=myslider2, path=value}" /> <slider name="myslider2" width="200" margin="0,0,0,20" horizontalalignment="center" verticalalignment="bottom" maximum="90" minimum="30" /> </stackpanel> <stackpanel> <wd:gauge title="反对率" width="200" height="200" margin="10" horizontalalignment="center" verticalalignment="center" valueformat="{}{0:0}%" value="{binding elementname=myslider, path=value}" /> <slider name="myslider" width="200" margin="0,0,0,20" horizontalalignment="center" verticalalignment="bottom" maximum="100" minimum="0" /> </stackpanel> <stackpanel verticalalignment="bottom"> <wd:gauge title="max" width="100" height="100" margin="10" horizontalalignment="center" verticalalignment="center" background="black" borderbrush="dodgerblue" fontsize="8" maximum="90" minimum="30" thickness="3" valueformat="{}{0:0}值" value="{binding elementname=myslider3, path=value}" /> <slider name="myslider3" width="200" margin="0,0,0,20" horizontalalignment="center" verticalalignment="bottom" maximum="90" minimum="30" /> </stackpanel> </wrappanel>
效果图
到此这篇关于wpf实现自绘仪表盘gauge的文章就介绍到这了,更多相关wpf自绘仪表盘内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论