5

老板加薪!看我做的WPF Loading!!! - 驚鏵

 2 years ago
source link: https://www.cnblogs.com/yanjinhua/p/16571359.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

老板加薪!看我做的WPF Loading!!!

控件名:RingLoading

作者:WPFDevelopersOrg

原文链接: https://github.com/WPFDevelopersOrg/WPFDevelopers

  • 框架使用大于等于.NET40

  • Visual Studio 2022;

  • 项目使用 MIT 开源许可协议;

  • 老板觉得公司系统等待动画转圈太简单,所以需要做一个稍微好看点的,就有这篇等待RingLoading动画;

视频效果预览👉https://www.zhihu.com/zvideo/1540649421552779264

  • 最外层使用Viewbox为父控件内部嵌套创建三组 Grid -> Ellipse 、 Border
    分别给它们指定不同的Angle从左侧开始 -135 225 54,做永久 Angle 动画;
  • PART_Ring1.RotateTransform.AngleFrom -135-495
  • PART_Ring2.RotateTransform.AngleFrom 225-585
  • PART_Ring3.RotateTransform.AngleFrom -54-315
  • 如何绘制;
  • EllipseStrokeDashArray进行设置23 100就能达到效果;

  • Border 做为圆设置 Effect 可实现阴影效果;

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
RingLoading|码云
RingLoading.xaml|Github
RingLoading.xaml|码云


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK