yanjinhua
V2EX  ›  .NET

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

  •  
  •   yanjinhua · Aug 10, 2022 · 7065 views
    This topic created in 1546 days ago, the information mentioned may be changed or developed.

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

    控件名:RingLoading

    作者:WPFDevelopersOrg

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

    • 框架使用大于等于.NET40;
    • Visual Studio 2022;
    • 项目使用 MIT 开源许可协议;

    👉视频点我效果预览⬅⬅

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

    • 对Ellipse的StrokeDashArray进行设置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|码云

    34 replies  •  2022-08-22 10:39:01 +08:00
    Terry05
    Terry05
    Aug 10, 2022
    1
    emmmmmm……恕我没看懂
    y830CAa5nink4rUQ
    y830CAa5nink4rUQ
    Aug 10, 2022❤️1
    2
    老板:这么丑?撤掉,换回上一版那个 GIF !
    runningowl
    runningowl
    Aug 10, 2022
    3
    Lottie 不香么
    loopinfor
    loopinfor
    Aug 10, 2022
    4
    这个 loading 效果过于另类了,应该不会有人真的用吧
    yanjinhua
    yanjinhua
    OP
    Aug 10, 2022
    5
    yanjinhua
    yanjinhua
    OP
    Aug 10, 2022
    6
    @loopinfor 哈哈哈
    yanjinhua
    yanjinhua
    OP
    Aug 10, 2022
    7
    @DrX 没用 gif
    yanjinhua
    yanjinhua
    OP
    Aug 10, 2022
    8
    @Terry05 呃呃呃呃呃
    wangyzj
    wangyzj
    Aug 10, 2022
    9
    不够卷
    SeanTheSheep
    SeanTheSheep
    Aug 10, 2022
    10
    逛 V 站一年了,第二次看到 WPF 相关的帖子,泪目了。
    yanjinhua
    yanjinhua
    OP
    Aug 10, 2022
    11
    @wangyzj 正在努力
    yanjinhua
    yanjinhua
    OP
    Aug 10, 2022
    12
    @SeanTheSheep 那么我很关心第一次的帖子 i😊
    20015jjw
    20015jjw
    Aug 10, 2022 via iPhone
    13
    amazon 可能会喜欢你(雾
    sinnosong1
    sinnosong1
    Aug 10, 2022
    14
    每行都能看懂,但是连起来就完全看不懂了,虽然我也写过 WPF ,一直都是入门状态的新手。。。
    yanjinhua
    yanjinhua
    OP
    Aug 10, 2022
    15
    @sinnosong1 哈哈哈,好像懂了 但是又没完全懂
    yanjinhua
    yanjinhua
    OP
    Aug 10, 2022
    16
    @20015jjw 我不懂了
    vone
    vone
    Aug 10, 2022❤️3
    17
    当场开除!
    dcsuibian
    dcsuibian
    Aug 10, 2022
    18
    现在 Electron 越来越多,对原生开发者也越来越敬重
    DawnMoon
    DawnMoon
    Aug 10, 2022
    19
    star 了,准备在我丑得要命的上位机里面试下这个主题
    stoluoyu
    stoluoyu
    Aug 10, 2022
    20
    精子有了,load 完不该进入卵子了么(大雾
    marcong95
    marcong95
    Aug 10, 2022
    21
    其实只留一组,甚至把那个东西的头部删掉其实就好多了,最好圆弧的长度还能随着时间变长变短。。。。
    v2byy
    v2byy
    Aug 10, 2022
    22
    就用 windows start 那个 loading 不香吗
    NGXDLK
    NGXDLK
    Aug 10, 2022
    23
    @marcong95 还可以变粗变细,变直变弯
    lifeintools
    lifeintools
    Aug 10, 2022
    24
    真好玩~
    xyx0826
    xyx0826
    Aug 11, 2022 via iPhone
    25
    很酷诶...WPF 我用了一段时间但是完全没搞懂它的高级样式和动画,现在 winui 3 也出了,不知道该学哪个了
    yanjinhua
    yanjinhua
    OP
    Aug 11, 2022
    26
    @vone 哈哈哈哈哈
    yanjinhua
    yanjinhua
    OP
    Aug 11, 2022
    27
    @dcsuibian 现在确实都是使用 electron 。谢谢
    yanjinhua
    yanjinhua
    OP
    Aug 11, 2022
    28
    @villivateur 欢迎使用哈,https://github.com/WPFDevelopersOrg 这个组织下都是关于 WPF 和 MAUI 的项目。有问题及时反馈哈。
    yanjinhua
    yanjinhua
    OP
    Aug 11, 2022
    29
    @stoluoyu 哈哈哈哈,后期应该会增加任务完成关闭。
    yanjinhua
    yanjinhua
    OP
    Aug 11, 2022
    30
    @NGXDLK 是这样的。
    yanjinhua
    yanjinhua
    OP
    Aug 11, 2022
    31
    @lifeintools 可以复制源码魔改起来。
    yanjinhua
    yanjinhua
    OP
    Aug 11, 2022
    32
    @xyx0826 maui 跨平台,win10 之前的系统。动画和高级样式多写几次就熟悉了。“https://github.com/WPFDevelopersOrg” 这个组织下 也有 maui 项目。
    ragnaroks
    ragnaroks
    Aug 19, 2022
    33
    WPF 设置样式( StyleSetter )和动画( StoryBorad )太累了,我已经放弃了,现在都用网页做 UI ,通过 websocket 链接到本地
    yanjinhua
    yanjinhua
    OP
    Aug 22, 2022
    34
    @ragnaroks 熟悉了就还好,也是不错的选择。👍
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4452 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 67ms · UTC 03:55 · PVG 11:55 · LAX 19:55 · JFK 22:55
    ♥ Do have faith in what you're doing.