老板加薪!看我做的WPF Loading!!!
控件名:RingLoading
作者:WPFDevelopersOrg
原文链接: https://github.com/WPFDevelopersOrg/WPFDevelopers.Minimal
框架使用大于等于
.NET40
;Visual Studio 2022
;项目使用 MIT 开源许可协议;
最外层使用Viewbox为父控件内部嵌套创建三组
Grid -> Ellipse 、 Border
分别给它们指定不同的Angle从左侧开始-135 225 54
,做永久 Angle 动画;如何绘制;
对Ellipse的StrokeDashArray进行设置23 100就能达到效果;
1)RingLoading.cs代码如下;
using System.Windows;
using System.Windows.Controls;namespace WPFDevelopers.Controls
{public class RingLoading : Control{// Using a DependencyProperty as the backing store for IsStart. This enables animation, styling, binding, etc...public static readonly DependencyProperty IsStartProperty =DependencyProperty.Register("IsStart", typeof(bool), typeof(RingLoading), new PropertyMetadata(default));// Using a DependencyProperty as the backing store for ProgressValue. This enables animation, styling, binding, etc...public static readonly DependencyProperty ProgressValueProperty =DependencyProperty.Register("ProgressValue", typeof(double), typeof(RingLoading),new PropertyMetadata(0d, OnProgressValueChangedCallBack));// Using a DependencyProperty as the backing store for Progress. This enables animation, styling, binding, etc...internal static readonly DependencyProperty ProgressProperty =DependencyProperty.Register("Progress", typeof(string), typeof(RingLoading), new PropertyMetadata(default));// Using a DependencyProperty as the backing store for Maximum. This enables animation, styling, binding, etc...public static readonly DependencyProperty MaximumProperty =DependencyProperty.Register("Maximum", typeof(double), typeof(RingLoading),new PropertyMetadata(100d, OnMaximumPropertyChangedCallBack));// Using a DependencyProperty as the backing store for Description. This enables animation, styling, binding, etc...public static readonly DependencyProperty DescriptionProperty =DependencyProperty.Register("Description", typeof(string), typeof(RingLoading),new PropertyMetadata(default));static RingLoading(){DefaultStyleKeyProperty.OverrideMetadata(typeof(RingLoading),new FrameworkPropertyMetadata(typeof(RingLoading)));}public bool IsStart{get => (bool)GetValue(IsStartProperty);set => SetValue(IsStartProperty, value);}public double ProgressValue{get => (double)GetValue(ProgressValueProperty);set => SetValue(ProgressValueProperty, value);}internal string Progress{get => (string)GetValue(ProgressProperty);set => SetValue(ProgressProperty, value);}public double Maximum{get => (double)GetValue(MaximumProperty);set => SetValue(MaximumProperty, value);}public string Description{get => (string)GetValue(DescriptionProperty);set => SetValue(DescriptionProperty, value);}private static void OnProgressValueChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e){if (!(d is RingLoading control))return;if (!double.TryParse(e.NewValue?.ToString(), out var value))return;var progress = value / control.Maximum;control.SetCurrentValue(ProgressProperty, progress.ToString("P0"));}private static void OnMaximumPropertyChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e){if (!(d is RingLoading control))return;if (!double.TryParse(e.NewValue?.ToString(), out var maxValue))return;if (maxValue <= 0)return;var progress = control.ProgressValue / maxValue;control.SetCurrentValue(ProgressProperty, progress.ToString("P0"));}}
}
2)RingLoading.xaml代码如下;
<Style TargetType="controls:RingLoading" BasedOn="{StaticResource ControlBasicStyle}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="controls:RingLoading"><ControlTemplate.Resources><Storyboard x:Key="PART_Resource_Storyboard" RepeatBehavior="Forever"><DoubleAnimation To="-495" Duration="0:0:1.5" Storyboard.TargetName="PART_Ring1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"/><DoubleAnimation To="585" Duration="0:0:1.5" Storyboard.TargetName="PART_Ring2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"/><DoubleAnimation To="-315" Duration="0:0:1.5" Storyboard.TargetName="PART_Ring3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"/></Storyboard></ControlTemplate.Resources><Grid><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><Viewbox HorizontalAlignment="Center" VerticalAlignment="Center" ><Border Padding="10" Width="100" Height="100" ><Grid><Grid x:Name="PART_Ring1" Width="60" Height="60" HorizontalAlignment="Center" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5"><Grid.RenderTransform><TransformGroup><ScaleTransform/><SkewTransform/><RotateTransform Angle="-135"/><TranslateTransform/></TransformGroup></Grid.RenderTransform><Ellipse Stroke="Red" StrokeThickness="2" StrokeDashArray="23 100" RenderTransformOrigin="0.5,0.5"/><Border Width="10" Height="10" CornerRadius="10" Background="Red" HorizontalAlignment="Right" Margin="0,0,-4,0"><Border.Effect><DropShadowEffect BlurRadius="10" ShadowDepth="0" Color="Red"/></Border.Effect></Border></Grid><Grid x:Name="PART_Ring2" Width="60" Height="60" HorizontalAlignment="Left" VerticalAlignment="Bottom" RenderTransformOrigin="0.5,0.5"><Grid.RenderTransform><TransformGroup><ScaleTransform/><SkewTransform/><RotateTransform Angle="225"/><TranslateTransform/></TransformGroup></Grid.RenderTransform><Ellipse Stroke="Purple" StrokeThickness="2" StrokeDashArray="23 100"/><Border Width="10" Height="10" CornerRadius="10" Background="Purple" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,-4"><Border.Effect><DropShadowEffect BlurRadius="10" ShadowDepth="0" Color="Purple"/></Border.Effect></Border></Grid><Grid x:Name="PART_Ring3" Width="60" Height="60" HorizontalAlignment="Right" VerticalAlignment="Bottom" RenderTransformOrigin="0.5,0.5"><Grid.RenderTransform><TransformGroup><ScaleTransform/><SkewTransform/><RotateTransform Angle="45"/><TranslateTransform/></TransformGroup></Grid.RenderTransform><Ellipse Stroke="#0fb8b2" StrokeThickness="2" StrokeDashArray="23 100"/><Border Width="10" Height="10" CornerRadius="10" Background="#0fb8b2" HorizontalAlignment="Right" Margin="0,0,-4,0"><Border.Effect><DropShadowEffect BlurRadius="10" ShadowDepth="0" Color="#0fb8b2"/></Border.Effect></Border></Grid></Grid></Border></Viewbox><StackPanel Grid.Row="1" Grid.ColumnSpan="2" Margin="10"><TextBlock HorizontalAlignment="Center" Text="Loading..." Margin="0,0,0,15"/><TextBlock HorizontalAlignment="Center" Text="{TemplateBinding Description}" Margin="0,0,0,15"/><TextBlock HorizontalAlignment="Center" Text="{TemplateBinding Progress}" FontSize="{StaticResource TitleFontSize}" FontWeight="Bold"/></StackPanel></Grid><ControlTemplate.Triggers><Trigger Property="IsStart" Value="True"><Trigger.EnterActions><BeginStoryboard Storyboard="{StaticResource PART_Resource_Storyboard}" x:Name="PART_BeginStoryboard"/></Trigger.EnterActions><Trigger.ExitActions><StopStoryboard BeginStoryboardName="PART_BeginStoryboard"/></Trigger.ExitActions></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>
3)RingLoadingExample.xaml代码如下;
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.RingLoadingExample"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><wpfdev:RingLoading IsStart="true" Width="400" Height="400"Description="WPFDevelopers" Foreground="Black" ProgressValue="50"/></Grid>
</UserControl>
RingLoading|Github[1]
RingLoading|码云[2]
RingLoading.xaml|Github[3]
RingLoading.xaml|码云[4]
参考资料
[1]
ThemeControl|Github: https://github.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers/Controls/Loadings/RingLoading.cs
[2]ThemeControl|码云: https://gitee.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers/Controls/Loadings/RingLoading.cs
[3]Styles.ThemeControl.xaml|Github: https://github.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers/Themes/LoadingGroup.xaml
[4]Styles.ThemeControl.xaml|码云: https://gitee.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers/Themes/LoadingGroup.xaml