WPF自定义控件(教程含源码)-loading 等待控件

控件需求

长时间等待时,防止用户进行其他操作,显示 loading 等待框。

控件最终效果如下所示:

20221107_113333

 控件设计方案

控件继承 window 窗口,loading 显示时可以直接阻塞线程,防止用户进行其他操作。

底部为半透明  Border 、中间为12颗米粒(米粒使用Rectangle)、loading文字提示内容。

将12颗米粒放在Canvas 控件中,将Canvas 按30° 不停旋转,即可得到最终的loading动画效果。

控件xaml模板下图所示

<Window x:Class="WPFCustomControl.Controls.RLoading"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFCustomControl.Controls"
        mc:Ignorable="d"
        Title="RLoading" Height="200" Width="200"
        WindowStyle="None" WindowStartupLocation="CenterScreen" Background="Transparent" AllowsTransparency="True" ShowInTaskbar="False"
        Loaded="Window_Loaded">
    <Window.Resources>
        <DrawingBrush x:Key="riceBrush" Stretch="None" AlignmentX="Center" AlignmentY="Top">
            <DrawingBrush.Drawing>
                <GeometryDrawing  Brush="#fff">
                    <GeometryDrawing.Geometry>
                        <EllipseGeometry RadiusX="3" RadiusY="17"/>
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingBrush.Drawing>
        </DrawingBrush>

        <Style TargetType="Rectangle">
            <Setter Property="Width" Value="100" />
            <Setter Property="Height" Value="100" />
            <Setter Property="Fill" Value="{StaticResource riceBrush }" />
            <Setter Property="RenderTransformOrigin" Value=".5,.5" />
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.Triggers>
            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                <BeginStoryboard>
                    <Storyboard  RepeatBehavior="Forever">
                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                       Storyboard.TargetName="canvasRotate"
                                                       Storyboard.TargetProperty="Angle">
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.08" Value="30"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.16" Value="60"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.24" Value="90"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.32" Value="120"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.40" Value="150"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.48" Value="180"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.56" Value="210"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.64" Value="240"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.72" Value="270"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.80" Value="300"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.88" Value="330"/>
                            <DiscreteDoubleKeyFrame KeyTime="00:00:00.96" Value="360"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Grid.Triggers>
        <Border Background="#333" Opacity="0.7" CornerRadius="4" SnapsToDevicePixels="True" />

        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <Canvas Width="100" Height="100" RenderTransformOrigin=".5,.5">
                <Canvas.RenderTransform>
                    <TransformGroup>
                        <RotateTransform Angle="0" x:Name="canvasRotate" />
                    </TransformGroup>
                </Canvas.RenderTransform>

                <Rectangle/>
                <Rectangle Opacity="0.92">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-30"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.84">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-60"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle  Opacity="0.76" >
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-90"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.68">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-120"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.60">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-150"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.52">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-180"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.44">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-210"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.36" >
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-240"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.28">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-270"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.20">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-300"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Opacity="0.12">
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle="-330"/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
            </Canvas>
            <Label x:Name="txtTitle" Foreground="White" HorizontalContentAlignment="Center" FontSize="20">加载中</Label>
        </StackPanel>
    </Grid>
</Window>

 控件后台代码如下图所示:

handler 字段为需要长时间执行的代码片段。handler 执行完成后,会自动执行 OnComplate 方法里的关闭窗口。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WPFCustomControl.Controls {
    /// <summary>
    /// RLoading.xaml 的交互逻辑
    /// </summary>
    public partial class RLoading : Window {
        Action handler;

        private RLoading(string title, Action handler) {
            InitializeComponent();

            this.txtTitle.Content = title;
            this.handler = handler;
        }
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            handler?.BeginInvoke(OnComplate, null);
        }

        private void OnComplate(IAsyncResult ar) {
            this.Dispatcher.Invoke(new Action(() => { this.Close(); }));
        }

        public static void ShowLoading(string title, Action handler, Window owner) {
            var loading = new RLoading(title, handler) { Owner = owner };

            loading.ShowDialog();
        }
    }
}

代码内容使用方式如下:

实例代码使用 Sleep(5000),睡眠5秒钟模拟长时间耗时动作。

        private void LoadingClick(object sender, RoutedEventArgs e) {
            Controls.RLoading.ShowLoading("正在加载", () => { System.Threading.Thread.Sleep(5000); }, this);
        }

有问题或看不懂的地方,欢迎评论去留言。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lhyriver

制作不易,打赏给我提供动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值