1. 前言

最近需要一个 WPF 的表盘控件,之前 Cyril-hcj 写过一篇不错的博客 《WPF在圆上画出刻度线》,里面介绍了一些原理及详细实现的代码:

double radius = BackEllipse.Width / 2;
double min = 0; double max = 100;
double step = 360.0 / (max - min);
for (int i = 0; i < max - min; i++)
{
Line lineScale = new Line
{
X1 = ((radius - 20) * Math.Cos(i * step * Math.PI / 180)) + radius,
Y1 = ((radius - 20) * Math.Sin(i * step * Math.PI / 180)) + radius,
X2 = (radius * Math.Cos(i * step * Math.PI / 180)) + radius,
Y2 = (radius * Math.Sin(i * step * Math.PI / 180)) + radius,
Stroke = Brushes.Red,
StrokeThickness = 2
}; MainCanvas.Children.Add(lineScale);
}

我本来想直接参考这篇文章的代码封装成一个控件,但我用得不多封装起来又麻烦,索性考虑用 ItemsControl 实现还比较方便些。

2. 使用 CirclePanel 实现

既然要用 ItemsControl,那首先要有个集合作为它的 ItemsSource。在 XAML 中可以用以下方式创建一个集合:

<x:Array x:Key="AuthorList" Type="{x:Type sys:String}">
<sys:String>Mahesh Chand</sys:String>
<sys:String>Praveen Kumar</sys:String>
<sys:String>Raj Beniwal</sys:String>
<sys:String>Neel Beniwal</sys:String>
<sys:String>Sam Hobbs</sys:String>
</x:Array>

不过也可以不这么大费周章,在 .NET 中 string 也是一个集合,

