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。
以上就是WPF实现炫酷Loading控件的全部内容,希望对大家的学习有所帮助。
本文地址:https://www.stayed.cn/item/14333
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我