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
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我