超炫酷的WPF实现Loading控件效果
作者:JackWang-CUMT 发布时间:2023-11-19 23:53:20
Win8系统的Loading效果还是很不错的,网上也有人用CSS3等技术实现,研究了一下,并打算用WPF自定义一个Loading控件实现类似的效果,并可以让用户对Loading的颗粒(Particle)背景颜色进行自定义,话不多说,直接上代码:
1、用VS2012新建一个WPF的用户控件库项目WpfControlLibraryDemo,VS自动生成如下结构:
2、删除UserControl1.xaml,并新建一个Loading的CustomControl(不是UserControl),如下图所示:
3、如果报错找不到Loading类型,请编译,下面在Generic.xaml主题文件中对Loading的样式和内容进行定义(注意添加
xmlns:system = "clr-namespace:System;assembly=mscorlib"),代码如下:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system = "clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfControlLibraryDemo">
<Style TargetType="{x:Type local:Loading}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Loading}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid Width = "50" Height = "50">
<Grid.Resources>
<!-- Value Converters -->
<!-- Particle Styling ,must to has RelativeSource -->
<SolidColorBrush x:Key = "ParticleColor" Color = "{Binding Path=FillColor,RelativeSource={RelativeSource TemplatedParent}}" />
<SolidColorBrush x:Key = "ParticleBackgroundColor" Color = "Transparent"/>
<system:Double x:Key = "ParticleOpacity">1</system:Double>
<system:Double x:Key = "ParticleRadius">5</system:Double>
<system:Double x:Key = "StartingPointX">0</system:Double>
<system:Double x:Key = "StartingPointY">-20</system:Double>
<system:Double x:Key = "RotationPointX">0.5</system:Double>
<system:Double x:Key = "RotationPointY">0.5</system:Double>
<!-- StoryBoard -->
<system:TimeSpan x:Key = "StoryBoardBeginTimeP0">00:00:00.000</system:TimeSpan>
<system:TimeSpan x:Key = "StoryBoardBeginTimeP1">00:00:00.100</system:TimeSpan>
<system:TimeSpan x:Key = "StoryBoardBeginTimeP2">00:00:00.200</system:TimeSpan>
<system:TimeSpan x:Key = "StoryBoardBeginTimeP3">00:00:00.300</system:TimeSpan>
<system:TimeSpan x:Key = "StoryBoardBeginTimeP4">00:00:00.400</system:TimeSpan>
<Duration x:Key = "StoryBoardDuration">00:00:01.800</Duration>
<!-- Particle Origin Angles -->
<system:Double x:Key = "ParticleOriginAngleP0">0</system:Double>
<system:Double x:Key = "ParticleOriginAngleP1">-10</system:Double>
<system:Double x:Key = "ParticleOriginAngleP2">-20</system:Double>
<system:Double x:Key = "ParticleOriginAngleP3">-30</system:Double>
<system:Double x:Key = "ParticleOriginAngleP4">-40</system:Double>
<!-- Particle Position & Timing 1 -->
<system:Double x:Key = "ParticleBeginAngle1">0</system:Double>
<system:Double x:Key = "ParticleEndAngle1">90</system:Double>
<system:TimeSpan x:Key = "ParticleBeginTime1">00:00:00.000</system:TimeSpan>
<Duration x:Key = "ParticleDuration1">00:00:00.750</Duration>
<!-- Particle Position & Timing 2 -->
<system:Double x:Key = "ParticleBeginAngle2">90</system:Double>
<system:Double x:Key = "ParticleEndAngle2">270</system:Double>
<system:TimeSpan x:Key = "ParticleBeginTime2">00:00:00.751</system:TimeSpan>
<Duration x:Key = "ParticleDuration2">00:00:00.300</Duration>
<!-- Particle Position & Timing 3 -->
<system:Double x:Key = "ParticleBeginAngle3">270</system:Double>
<system:Double x:Key = "ParticleEndAngle3">360</system:Double>
<system:TimeSpan x:Key = "ParticleBeginTime3">00:00:01.052</system:TimeSpan>
<Duration x:Key = "ParticleDuration3">00:00:00.750</Duration>
<Style x:Key = "EllipseStyle" TargetType = "Ellipse">
<Setter Property = "Width" Value = "{StaticResource ParticleRadius}"/>
<Setter Property = "Height" Value = "{StaticResource ParticleRadius}"/>
<Setter Property = "Fill" Value = "{StaticResource ParticleColor}"/>
<Setter Property = "RenderTransformOrigin" Value = "0.5, 0.5"/>
<Setter Property = "Opacity" Value = "{StaticResource ParticleOpacity}"/>
</Style>
</Grid.Resources>
<Canvas Width = "1" Height = "1" Margin="0,0,0,0">
<Canvas.Triggers>
<EventTrigger RoutedEvent = "Canvas.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard
BeginTime = "{StaticResource StoryBoardBeginTimeP0}"
Duration = "{StaticResource StoryBoardDuration}"
RepeatBehavior = "Forever">
<DoubleAnimation
Storyboard.TargetName = "p0"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle1}"
To = "{StaticResource ParticleEndAngle1}"
BeginTime = "{StaticResource ParticleBeginTime1}"
Duration = "{StaticResource ParticleDuration1}"/>
<DoubleAnimation
Storyboard.TargetName = "p0"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle2}"
To = "{StaticResource ParticleEndAngle2}"
BeginTime = "{StaticResource ParticleBeginTime2}"
Duration = "{StaticResource ParticleDuration2}"/>
<DoubleAnimation
Storyboard.TargetName = "p0"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle3}"
To = "{StaticResource ParticleEndAngle3}"
BeginTime = "{StaticResource ParticleBeginTime3}"
Duration = "{StaticResource ParticleDuration3}"/>
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard
BeginTime = "{StaticResource StoryBoardBeginTimeP1}"
Duration = "{StaticResource StoryBoardDuration}"
RepeatBehavior = "Forever">
<DoubleAnimation
Storyboard.TargetName = "p1"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle1}"
To = "{StaticResource ParticleEndAngle1}"
BeginTime = "{StaticResource ParticleBeginTime1}"
Duration = "{StaticResource ParticleDuration1}"/>
<DoubleAnimation
Storyboard.TargetName = "p1"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle2}"
To = "{StaticResource ParticleEndAngle2}"
BeginTime = "{StaticResource ParticleBeginTime2}"
Duration = "{StaticResource ParticleDuration2}"/>
<DoubleAnimation
Storyboard.TargetName = "p1"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle3}"
To = "{StaticResource ParticleEndAngle3}"
BeginTime = "{StaticResource ParticleBeginTime3}"
Duration = "{StaticResource ParticleDuration3}"/>
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard
BeginTime = "{StaticResource StoryBoardBeginTimeP2}"
Duration = "{StaticResource StoryBoardDuration}"
RepeatBehavior = "Forever">
<DoubleAnimation
Storyboard.TargetName = "p2"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle1}"
To = "{StaticResource ParticleEndAngle1}"
BeginTime = "{StaticResource ParticleBeginTime1}"
Duration = "{StaticResource ParticleDuration1}"/>
<DoubleAnimation
Storyboard.TargetName = "p2"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle2}"
To = "{StaticResource ParticleEndAngle2}"
BeginTime = "{StaticResource ParticleBeginTime2}"
Duration = "{StaticResource ParticleDuration2}"/>
<DoubleAnimation
Storyboard.TargetName = "p2"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle3}"
To = "{StaticResource ParticleEndAngle3}"
BeginTime = "{StaticResource ParticleBeginTime3}"
Duration = "{StaticResource ParticleDuration3}"/>
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard
BeginTime = "{StaticResource StoryBoardBeginTimeP3}"
Duration = "{StaticResource StoryBoardDuration}"
RepeatBehavior = "Forever">
<DoubleAnimation
Storyboard.TargetName = "p3"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle1}"
To = "{StaticResource ParticleEndAngle1}"
BeginTime = "{StaticResource ParticleBeginTime1}"
Duration = "{StaticResource ParticleDuration1}"/>
<DoubleAnimation
Storyboard.TargetName = "p3"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle2}"
To = "{StaticResource ParticleEndAngle2}"
BeginTime = "{StaticResource ParticleBeginTime2}"
Duration = "{StaticResource ParticleDuration2}"/>
<DoubleAnimation
Storyboard.TargetName = "p3"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle3}"
To = "{StaticResource ParticleEndAngle3}"
BeginTime = "{StaticResource ParticleBeginTime3}"
Duration = "{StaticResource ParticleDuration3}"/>
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard
BeginTime = "{StaticResource StoryBoardBeginTimeP4}"
Duration = "{StaticResource StoryBoardDuration}"
RepeatBehavior = "Forever">
<DoubleAnimation
Storyboard.TargetName = "p4"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle1}"
To = "{StaticResource ParticleEndAngle1}"
BeginTime = "{StaticResource ParticleBeginTime1}"
Duration = "{StaticResource ParticleDuration1}"/>
<DoubleAnimation
Storyboard.TargetName = "p4"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle2}"
To = "{StaticResource ParticleEndAngle2}"
BeginTime = "{StaticResource ParticleBeginTime2}"
Duration = "{StaticResource ParticleDuration2}"/>
<DoubleAnimation
Storyboard.TargetName = "p4"
Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"
From = "{StaticResource ParticleBeginAngle3}"
To = "{StaticResource ParticleEndAngle3}"
BeginTime = "{StaticResource ParticleBeginTime3}"
Duration = "{StaticResource ParticleDuration3}"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Canvas.Triggers>
<Border
x:Name = "p0"
Background = "{StaticResource ParticleBackgroundColor}"
Opacity = "{StaticResource ParticleOpacity}">
<Border.RenderTransform>
<RotateTransform/>
</Border.RenderTransform>
<Border.RenderTransformOrigin>
<Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>
</Border.RenderTransformOrigin>
<Ellipse Style = "{StaticResource EllipseStyle}">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>
<RotateTransform Angle = "{StaticResource ParticleOriginAngleP0}"/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
<Border
x:Name = "p1"
Background = "{StaticResource ParticleBackgroundColor}"
Opacity = "{StaticResource ParticleOpacity}">
<Border.RenderTransform>
<RotateTransform/>
</Border.RenderTransform>
<Border.RenderTransformOrigin>
<Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>
</Border.RenderTransformOrigin>
<Ellipse Style = "{StaticResource EllipseStyle}">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>
<RotateTransform Angle = "{StaticResource ParticleOriginAngleP1}"/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
<Border
x:Name = "p2"
Background = "{StaticResource ParticleBackgroundColor}"
Opacity = "{StaticResource ParticleOpacity}">
<Border.RenderTransform>
<RotateTransform/>
</Border.RenderTransform>
<Border.RenderTransformOrigin>
<Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>
</Border.RenderTransformOrigin>
<Ellipse Style = "{StaticResource EllipseStyle}">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>
<RotateTransform Angle = "{StaticResource ParticleOriginAngleP2}"/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
<Border
x:Name = "p3"
Background = "{StaticResource ParticleBackgroundColor}"
Opacity = "{StaticResource ParticleOpacity}">
<Border.RenderTransform>
<RotateTransform/>
</Border.RenderTransform>
<Border.RenderTransformOrigin>
<Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>
</Border.RenderTransformOrigin>
<Ellipse Style = "{StaticResource EllipseStyle}">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>
<RotateTransform Angle = "{StaticResource ParticleOriginAngleP3}"/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
<Border
x:Name = "p4"
Background = "{StaticResource ParticleBackgroundColor}"
Opacity = "{StaticResource ParticleOpacity}">
<Border.RenderTransform>
<RotateTransform/>
</Border.RenderTransform>
<Border.RenderTransformOrigin>
<Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>
</Border.RenderTransformOrigin>
<Ellipse Style = "{StaticResource EllipseStyle}">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>
<RotateTransform Angle = "{StaticResource ParticleOriginAngleP4}"/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
</Canvas>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
在构建中发现,一开始在设定绑定时,写成<SolidColorBrush x:Key = "ParticleColor" Color = "{Binding Path=FillColor}" />一直都无法绑定成功,后来查了资料,改成<SolidColorBrush x:Key = "ParticleColor" Color = "{Binding Path=FillColor,RelativeSource={RelativeSource TemplatedParent}}" /> 后成功。
4、编辑Loading.cs文件,对自定义属性FillColor和逻辑进行编码:
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.Navigation;
using System.Windows.Shapes;
namespace WpfControlLibraryDemo
{
using System.ComponentModel;
/// <summary>
/// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
///
/// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:WpfControlLibraryDemo"
///
///
/// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:WpfControlLibraryDemo;assembly=WpfControlLibraryDemo"
///
/// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
/// 并重新生成以避免编译错误:
///
/// 在解决方案资源管理器中右击目标项目,然后依次单击
/// “添加引用”->“项目”->[浏览查找并选择此项目]
///
///
/// 步骤 2)
/// 继续操作并在 XAML 文件中使用控件。
///
/// <MyNamespace:Loading/>
///
/// </summary>
public class Loading : Control
{
static Loading()
{
//重载默认样式
DefaultStyleKeyProperty.OverrideMetadata(typeof(Loading), new FrameworkPropertyMetadata(typeof(Loading)));
//DependencyProperty 注册 FillColor
FillColorProperty = DependencyProperty.Register("FillColor",
typeof(Color),
typeof(Loading),
new UIPropertyMetadata(Colors.DarkBlue,
new PropertyChangedCallback(OnUriChanged))
);
//Colors.DarkBlue为控件初始化默认值
}
//属性变更回调函数
private static void OnUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Border b = (Border)d;
//MessageBox.Show(e.NewValue.ToString());
}
#region 自定义Fields
// DependencyProperty属性定义 FillColorProperty=FillColor+Property组成
public static readonly DependencyProperty FillColorProperty;
#endregion
//VS设计器属性支持
[Description("背景色"), Category("个性配置"), DefaultValue("#FF668899")]
public Color FillColor
{
//GetValue,SetValue为固定写法,此处一般不建议处理其他逻辑
get { return (Color)GetValue(FillColorProperty); }
set { SetValue(FillColorProperty, value); }
}
}
}
5、编译,如果无误后,可以添加WPF应用程序WpfAppLoadingTest进行测试(添加项目引用)。
打开MainWindow.xaml,将Loading控件拖放到设计界面上,如下图所示:
6、控件颜色修改,选中控件,在属性栏中进行配置即可:
7.总结
可以看到WPF自定义控件还是比较容易的,但是难点在于UI的设计,如果需要做的美观,需要美工的参与,而且需要转换成XAML。


