千家信息网

WPF怎么实现雷达扫描图的绘制

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要介绍了WPF怎么实现雷达扫描图的绘制的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇WPF怎么实现雷达扫描图的绘制文章都会有所收获,下面我们一起来看看吧。制作思
千家信息网最后更新 2026年11月01日WPF怎么实现雷达扫描图的绘制

这篇文章主要介绍了WPF怎么实现雷达扫描图的绘制的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇WPF怎么实现雷达扫描图的绘制文章都会有所收获,下面我们一起来看看吧。

制作思路

  • 绘制圆形(或者称之轮)

  • 绘制分割线

  • 绘制扫描范围

  • 添加扫描点

具体实现

首先我们使用自定义的控件。你可以使用vs自动添加,也可以手动创建类。注意手动创建时要创建Themes/Generic.xaml的文件路径哦。

控件继承自itemscontrol,取名叫做Radar。

我们第一步思考如何实现圆形或者轮,特别是等距的轮。

我们可以使用简单的itemscontrol的WPF控件,通过自定义ItemTemplate就可以简单的创建了。

因为要显示圆,所以使用Ellipse是最简单的事情。

又因为要在同一个区域内,显示同心圆,我们将面板改为Grid,利用叠加的特性去构造同心圆。

既然我们用了itemscontrol 来承载圈轮,直接让这个圈可自定义呢?

所以,我们构造一个集合依赖属性。

///         /// 每圈的大小        ///         public FreezableCollection RadarCircle        {            get { return (FreezableCollection)GetValue(RadarCircleProperty); }            set { SetValue(RadarCircleProperty, value); }        }        ///         /// 每圈的大小        ///         public static readonly DependencyProperty RadarCircleProperty =            DependencyProperty.Register("RadarCircle", typeof(FreezableCollection), typeof(Radar), new PropertyMetadata(new PropertyChangedCallback(OnRadarCircelValueChanged)));

对应泛型类可以参考源代码,基本元素就是绑定ellipse的参数

                                                                                                                                                                                                                                                                                                                            

哇啦,图像就出来了。

同理,我们创建分割线也是同样的过程。

对于分割线的切割算法,我们使用圆上点的坐标可以通过( rcos,rsin)=》(x,y) ,也就是极坐标。

关于此部分代码是放在布局块内ArrangeOverride,也可以放置在OnReader。

下面是局部代码,完整可以参考源代码

var angle = 180.0 / 6;            circlesize = size.Height > size.Width ? size.Width : size.Height;            RadarFillWidth = circlesize;            var midx = circlesize / 2.0;            var midy = circlesize / 2.0;            circlesize = circlesize / 2;            RadarRadius = circlesize;            //默认为6个            for (int i = 0; i < 6; i++)            {                var baseangel = angle * i;                var l1 = new Point(midx + circlesize * Math.Cos(Rad(baseangel)), midy - circlesize * Math.Sin(Rad(baseangel)));                var half = baseangel + 180;                var l2 = new Point(midx + circlesize * Math.Cos(Rad(half)), midy - circlesize * Math.Sin(Rad(half)));                RadarLineSize radarLine = new RadarLineSize();                radarLine.Start = l1;                radarLine.End = l2;                radarLine.Color = RadarLineColor;                RadarLine.Add(radarLine);            }            return size;

依赖属性

///         /// 雷达图的分割线,目前固定为6,可以自行修改        ///         public FreezableCollection RadarLine        {            get { return (FreezableCollection)GetValue(RadarLineProperty); }            set { SetValue(RadarLineProperty, value); }        }        ///         /// 雷达图的分割线,目前固定为6,可以自行修改        ///         public static readonly DependencyProperty RadarLineProperty =            DependencyProperty.Register("RadarLine", typeof(FreezableCollection), typeof(Radar));

xaml代码

                                                                                                                                                                                                                                                                                                                                                

下一步就是扇形扫描了。

我们使用一个完整的圆,将其内部颜色填充为线性刷就可以得到一个效果不错的扫描了。

///         /// 雷达扫描的颜色        ///         public Brush RadarColor        {            get { return (Brush)GetValue(RadarColorProperty); }            set { SetValue(RadarColorProperty, value); }        }        ///         /// 雷达扫描的颜色        ///         public static readonly DependencyProperty RadarColorProperty =            DependencyProperty.Register("RadarColor", typeof(Brush), typeof(Radar));

为了更好的定义这个圆,我们将radar的template使用grid面板等距分成四个区域(其实没啥用,主要是为了扇形扫描时做圆心选择的line,也可以不分成四个)。

在考虑动画,只需要做圆形360的选择就可以了。为了更好应用,我们创一个paly的依赖属性来播放动画。

///         /// 是否播放动画        ///         public bool Play        {            get { return (bool)GetValue(PlayProperty); }            set { SetValue(PlayProperty, value); }        }        ///         /// 是否播放动画        ///         public static readonly DependencyProperty PlayProperty =            DependencyProperty.Register("Play", typeof(bool), typeof(Radar), new PropertyMetadata(false));

