wpf 如何写一个圆形的进度条

news/2024/9/18 3:56:06/文章来源:https://www.cnblogs.com/lvpp13/p/18356513

先看一下效果吧

调用代码如下

<local:CycleProgressBar Width="100" Height="100" Background="#FFF68986" Foreground="#FFFA1F09"Maximum="100" Minimum="0" Value="20" IsIndeterminate="False"/>

然后下面就来实现一下这个效果

第一步:先创建一个空的wpf项目

第二步:添加一个自定义控件,取名为CycleProgressBar

添加完以后,vs会自动生成一个类和一个Themes文件夹,下面有一个名为Generic的资源文件

Generic里面就是这个自定义控件的默认样式,里面只有一个border,我们就是通过改造这个默认的样式来实现圆形的进度条

到目前位置,都是vs自动生成的代码,不需要我们做任何操作

 

第三步:将父类设置成RangeBase,因为原生的progressbar就是继承的这个类,所以我们也继承这个类

 

第四步:添加依赖属性IsIndeterminate,这个属性用来控制进度条是不是一直转圈圈

        public bool IsIndeterminate{get { return (bool)GetValue(IsIndeterminateProperty); }set { SetValue(IsIndeterminateProperty, value); }}// Using a DependencyProperty as the backing store for IsIndeterminate.  This enables animation, styling, binding, etc...public static readonly DependencyProperty IsIndeterminateProperty =DependencyProperty.Register("IsIndeterminate", typeof(bool), typeof(CycleProgressBar), new PropertyMetadata(false));

 

第五步:绘制控件的模板样式

在绘制之前,先添加一个nuget上面的引用,搜索expression.drawing,然后添加下面的引用

再在generic文件里面引入命名空间

xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"

再写样式之前的准备工作就准备完了,后面就是开始写模板样式了,下面是样式的代码和注释

 <local:ProgressBarValueToPercentage x:Key="ProgressBarValueToPercentage"/><Style TargetType="{x:Type local:CycleProgressBar}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type local:CycleProgressBar}"><Grid><!--这个椭圆就是进度条的背景部分,把高度和宽度都绑定到宽度上,当然绑定到高度上也一样,主要是为了保证高度和宽度一直,这样子才会显示成圆形StrokeThickness根据自己的实际情况设置,这个表示背景部分的宽度--><Ellipse Stroke="{TemplateBinding Background}" StrokeThickness="10"Height="{TemplateBinding Width}" Width="{TemplateBinding Width}"/><!--这个圆弧的作用就是显示进度条的进度--><ed:Arc x:Name="PART_Track" Width="{TemplateBinding Width}" Height="{TemplateBinding Width}"StartAngle="0" EndAngle="0" Fill="{TemplateBinding Foreground}" Panel.ZIndex="1"ArcThickness="10"Stretch="None" StrokeEndLineCap="Round" StrokeStartLineCap="Round" ArcThicknessUnit="Pixel" RenderTransformOrigin="0.5,0.5"><ed:Arc.RenderTransform><TransformGroup><RotateTransform/></TransformGroup></ed:Arc.RenderTransform></ed:Arc><!--这个进度条的作用就是当我们设置IsIndeterminate为true的时候,让这个进度条一直在那里转圈圈--><ed:Arc x:Name="PART_Track_Repeat" Width="{TemplateBinding Width}" Height="{TemplateBinding Width}"StartAngle="0" EndAngle="90" Fill="{TemplateBinding Foreground}" Panel.ZIndex="1"ArcThickness="10" Visibility="Collapsed"Stretch="None" StrokeEndLineCap="Round" StrokeStartLineCap="Round" ArcThicknessUnit="Pixel" RenderTransformOrigin="0.5,0.5"><ed:Arc.RenderTransform><TransformGroup><RotateTransform/></TransformGroup></ed:Arc.RenderTransform></ed:Arc><!--这个textblock的作用就是显示进度条的百分比--><TextBlock x:Name="tbPercentage" VerticalAlignment="Center" HorizontalAlignment="Center"><TextBlock.Text><MultiBinding Converter="{StaticResource ResourceKey=ProgressBarValueToPercentage}"><Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=local:CycleProgressBar}" Path="Maximum"/><Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=local:CycleProgressBar}" Path="Value"/><Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=local:CycleProgressBar}" Path="Minimum"/></MultiBinding></TextBlock.Text></TextBlock></Grid><ControlTemplate.Triggers><!--设置IsIndeterminate为true的时候,就把百分比和进度条的进度的圆弧隐藏,只保留一直转圈圈的那个圆弧--><!--然后就是一个动画,让圆弧一直转圈圈--><Trigger Property="IsIndeterminate" Value="True"><Setter Property="Visibility" TargetName="PART_Track" Value="Hidden"/><Setter Property="Visibility" TargetName="PART_Track_Repeat" Value="Visible"/><Setter Property="Visibility" TargetName="tbPercentage" Value="Hidden"/><Trigger.EnterActions><BeginStoryboard><Storyboard RepeatBehavior="Forever"><DoubleAnimationUsingKeyFrames Storyboard.TargetName="PART_Track_Repeat" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"><EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/><EasingDoubleKeyFrame KeyTime="00:00:01" Value="360"/></DoubleAnimationUsingKeyFrames></Storyboard></BeginStoryboard></Trigger.EnterActions></Trigger><Trigger Property="IsIndeterminate" Value="False"><Setter TargetName="tbPercentage" Property="Visibility" Value="Visible"/></Trigger><MultiTrigger><MultiTrigger.Conditions><Condition Property="IsIndeterminate" Value="false"/><Condition Property="Value" Value="0"/></MultiTrigger.Conditions><Setter Property="Visibility" Value="Hidden" TargetName="PART_Track"/></MultiTrigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>