猜你喜欢
- 日常的开发中经常会需要用到自定义View,这次刚好有个需求,需要用到带有节点的进度条。东西很简单直接继承View就行了。首先定义一些需要的属
- 本文重在实现理解,过滤器,业务,逻辑需求,样式请无视。。项目结构如下1.idea新建Spring boot项目,在pom中加上thymele
- 前言:Java异常处理的五个关键字:try、catch、finally、throw、throws抛出异常throw在编写程序时,我们必须要考
- 场景:使用MyBatis批量查询(select)、批量插入(insert)、批量更新(update)、批量删除(delete)操作MySQL
- 1.封装分页Page类package com.framework.common.page.impl;import java.io.Seria
- Prim算法介绍1.点睛在生成树的过程中,把已经在生成树中的节点看作一个集合,把剩下的节点看作另外一个集合,从连接两个集合的边中选择一条权值
- 本文实例讲述了C#实现基于IE内核的简单浏览器。分享给大家供大家参考。具体如下:Form1.cs如下:using System;using
- 最近因为项目需要,自己实现了个可以自由移动,并且长按可以跳出一个控制播放的,大的悬浮窗。好,开始吧。首先我们先聊权限,悬浮窗需要在manif
- TV 3D卡片无限循环效果,供大家参考,具体内容如下##前言1、需求:实现3个卡片实现无限循环效果:1-2-3-1-2-3-1…,而且要实现
- 问题: 在win10系统中,使用IDEA 查看源码的时候,经常跳转代码,这样会让使用者感觉和方便,但是当你想要返回上次跳转的位置时,却不知道
- gateway网关与前端请求的跨域问题最近因项目需要,引入了gateway网关。可是发现将前端请求的端口指向网关后,用postman发送请求
- 前面的铺垫文章已经连着写了六篇了,主要是介绍了spring和SpringMVC框架,小伙伴们在学习的过程中大概也发现了这两个框架需要我们手动
- 在Java里面,可以用复制语句”A=B”给基本类型的数
- 何为高阶函数 大家可能对这个名词并不熟悉,但是这个名词所表达的事物却是我们经常使用到的。只要我们的函
- spring cloud oauth2 feign 遇到的坑关于oauth2相关的内容这里不重复描述,在spring cloud中在管理内部
- 来源:https://www.cnblogs.com/dato/p/7027949.html
- 1,首先要安装OpenCvSharp,使用cv2的函数获取设备,并将图像转换到Bitmapusing OpenCvSharp;
- 一、File流概念 JAVA中针对文件的读写操作设置了一系列的流,其
- 在阻塞队里中,除了对元素进行增加和删除外,我们可以把元素的删除做一个延迟的处理,即使用DelayQueue的方法。本文就来和大家聊聊Java
- /// <summary> /// 遍历Co