xaml代码( 部分)

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

效果

那么剩下就是扫描点的操作。

因为我们的控件是继承ItemsControl,我们到现在还没有利用ItemsSource这个属性。

所以我们要制作一个子控件来呈现扫描点。

由于子控件较为简单,只不过是一个圆而已。我们就让子控件继承Control就好了。

一切从简,我们不弄布局这一套了,直接在父控件中使用Canvas面板,子控件增加属性Left,Top这两个依赖属性。

重点说一下,子控件中存在一个linscar的方法,是为了将点如果在雷达外侧时,按照同角度缩放到最外层的方法。就是通过半径重新计算一边极坐标。

///         /// 线性缩放        ///         /// 半径        internal void LineScar(double size)        {            var midpoint = new Vector(size, size);            var vp = new Vector(Left, Top);            var sub = vp - midpoint;            var angle = Vector.AngleBetween(sub, new Vector(size, 1));            angle = angle > 0 ? angle : angle + 360;            //距离大于半径,根据半径重新绘制            if (sub.Length >= size)            {                Top = size - size * Math.Sin(Rad(angle)) - Width / 2;                Left = size + size * Math.Cos(Rad(angle)) - Width / 2;            }        }

那么在父项中如何摆放呢?

我们刚才说父项使用canvas绘图,所以我们在radar中修改itempanel的面板属性,下面代码存在于父项xaml

                                                                                    

子项代码如下,比较少就贴了

xaml代码

radarItem

///     /// 雷达子项     ///     public class RadarItem : Control    {        static RadarItem()        {            DefaultStyleKeyProperty.OverrideMetadata(typeof(RadarItem), new FrameworkPropertyMetadata(typeof(RadarItem)));        }        public RadarItem()        {        }        ///         /// 转弧度        ///         /// 角度        /// 弧度制        double Rad(doubleval)        {            return val * Math.PI / 180;        }        ///         /// 线性缩放        ///         /// 半径        internal void LineScar(double size)        {            var midpoint = new Vector(size, size);            var vp = new Vector(Left, Top);            var sub = vp - midpoint;            var angle = Vector.AngleBetween(sub, new Vector(size, 1));            angle = angle > 0 ? angle : angle + 360;            //距离大于半径,根据半径重新绘制            if (sub.Length >= size)            {                Top = size - size * Math.Sin(Rad(angle)) - Width / 2;                Left = size + size * Math.Cos(Rad(angle)) - Width / 2;            }        }        ///         /// 顶部距离,用canvas.top绘制        ///         public double Top        {            get { return (double)GetValue(TopProperty); }            set { SetValue(TopProperty, value); }        }        ///         /// 顶部距离,用canvas.top绘制        ///         public static readonly DependencyProperty TopProperty =            DependencyProperty.Register("Top", typeof(double), typeof(RadarItem), new PropertyMetadata(0.0));        ///         /// 左侧距离,用于canvas.left绘制        ///         public double Left        {            get { return (double)GetValue(LeftProperty); }            set { SetValue(LeftProperty, value); }        }        ///         /// 左侧距离,用于canvas.left绘制        ///         public static readonly DependencyProperty LeftProperty =            DependencyProperty.Register("Left", typeof(double), typeof(RadarItem), new PropertyMetadata(0.0));        ///         /// 填充颜色        ///         public Brush Color        {            get { return (Brush)GetValue(ColorProperty); }            set { SetValue(ColorProperty, value); }        }        ///         /// 填充颜色        ///         public static readonly DependencyProperty ColorProperty =            DependencyProperty.Register("Color", typeof(Brush), typeof(RadarItem), new PropertyMetadata(new SolidColorBrush(Colors.Red)));    }

于是乎我们就得到了一个雷达扫描图

关于"WPF怎么实现雷达扫描图的绘制"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"WPF怎么实现雷达扫描图的绘制"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。

雷达 控件 代码 半径 属性 分割线 颜色 动画 就是 面板 圆形 知识 线性 内容 区域 同心圆 大小 子项 布局 弧度 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 深圳九邦互联网科技有限公司 互联网和科技技术 互联网电商科技 新华互联网科技学院 现代科技和互联网有关系吗 互联网科技教育视频 来此购互联网科技有限公司 青岛科技大学互联网大赛研究生 宜昌元轩互联网科技有限公司 玉溪互联网科技怎么选 广州市恰铎互联网科技有限公司 深圳育鹏互联网科技有限公司招聘 互联网数据科技专业 沐思想互联网科技有限公司 南通创西澳互联网科技有限公司 广州有谷有贝互联网科技有限公司 广州智享互联网科技 北京互联网科技类企业分布 长沙易易互联网科技有限公司 银川新华互联网科技学校招聘 云信互联网科技有限公司 互联网科技公司税收优惠 疫情对互联网科技公司影响 与互联网科技公司 人人互联网科技是培训 受益于互联网科技的高速发展 开一家科技互联网公司需要多少钱 互联网科技的前景 广西泛欧互联网科技有限公司 互联网科技品牌
0