你的位置:首页 > ASP.net教程

[ASP.net教程]WPF实现炫酷Loading控件

Win8系统的Loading效果还是很不错的,网上也有人用CSS3等技术实现,研究了一下,并打算用WPF自定义一个Loading控件实现类似的效果,并可以让用户对Loading的颗粒(Particle)背景颜色进行自定义,话不多说,直接上代码:

1、用VS2012新建一个WPF的用户控件库项目WpfControlLibraryDemo,VS自动生成如下结构:

2、删除UserControl1.xaml,并新建一个Loading的CustomControl(不是UserControl),如下图所示:

3、如果报错找不到Loading类型,请编译,下面在Generic.xaml主题文件中对Loading的样式和内容进行定义(注意添加 

 1 <ResourceDictionary 2   ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3   ="http://schemas.microsoft.com/winfx/2006/xaml" 4    = "clr-namespace:System;assembly=mscorlib" 5   ="clr-namespace:WpfControlLibraryDemo"> 6  7  8   <Style TargetType="{x:Type local:Loading}"> 9     <Setter Property="Template"> 10       <Setter.Value> 11         <ControlTemplate TargetType="{x:Type local:Loading}"> 12           <Border Background="{TemplateBinding Background}" 13               BorderBrush="{TemplateBinding BorderBrush}" 14               BorderThickness="{TemplateBinding BorderThickness}"> 15             <Grid Width = "50" Height = "50"> 16               <Grid.Resources> 17                 <!-- Value Converters --> 18               19                 <!-- Particle Styling ,must to has RelativeSource --> 20                 <SolidColorBrush x:Key = "ParticleColor" Color = "{Binding Path=FillColor,RelativeSource={RelativeSource TemplatedParent}}" /> 21                 <SolidColorBrush x:Key = "ParticleBackgroundColor" Color = "Transparent"/> 22                 <system:Double x:Key = "ParticleOpacity">1</system:Double> 23                 <system:Double x:Key = "ParticleRadius">5</system:Double> 24  25                 <system:Double x:Key = "StartingPointX">0</system:Double> 26                 <system:Double x:Key = "StartingPointY">-20</system:Double> 27  28                 <system:Double x:Key = "RotationPointX">0.5</system:Double> 29                 <system:Double x:Key = "RotationPointY">0.5</system:Double> 30  31                 <!-- StoryBoard --> 32                 <system:TimeSpan x:Key = "StoryBoardBeginTimeP0">00:00:00.000</system:TimeSpan> 33                 <system:TimeSpan x:Key = "StoryBoardBeginTimeP1">00:00:00.100</system:TimeSpan> 34                 <system:TimeSpan x:Key = "StoryBoardBeginTimeP2">00:00:00.200</system:TimeSpan> 35                 <system:TimeSpan x:Key = "StoryBoardBeginTimeP3">00:00:00.300</system:TimeSpan> 36                 <system:TimeSpan x:Key = "StoryBoardBeginTimeP4">00:00:00.400</system:TimeSpan> 37                 <Duration x:Key = "StoryBoardDuration">00:00:01.800</Duration> 38  39                 <!-- Particle Origin Angles --> 40                 <system:Double x:Key = "ParticleOriginAngleP0">0</system:Double> 41                 <system:Double x:Key = "ParticleOriginAngleP1">-10</system:Double> 42                 <system:Double x:Key = "ParticleOriginAngleP2">-20</system:Double> 43                 <system:Double x:Key = "ParticleOriginAngleP3">-30</system:Double> 44                 <system:Double x:Key = "ParticleOriginAngleP4">-40</system:Double> 45  46                 <!-- Particle Position & Timing 1 --> 47                 <system:Double x:Key = "ParticleBeginAngle1">0</system:Double> 48                 <system:Double x:Key = "ParticleEndAngle1">90</system:Double> 49                 <system:TimeSpan x:Key = "ParticleBeginTime1">00:00:00.000</system:TimeSpan> 50                 <Duration x:Key = "ParticleDuration1">00:00:00.750</Duration> 51  52                 <!-- Particle Position & Timing 2 --> 53                 <system:Double x:Key = "ParticleBeginAngle2">90</system:Double> 54                 <system:Double x:Key = "ParticleEndAngle2">270</system:Double> 55                 <system:TimeSpan x:Key = "ParticleBeginTime2">00:00:00.751</system:TimeSpan> 56                 <Duration x:Key = "ParticleDuration2">00:00:00.300</Duration> 57  58                 <!-- Particle Position & Timing 3 --> 59                 <system:Double x:Key = "ParticleBeginAngle3">270</system:Double> 60                 <system:Double x:Key = "ParticleEndAngle3">360</system:Double> 61                 <system:TimeSpan x:Key = "ParticleBeginTime3">00:00:01.052</system:TimeSpan> 62                 <Duration x:Key = "ParticleDuration3">00:00:00.750</Duration> 63  64                 <Style x:Key = "EllipseStyle" TargetType = "Ellipse"> 65                   <Setter Property = "Width" Value = "{StaticResource ParticleRadius}"/> 66                   <Setter Property = "Height" Value = "{StaticResource ParticleRadius}"/> 67                   <Setter Property = "Fill" Value = "{StaticResource ParticleColor}"/> 68                   <Setter Property = "RenderTransformOrigin" Value = "0.5, 0.5"/> 69                   <Setter Property = "Opacity" Value = "{StaticResource ParticleOpacity}"/> 70                 </Style> 71               </Grid.Resources> 72               <Canvas Width = "1" Height = "1" Margin="0,0,0,0"> 73                 <Canvas.Triggers> 74                   <EventTrigger RoutedEvent = "Canvas.Loaded"> 75                     <EventTrigger.Actions> 76                       <BeginStoryboard> 77                         <Storyboard 78              79               BeginTime = "{StaticResource StoryBoardBeginTimeP0}" 80               Duration = "{StaticResource StoryBoardDuration}" 81               RepeatBehavior = "Forever"> 82                           <DoubleAnimation 83                 Storyboard.TargetName = "p0" 84                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)" 85                 From = "{StaticResource ParticleBeginAngle1}" 86                 To = "{StaticResource ParticleEndAngle1}" 87                 BeginTime = "{StaticResource ParticleBeginTime1}" 88                 Duration = "{StaticResource ParticleDuration1}"/> 89                           <DoubleAnimation 90                 Storyboard.TargetName = "p0" 91                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)" 92                 From = "{StaticResource ParticleBeginAngle2}" 93                 To = "{StaticResource ParticleEndAngle2}" 94                 BeginTime = "{StaticResource ParticleBeginTime2}" 95                 Duration = "{StaticResource ParticleDuration2}"/> 96                           <DoubleAnimation 97                 Storyboard.TargetName = "p0" 98                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)" 99                 From = "{StaticResource ParticleBeginAngle3}"100                 To = "{StaticResource ParticleEndAngle3}"101                 BeginTime = "{StaticResource ParticleBeginTime3}"102                 Duration = "{StaticResource ParticleDuration3}"/>103                         </Storyboard>104                       </BeginStoryboard>105                       <BeginStoryboard>106                         <Storyboard107               108               BeginTime = "{StaticResource StoryBoardBeginTimeP1}"109               Duration = "{StaticResource StoryBoardDuration}"110               RepeatBehavior = "Forever">111 112                           <DoubleAnimation113                 Storyboard.TargetName = "p1"114                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"115                 From = "{StaticResource ParticleBeginAngle1}"116                 To = "{StaticResource ParticleEndAngle1}"117                 BeginTime = "{StaticResource ParticleBeginTime1}"118                 Duration = "{StaticResource ParticleDuration1}"/>119                           <DoubleAnimation120                 Storyboard.TargetName = "p1"121                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"122                 From = "{StaticResource ParticleBeginAngle2}"123                 To = "{StaticResource ParticleEndAngle2}"124                 BeginTime = "{StaticResource ParticleBeginTime2}"125                 Duration = "{StaticResource ParticleDuration2}"/>126                           <DoubleAnimation127                 Storyboard.TargetName = "p1"128                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"129                 From = "{StaticResource ParticleBeginAngle3}"130                 To = "{StaticResource ParticleEndAngle3}"131                 BeginTime = "{StaticResource ParticleBeginTime3}"132                 Duration = "{StaticResource ParticleDuration3}"/>133                         </Storyboard>134                       </BeginStoryboard>135                       <BeginStoryboard>136                         <Storyboard137               138               BeginTime = "{StaticResource StoryBoardBeginTimeP2}"139               Duration = "{StaticResource StoryBoardDuration}"140               RepeatBehavior = "Forever">141 142                           <DoubleAnimation143                 Storyboard.TargetName = "p2"144                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"145                 From = "{StaticResource ParticleBeginAngle1}"146                 To = "{StaticResource ParticleEndAngle1}"147                 BeginTime = "{StaticResource ParticleBeginTime1}"148                 Duration = "{StaticResource ParticleDuration1}"/>149                           <DoubleAnimation150                 Storyboard.TargetName = "p2"151                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"152                 From = "{StaticResource ParticleBeginAngle2}"153                 To = "{StaticResource ParticleEndAngle2}"154                 BeginTime = "{StaticResource ParticleBeginTime2}"155                 Duration = "{StaticResource ParticleDuration2}"/>156                           <DoubleAnimation157                 Storyboard.TargetName = "p2"158                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"159                 From = "{StaticResource ParticleBeginAngle3}"160                 To = "{StaticResource ParticleEndAngle3}"161                 BeginTime = "{StaticResource ParticleBeginTime3}"162                 Duration = "{StaticResource ParticleDuration3}"/>163                         </Storyboard>164                       </BeginStoryboard>165 166                       <BeginStoryboard>167                         <Storyboard168               169               BeginTime = "{StaticResource StoryBoardBeginTimeP3}"170               Duration = "{StaticResource StoryBoardDuration}"171               RepeatBehavior = "Forever">172 173                           <DoubleAnimation174                 Storyboard.TargetName = "p3"175                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"176                 From = "{StaticResource ParticleBeginAngle1}"177                 To = "{StaticResource ParticleEndAngle1}"178                 BeginTime = "{StaticResource ParticleBeginTime1}"179                 Duration = "{StaticResource ParticleDuration1}"/>180                           <DoubleAnimation181                 Storyboard.TargetName = "p3"182                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"183                 From = "{StaticResource ParticleBeginAngle2}"184                 To = "{StaticResource ParticleEndAngle2}"185                 BeginTime = "{StaticResource ParticleBeginTime2}"186                 Duration = "{StaticResource ParticleDuration2}"/>187                           <DoubleAnimation188                 Storyboard.TargetName = "p3"189                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"190                 From = "{StaticResource ParticleBeginAngle3}"191                 To = "{StaticResource ParticleEndAngle3}"192                 BeginTime = "{StaticResource ParticleBeginTime3}"193                 Duration = "{StaticResource ParticleDuration3}"/>194                         </Storyboard>195                       </BeginStoryboard>196 197                       <BeginStoryboard>198                         <Storyboard199               200               BeginTime = "{StaticResource StoryBoardBeginTimeP4}"201               Duration = "{StaticResource StoryBoardDuration}"202               RepeatBehavior = "Forever">203 204                           <DoubleAnimation205                 Storyboard.TargetName = "p4"206                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"207                 From = "{StaticResource ParticleBeginAngle1}"208                 To = "{StaticResource ParticleEndAngle1}"209                 BeginTime = "{StaticResource ParticleBeginTime1}"210                 Duration = "{StaticResource ParticleDuration1}"/>211                           <DoubleAnimation212                 Storyboard.TargetName = "p4"213                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"214                 From = "{StaticResource ParticleBeginAngle2}"215                 To = "{StaticResource ParticleEndAngle2}"216                 BeginTime = "{StaticResource ParticleBeginTime2}"217                 Duration = "{StaticResource ParticleDuration2}"/>218                           <DoubleAnimation219                 Storyboard.TargetName = "p4"220                 Storyboard.TargetProperty = "(UIElement.RenderTransform).(RotateTransform.Angle)"221                 From = "{StaticResource ParticleBeginAngle3}"222                 To = "{StaticResource ParticleEndAngle3}"223                 BeginTime = "{StaticResource ParticleBeginTime3}"224                 Duration = "{StaticResource ParticleDuration3}"/>225                         </Storyboard>226                       </BeginStoryboard>227                     </EventTrigger.Actions>228                   </EventTrigger>229                 </Canvas.Triggers>230                 <Border231       x:Name = "p0"232       Background = "{StaticResource ParticleBackgroundColor}"233       Opacity = "{StaticResource ParticleOpacity}">234                   <Border.RenderTransform>235                     <RotateTransform/>236                   </Border.RenderTransform>237                   <Border.RenderTransformOrigin>238                     <Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>239                   </Border.RenderTransformOrigin>240                   <Ellipse Style = "{StaticResource EllipseStyle}">241                     <Ellipse.RenderTransform>242                       <TransformGroup>243                         <TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>244                         <RotateTransform Angle = "{StaticResource ParticleOriginAngleP0}"/>245                       </TransformGroup>246                     </Ellipse.RenderTransform>247                   </Ellipse>248                 </Border>249                 <Border250       x:Name = "p1"251       Background = "{StaticResource ParticleBackgroundColor}"252       Opacity = "{StaticResource ParticleOpacity}">253                   <Border.RenderTransform>254                     <RotateTransform/>255                   </Border.RenderTransform>256                   <Border.RenderTransformOrigin>257                     <Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>258                   </Border.RenderTransformOrigin>259                   <Ellipse Style = "{StaticResource EllipseStyle}">260                     <Ellipse.RenderTransform>261                       <TransformGroup>262                         <TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>263                         <RotateTransform Angle = "{StaticResource ParticleOriginAngleP1}"/>264                       </TransformGroup>265                     </Ellipse.RenderTransform>266                   </Ellipse>267                 </Border>268                 <Border269       x:Name = "p2"270       Background = "{StaticResource ParticleBackgroundColor}"271       Opacity = "{StaticResource ParticleOpacity}">272                   <Border.RenderTransform>273                     <RotateTransform/>274                   </Border.RenderTransform>275                   <Border.RenderTransformOrigin>276                     <Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>277                   </Border.RenderTransformOrigin>278                   <Ellipse Style = "{StaticResource EllipseStyle}">279                     <Ellipse.RenderTransform>280                       <TransformGroup>281                         <TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>282                         <RotateTransform Angle = "{StaticResource ParticleOriginAngleP2}"/>283                       </TransformGroup>284                     </Ellipse.RenderTransform>285                   </Ellipse>286                 </Border>287                 <Border288       x:Name = "p3"289       Background = "{StaticResource ParticleBackgroundColor}"290       Opacity = "{StaticResource ParticleOpacity}">291                   <Border.RenderTransform>292                     <RotateTransform/>293                   </Border.RenderTransform>294                   <Border.RenderTransformOrigin>295                     <Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>296                   </Border.RenderTransformOrigin>297                   <Ellipse Style = "{StaticResource EllipseStyle}">298                     <Ellipse.RenderTransform>299                       <TransformGroup>300                         <TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>301                         <RotateTransform Angle = "{StaticResource ParticleOriginAngleP3}"/>302                       </TransformGroup>303                     </Ellipse.RenderTransform>304                   </Ellipse>305                 </Border>306                 <Border307       x:Name = "p4"308       Background = "{StaticResource ParticleBackgroundColor}"309       Opacity = "{StaticResource ParticleOpacity}">310                   <Border.RenderTransform>311                     <RotateTransform/>312                   </Border.RenderTransform>313                   <Border.RenderTransformOrigin>314                     <Point X = "{StaticResource RotationPointX}" Y = "{StaticResource RotationPointY}"/>315                   </Border.RenderTransformOrigin>316                   <Ellipse Style = "{StaticResource EllipseStyle}">317                     <Ellipse.RenderTransform>318                       <TransformGroup>319                         <TranslateTransform X = "{StaticResource StartingPointX}" Y = "{StaticResource StartingPointY}"/>320                         <RotateTransform Angle = "{StaticResource ParticleOriginAngleP4}"/>321                       </TransformGroup>322                     </Ellipse.RenderTransform>323                   </Ellipse>324                 </Border>325               </Canvas>326             </Grid>327 328 329 330           </Border>331         </ControlTemplate>332       </Setter.Value>333     </Setter>334   </Style>335   336   337   338 </ResourceDictionary>