里面有一个名为ProgressBarValueToPercentage的转换,直接添加一个类,然后代码就在下面

public class ProgressBarValueToPercentage : IMultiValueConverter
{public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture){var maximum = System.Convert.ToDouble(values[0]);var value = System.Convert.ToDouble(values[1]);var minimum = System.Convert.ToDouble(values[2]);if (maximum == 0){return "0" + "%";}double progressValue = (value - minimum) / (maximum - minimum) * 100;return (Math.Round(progressValue)).ToString() + "%";}public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture){throw new NotImplementedException();}
}

到现在,样式部分就写完了,然后还要去后台代码里面实现具体的功能

第六步:实现后台代码功能

public class CycleProgressBar : RangeBase
{public bool IsIndeterminate{get { return (bool)GetValue(IsIndeterminateProperty); }set { SetValue(IsIndeterminateProperty, value); }}// Using a DependencyProperty as the backing store for IsIndeterminate.  This enables animation, styling, binding, etc...public static readonly DependencyProperty IsIndeterminateProperty =DependencyProperty.Register("IsIndeterminate", typeof(bool), typeof(CycleProgressBar), new PropertyMetadata(false));private FrameworkElement _track;static CycleProgressBar(){//这段代码是创建控件的时候自带的,不用管,代码的意思就是去找generic里面名为CycleProgressBar的样式,//如果把这段代码删了,或者generic没有CycleProgressBar的样式,程序就会报错DefaultStyleKeyProperty.OverrideMetadata(typeof(CycleProgressBar), new FrameworkPropertyMetadata(typeof(CycleProgressBar)));}/// <summary>/// 计算进度条的值/// </summary>private void SetPartTrackValue(){double minimum = this.Minimum;double maximum = this.Maximum;double value = this.Value;double num = (maximum <= minimum) ? 1.0 : ((value - minimum) / (maximum - minimum));var EndAngle = num * 360;if (_track != null){var arc = _track as Arc;arc.EndAngle = EndAngle;}}/// <summary>/// 应用控件模板的时候调用的方法/// </summary>public override void OnApplyTemplate(){base.OnApplyTemplate();this._track = GetTemplateChild("PART_Track") as FrameworkElement;SetPartTrackValue();}/// <summary>/// 进度条的进度变化时触发/// </summary>/// <param name="oldValue"></param>/// <param name="newValue"></param>protected override void OnValueChanged(double oldValue, double newValue){base.OnValueChanged(oldValue, newValue);SetPartTrackValue();}/// <summary>/// 最大值变化时触发/// </summary>/// <param name="oldMaximum"></param>/// <param name="newMaximum"></param>protected override void OnMaximumChanged(double oldMaximum, double newMaximum){base.OnMaximumChanged(oldMaximum, newMaximum);SetPartTrackValue();}/// <summary>/// 最小值变化时触发/// </summary>/// <param name="oldMinimum"></param>/// <param name="newMinimum"></param>protected override void OnMinimumChanged(double oldMinimum, double newMinimum){base.OnMinimumChanged(oldMinimum, newMinimum);SetPartTrackValue();}/// <summary>/// 控件大小变化时触发/// </summary>/// <param name="sizeInfo"></param>protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo){base.OnRenderSizeChanged(sizeInfo);SetPartTrackValue();}
}

好了,控件的后台代码也写完了,就可以直接运行了

设置IsIndeterminate="True"以后,黄色部分就会一直转圈圈啦(脑补一下吧,没有gif,囧)

 

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

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

相关文章

与LLMs进行在IDE中直接、无需提示的交互是工具构建者探索的一个有希望的未来方向

这个观点在卡内基梅隆大学与谷歌研究人员合作文章《Using an LLM to Help With Code Understanding》中提出。这个观点在卡内基梅隆大学与谷歌研究人员合作文章 《Using an LLM to Help With Code Understanding》 中提出。 论文地址:https://dl.acm.org/doi/abs/10.1145/3597…

dbeaver连oceanBase

1. OceanBase OceanBase是由蚂蚁集团完全自主研发的企业级分布式关系数据库,始创于2010年。OceanBase具有数据强一致、高可用、高性能、在线扩展、高度兼容SQL标准和主流关系数据库、低成本等特点。 2020年6月:OceanBase独立公司化运作。2021年6月1日,OceanBase正式对外开源…

KingbaseES RAC运维案例之---集群及数据库管理

KingbaseES、KingbaseRAC案例说明: KingbaseES RAC在部署完成后,进行日常的集群及数据库管理。 适用版本: KingbaseES V008R006C008M030B0010 操作系统版本: [root@node201 KingbaseHA]# cat /etc/centos-release CentOS Linux release 7.9.2009 (Core)集群架构: 如下所示…

“mouseover”和“mouseleave”的事件侦听器

“mouseover”和“mouseleave”的事件侦听器 “mouseover”和“mouseleave”是两个常用的事件侦听器,用于处理鼠标在网页上移入和移出元素的操作。 “mouseover”事件:当鼠标指针移入一个元素时触发。可以通过添加“mouseover”事件侦听器来执行相应的操作,例如改变元素的样…

易基因:儿童和成人实体瘤共有微小差异甲基化区域(mDMR)的全面分析 | 表观研究

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 癌症是美国1~14岁儿童第二大常见死因,每年约有11000例新发病例和1200例死亡病例。与成人癌症相比,儿童肿瘤通常突变负荷较低。然而儿童肿瘤的表观基因组发生显著变化,尤其具有广泛的DNA甲基化变化。儿童肿瘤…

东舟技术诚邀相聚2024汽车测试及质量监控博览会

引领汽车测试行业的年度盛会即将拉开帷幕!2024汽车测试及质量监控博览会将于2024年8月28日至30日在上海世博展览馆1号馆盛大举行。它已牢固确立为不可或缺的测试和验证技术展会,涵盖从样车到生产的全过程,展示大量用于测试、开发和验证阶段的新设备,以实现更好的耐久性、可…

如何挑选最适合您需求的项目管理系统

国内外主流的10款国外项目管理软件对比:PingCode、Worktile、Trello、Monday.com、ClickUp、Jira、Asana、Tapd、Tower、Teambition。在管理复杂项目时,选对工具是成功的关键。全生命周期项目管理系统不仅可以帮助你保持项目的进度和预算控制,还能优化资源分配和风险管理。但…

vue2实现轮播图

1.在components路径下新建文件Carousel.vue,在Carousel.vue文件中创建一个 Vue 组件实现轮播图的功能<button @click="prev" class="carousel-control prev">‹ <button @click="next" class="carousel-control next">›…

【BUUCTF】Easy Java

【BUUCTF】Easy Java 题目来源 收录于:BUUCTF  RoarCTF 2019 题目描述 经典登录框不过SQL注入、目录扫描都没有发现 题解 点击页面的 help跳转到/Download路径下,但是并没有得到其他信息。 这里我们改变请求方式为 POST即可下载文件help.docx但是打开help.docx并没有得到有…

记一次NoClassDeffoundEror问题解决过程

背景:在对某台计算服务器进行代码修改后,发现es查询报错,抛出异常如下: 思路:1.jar包冲突查询了对应jar的pom文件,发现只有一个es的版本jar包,不存在冲突,百思不得其解。 2.本地环境问题清理idea的缓存,发行问题仍然存在 最后翻阅资料,打了断点追踪异常抛出的地方,突…

Keras图形数据增强

在《跟着迪哥学Python数据分析与机器学习实战》这书中提到Keras图像数据增强函数ImageDataGenerator:查看官方API却发现不存在,因为现在Keras都推荐使用版本3了。但是预处理层还是保留了,此时可以使用如下一些层的函数:Resizing层,调整层。版本2对应的是https://keras.io/2.16/…

游戏安全入门-扫雷分析远程线程注入

无论学习什么,首先,我们应该有个目标,那么入门windows游戏安全,脑海中浮现出来的一个游戏 -- 扫雷,一款家喻户晓的游戏,虽然已经被大家分析的不能再透了,但是我觉得自己去分析一下还是极好的,把它作为一个小目标再好不过了。前言 无论学习什么,首先,我们应该有个目标…