可以用作 ItemsControl 的 ItemsSource。但在 Xaml 上直接写 ItemsSource="somestring"` 会报错,可以用 ContentControl 包装一下,写成这样:

<ContentControl Content="111111111111">
<ContentControl.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="10"
Height="3"
Fill="#383838" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>

这样 UI 上就会重复创建 12 个 Rectangle,然后设置 ItemsControl 的 ItemsPanel,让这些 Rectangle 按着圆形布局。这里我使用了 HandyControl 的 CirclePanel,这个 Panel 用起来十分简单,它会自动将 Children 在圆形上等距分布:

<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<hc:CirclePanel Diameter="310" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

顺便一提,HandyControl 的 Nuget 地址为:https://www.nuget.org/packages/HandyControl/3.3.0?_src=template

最后再添加一些边框和内阴影,一个简单的表盘就完成了。

3. 用 DataTrigger 实现不同的指针

上面的表盘还是做得太朴素了,我们可以用 DataTrigger 让它变得更复杂些。首先改变 ItemsSource 的内容,让它变成 60 个指针。反正只是 60 个,也没多复杂,复制粘贴几次就有了:

<ContentControl Content="100001000010000100001000010000100001000010000100001000010000">

然后设置 DataTrigger,在 Item 的内容等于 1 时指针变粗些:

<DataTemplate>
<Rectangle x:Name="Tick"
Width="10"
Height="2"
Fill="#383838" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="1">
<Setter TargetName="Tick" Property="Height" Value="5" />
<Setter TargetName="Tick" Property="Width" Value="16" />
<Setter TargetName="Tick" Property="Margin" Value="0,0,3,0" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

这样看起来就和真的表盘差不多了。

4. 用 OpacityMask 实现方形表盘

这次更进一步实现一个方形的表盘,首先将 CirclePanel 的尺寸变大,然后加长刻度线:

然后在它的背后藏一个 Border,用它作为刻度线的 OpacityMask,这样就完成了一个方形表盘:

<Border x:Name="Border"
Width="340"
Height="340"
BorderBrush="White"
BorderThickness="16" />
<ContentControl Style="{StaticResource ClockControl2}">
<ContentControl Margin="-100" Content="100001000010000100001000010000100001000010000100001000010000">
<ContentControl.OpacityMask>
<VisualBrush Stretch="None" Visual="{Binding ElementName=Border}" />
</ContentControl.OpacityMask>

5. 用 ArcPanel 实现仪表盘

CirclePanel 虽然很好用,可惜的是不能实现弧形布局,于是我又另外找了 HeBianGu 的 ArcPanel 来实现仪表板,用它替换掉 CirclePanel 即可实现弧形布局的刻度线:

<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<h:ArcPanel Width="200"
Height="200"
AngleToCenter="True"
EndAngle="-30"
StartAngle="210" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

5. 最后

这篇文章介绍了如何实现表盘刻度,基本都是用别人的 Panel 实现布局,我自己反而没出什么力,感谢两位大佬实现的优秀 Panel。

顺便一提,也可以用 Ellipe 配合 StrokeDashArray 简单做出这种效果,只是如果太粗的指针会看得出来是个扇形,不是矩形,而且还不够灵活。

源码:https://github.com/DinoChan/wpf_design_and_animation_lab

[WPF] 使用 HandyControl 的 CirclePanel 画出表盘刻度的更多相关文章

  1. WPF 如何画出1像素的线

    如何有人告诉你,请你画出1像素的线,是不是觉得很简单,实际上在 WPF 上还是比较难的. 本文告诉大家,如何让画出的线不模糊 画出线的第一个方法,创建一个 Canvas ,添加一个线 界面代码 < ...

  2. WPF Blend 脑洞大开的问题:如何用Blend得到或画出一个凹槽、曲面。

    原文:WPF Blend 脑洞大开的问题:如何用Blend得到或画出一个凹槽.曲面. 目标图: 步骤一(放置一个矩形,填充蓝色): 步骤二(复制该矩形,并调整边角,填充粉红色): 第三部:让图形部分重 ...

  3. wpf 在不同DPI下如何在DrawingVisual中画出清晰的图形

    环境Win10 VS2017 .Net Framework4.7.1   本文仅讨论在DrawingVisual中进行的画图.   WPF单位,系统DPI,显示器DPI三者的定义及关系 WPF单位:一 ...

  4. WPF在圆上画出刻度线

    思路 我们可以使用Ellipse先画出一个圆当背景,然后用Canvas再叠加画上刻度线,就能得到如下的效果 我们先用Ellipse画一个橙色的圆,然后将Canvas的宽度和高度绑定到Ellipse的宽 ...

  5. 像画笔一样慢慢画出Path的三种方法(补充第四种)

    今天大家在群里大家非常热闹的讨论像画笔一样慢慢画出Path的这种效果该如何实现. 北京-LGL 博客号@ligl007发起了这个话题.然后各路高手踊跃发表意见.最后雷叔 上海-雷蒙 博客号@雷蒙之星 ...

  6. 通通玩blend美工(8)——动态绘制路径动画,画出个萌妹子~

    原文:通通玩blend美工(8)--动态绘制路径动画,画出个萌妹子~ 2年前我在玩Flex的时候就一直有一个疑问,就是如何来实现一个蚊香慢慢烧完的Loading动画呢? 刚经历了某甲方高强度一个月的洗 ...

  7. win2d 通过 CanvasActiveLayer 画出透明度和裁剪

    本文告诉大家如果在 UWP 的 win2d 通过 CanvasActiveLayer 创建一层,在这里画出的图片有透明度或者裁剪 在 win2d 如果需要对某个元素裁剪,可以使用很多方法,本文只是告诉 ...

  8. 在C#的WPF程序使用XAML实现画线

    在WPF中画直线.新建WPF应用程序,使用XAML画直线.使用X1.Y1两个属性可以设置直线的起点坐标,X2.Y2两个属性则可以设置直线的终点坐标.控制起点/终点坐标就可以实现平行.交错等效果.Str ...

  9. H5坦克大战之【画出坦克】

    今天是个特殊的日子,圣诞节,也是周末,在这里先祝大家圣诞快乐!喜庆的日子,我们可以稍微放松一下,扯一扯昨天雷霆对战凯尔特人的比赛,这场比赛大威少又双叒叕拿下三双,而且是一个45+11+11的超级三双, ...

随机推荐

  1. php个性代码注释

      // _ooOoo_ // o8888888o // 88" . "88 // (| -_- |) // O\ = /O // ____/`---'\____ // . ' \ ...

  2. 【Java面试】请简单说一下你对受检异常和非受检异常的理解

    Hi,我是Mic 今天给大家分享一道阿里一面的面试题. 这道题目比较基础,但是确难倒了很多人. 关于"受检异常和非受检异常的理解" 我们来看看普通人和高手的回答. 普通人: 嗯.. ...

  3. 对互斥事件和条件概率的相互理解《考研概率论学习之我见》 -by zobol

    1.从条件概率来定义互斥和对立事件 2.互斥事件是独立事件吗? 3.每个样本点都可以看作是互斥事件,来重新看待条件概率 一.从条件概率来定义互斥和对立事件 根据古典概率-条件概率的定义,当在" ...

  4. springboot2.7.x 集成log4j2配置写入日志到mysql自定义表格

    在阅读之前请先查看[springboot集成log4j2] 本文暂不考虑抽象等实现方式,只限于展示如何自定义配置log4j2并写入mysql数据库(自定义结构) 先看下log4j2的配置 <?x ...

  5. 简述电动汽车的发展前景及3D个性化定制需求

    李彦宏前几天又搞事,他宣布百度要开始造电动汽车了!百度市值更是因此一夜暴涨了700亿. 这熟悉的配方,好像在乔布斯.库克那里也见过. 苹果的"iCar"(或者是Apple Car) ...

  6. SQL注入漏洞篇

    一篇SQL注入漏洞汇总,更新中-- 如有缺陷 望大佬指正 SQL注入产生的原因? 当程序执行逻辑时没有对用户输入的参数做过滤处理,使参数直接与后台数据库产生逻辑交互,即SQL注入黑客就可以利用各种SQ ...

  7. 集成学习——GBDT(手推公式)

  8. Windows 2008R2 IIS环境配置(靶机)

    一.Windows 2008 R2系统安装 VMware Workstation 15安装包 链接:https://pan.baidu.com/s/11sYcZTYPqIV-pyvzo7pWLQ 提取 ...

  9. 实战回忆录:从Webshell开始突破边界

    正文 某授权单位的一次渗透,由于使用的php框架,某cms的上传,从实现webshell开始. 详情 添加监听,生成木马文件更改应用程序名称隐藏上线. 修改休眠时间为10秒 查看主机名whoami 抓 ...

  10. sql-DQL-单表查询

    单表查询 select [distint]* 字段列表 from 表名列表 where 条件列表 group by 分组字段 having 分组之后的条件 order by 排序 limit 分页限定 ...