在构建中发现,一开始在设定绑定时,写成<SolidColorBrush x:Key = "ParticleColor" Color = "{Binding Path=FillColor}" />一直都无法绑定成功,后来查了资料,改成<SolidColorBrush x:Key = "ParticleColor" Color = "{Binding Path=FillColor,RelativeSource={RelativeSource TemplatedParent}}" /> 后成功。

4、编辑Loading.cs文件,对自定义属性FillColor和逻辑进行编码:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Data; 9 using System.Windows.Documents;10 using System.Windows.Input;11 using System.Windows.Media;12 using System.Windows.Media.Imaging;13 using System.Windows.Navigation;14 using System.Windows.Shapes;15 16 namespace WpfControlLibraryDemo17 {18   using System.ComponentModel;19   /// <summary>20   /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。21   ///22   /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。23   /// 将此 24   /// 元素中:25   ///26   ///   27   ///28   ///29   /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。30   /// 将此 31   /// 元素中:32   ///33   ///   34   ///35   /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,36   /// 并重新生成以避免编译错误:37   ///38   ///   在解决方案资源管理器中右击目标项目,然后依次单击39   ///   “添加引用”->“项目”->[浏览查找并选择此项目]40   ///41   ///42   /// 步骤 2)43   /// 继续操作并在 XAML 文件中使用控件。44   ///45   ///   <MyNamespace:Loading/>46   ///47   /// </summary>48   public class Loading : Control49   {50     static Loading()51     {52       //重载默认样式53       DefaultStyleKeyProperty.OverrideMetadata(typeof(Loading), new FrameworkPropertyMetadata(typeof(Loading)));54       //DependencyProperty 注册 FillColor55       FillColorProperty = DependencyProperty.Register("FillColor",56         typeof(Color),57         typeof(Loading),58         new UIPropertyMetadata(Colors.DarkBlue,59         new PropertyChangedCallback(OnUriChanged))60         );61       //Colors.DarkBlue为控件初始化默认值62 63     }64     //属性变更回调函数65     private static void OnUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)66     {67       //Border b = (Border)d;68       //MessageBox.Show(e.NewValue.ToString());69 70     }71     #region 自定义Fields72     // DependencyProperty属性定义  FillColorProperty=FillColor+Property组成73     public static readonly DependencyProperty FillColorProperty;74     #endregion75     //VS设计器属性支持76     [Description("背景色"), Category("个性配置"), DefaultValue("#FF668899")]77     public Color FillColor78     {79       //GetValue,SetValue为固定写法,此处一般不建议处理其他逻辑80       get { return (Color)GetValue(FillColorProperty); }81       set { SetValue(FillColorProperty, value); }82     }83   }84 }

 5、编译,如果无误后,可以添加WPF应用程序WpfAppLoadingTest进行测试(添加项目引用)。

打开MainWindow.xaml,将Loading控件拖放到设计界面上,如下图所示:

 6、控件颜色修改,选中控件,在属性栏中进行配置即可:

 7.总结

可以看到WPF自定义控件还是比较容易的,但是难点在于UI的设计,如果需要做的美观,需要美工的参与,而且需要转换成XAML。