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的樣式和內容進行定義(注意添加 xmlns:system = "clr-namespace:System;assembly=mscorlib"),代碼如下:

 1 <ResourceDictionary  2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4  xmlns:system = "clr-namespace:System;assembly=mscorlib"
 5  xmlns:local="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                                                 <Storyboard 107                             
108                             BeginTime = "{StaticResource StoryBoardBeginTimeP1}"
109  Duration = "{StaticResource StoryBoardDuration}"
110  RepeatBehavior = "Forever">
111 
112                                                     <DoubleAnimation 113                                 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                                                     <DoubleAnimation 120                                 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                                                     <DoubleAnimation 127                                 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                                                 <Storyboard 137                             
138                             BeginTime = "{StaticResource StoryBoardBeginTimeP2}"
139  Duration = "{StaticResource StoryBoardDuration}"
140  RepeatBehavior = "Forever">
141 
142                                                     <DoubleAnimation 143                                 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                                                     <DoubleAnimation 150                                 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                                                     <DoubleAnimation 157                                 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                                                 <Storyboard 168                             
169                             BeginTime = "{StaticResource StoryBoardBeginTimeP3}"
170  Duration = "{StaticResource StoryBoardDuration}"
171  RepeatBehavior = "Forever">
172 
173                                                     <DoubleAnimation 174                                 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                                                     <DoubleAnimation 181                                 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                                                     <DoubleAnimation 188                                 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                                                 <Storyboard 199                             
200                             BeginTime = "{StaticResource StoryBoardBeginTimeP4}"
201  Duration = "{StaticResource StoryBoardDuration}"
202  RepeatBehavior = "Forever">
203 
204                                                     <DoubleAnimation 205                                 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                                                     <DoubleAnimation 212                                 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                                                     <DoubleAnimation 219                                 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                                 <Border 231             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                                 <Border 250             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                                 <Border 269             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                                 <Border 288             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                                 <Border 307             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 WpfControlLibraryDemo 17 { 18     using System.ComponentModel; 19     /// <summary>
20     /// 按照步驟 1a 或 1b 操作,然后執行步驟 2 以在 XAML 文件中使用此自定義控件。 21     ///
22     /// 步驟 1a) 在當前項目中存在的 XAML 文件中使用該自定義控件。 23     /// 將此 XmlNamespace 特性添加到要使用該特性的標記文件的根 24     /// 元素中: 25     ///
26     /// xmlns:MyNamespace="clr-namespace:WpfControlLibraryDemo" 27     ///
28     ///
29     /// 步驟 1b) 在其他項目中存在的 XAML 文件中使用該自定義控件。 30     /// 將此 XmlNamespace 特性添加到要使用該特性的標記文件的根 31     /// 元素中: 32     ///
33     /// xmlns:MyNamespace="clr-namespace:WpfControlLibraryDemo;assembly=WpfControlLibraryDemo" 34     ///
35     /// 您還需要添加一個從 XAML 文件所在的項目到此項目的項目引用, 36     /// 並重新生成以避免編譯錯誤: 37     ///
38     /// 在解決方案資源管理器中右擊目標項目,然后依次單擊 39     /// “添加引用”->“項目”->[瀏覽查找並選擇此項目] 40     ///
41     ///
42     /// 步驟 2) 43     /// 繼續操作並在 XAML 文件中使用控件。 44     ///
45     ///     <MyNamespace:Loading/>
46     ///
47     /// </summary>
48     public class Loading : Control 49  { 50         static Loading() 51  { 52             //重載默認樣式
53             DefaultStyleKeyProperty.OverrideMetadata(typeof(Loading), new FrameworkPropertyMetadata(typeof(Loading))); 54             //DependencyProperty 注冊 FillColor
55             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 自定義Fields
72         // DependencyProperty屬性定義 FillColorProperty=FillColor+Property組成
73         public static readonly DependencyProperty FillColorProperty; 74         #endregion
75         //VS設計器屬性支持
76         [Description("背景色"), Category("個性配置"), DefaultValue("#FF668899")] 77         public Color FillColor 78  { 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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM