WPF開發程序過程中總會遇到一個需求:Loading...正在加載中,這樣一個需求作為加載的過渡效果。
這里博主給出兩種方法來實現:
1.使用一張規則圖片,加上圖片的wpf旋轉效果來實現加載效果。
2.wpf程序划點,然后旋轉實現加載效果。
下面分別給出實現方法及代碼:
1.規則圖片的旋轉實現
<Image x:Name="run_image" Source="../Images/loading_pic.png" Stretch="UniformToFill" Margin="25,0,0,0" Width="28" Height="28"
HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" >
</Image>
這里的RenderTransformOrigin="0.5,0.5"表示以圖片的圓心為指定變換原點
在后台中初始化代碼中加上下面一段:

//圖片轉動 DoubleAnimation da = new DoubleAnimation(); da.From = 0; da.To = 360; da.Duration = new Duration(TimeSpan.FromSeconds(3)); da.RepeatBehavior = RepeatBehavior.Forever; RotateTransform rt = new RotateTransform(); run_image.RenderTransform = rt; rt.BeginAnimation(RotateTransform.AngleProperty, da); //圖片轉動
2.wpf程序划點,然后旋轉實現加載效果
在xaml中我們添加一個遮罩層和這個loading的圖像:

<Grid x:Name="LoadGrid" Visibility="Collapsed" IsVisibleChanged="HandleVisibleChanged"> <Grid.Background> <SolidColorBrush Color="Black" Opacity="0.2" /> </Grid.Background> <Grid.Resources> <SolidColorBrush Color="#FF007BE5" x:Key="CirclesColor" /> <!--<SolidColorBrush Color="Black" x:Key="BackgroundColor" Opacity=".20" />--> </Grid.Resources> <Viewbox Width="100" Height="100" HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid x:Name="LayoutRoot" Background="Transparent" ToolTip="Please wait...." HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock Text="Loading..." HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" Foreground="#FFE3953D" FontWeight="Bold" /> <Canvas RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Height="120" Loaded="HandleLoaded" Unloaded="HandleUnloaded" > <Ellipse x:Name="C0" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="1.0"/> <Ellipse x:Name="C1" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.9"/> <Ellipse x:Name="C2" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.8"/> <Ellipse x:Name="C3" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.7"/> <Ellipse x:Name="C4" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.6"/> <Ellipse x:Name="C5" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.5"/> <Ellipse x:Name="C6" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.4"/> <Ellipse x:Name="C7" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.3"/> <Ellipse x:Name="C8" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.2"/> <Canvas.RenderTransform> <RotateTransform x:Name="SpinnerRotate" Angle="0" /> </Canvas.RenderTransform> </Canvas> </Grid> </Viewbox> </Grid>
上面的代碼實現了:一個半透明的黑色蒙版,9個顏色相同但是透明度不同的藍色圓點,loading字樣
然后需要在后台cs代碼中加入下列代碼:

#region /// <summary> /// 隊列計時器 /// </summary> private DispatcherTimer animationTimer; #endregion #region 加載界面初始化方法 public void LoadingWait() { animationTimer = new DispatcherTimer( DispatcherPriority.ContextIdle, Dispatcher); animationTimer.Interval = new TimeSpan(0, 0, 0, 0, 90); } #endregion #region 執行方法 private void Start() { animationTimer.Tick += HandleAnimationTick; animationTimer.Start(); } private void Stop() { animationTimer.Stop(); animationTimer.Tick -= HandleAnimationTick; } private void HandleAnimationTick(object sender, EventArgs e) { SpinnerRotate.Angle = (SpinnerRotate.Angle + 36) % 360; } private void HandleLoaded(object sender, RoutedEventArgs e) { const double offset = Math.PI; const double step = Math.PI * 2 / 10.0; SetPosition(C0, offset, 0.0, step); SetPosition(C1, offset, 1.0, step); SetPosition(C2, offset, 2.0, step); SetPosition(C3, offset, 3.0, step); SetPosition(C4, offset, 4.0, step); SetPosition(C5, offset, 5.0, step); SetPosition(C6, offset, 6.0, step); SetPosition(C7, offset, 7.0, step); SetPosition(C8, offset, 8.0, step); } private void SetPosition(Ellipse ellipse, double offset, double posOffSet, double step) { ellipse.SetValue(Canvas.LeftProperty, 50.0 + Math.Sin(offset + posOffSet * step) * 50.0); ellipse.SetValue(Canvas.TopProperty, 50 + Math.Cos(offset + posOffSet * step) * 50.0); } private void HandleUnloaded(object sender, RoutedEventArgs e) { Stop(); } private void HandleVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { bool isVisible = (bool)e.NewValue; if (animationTimer == null) { LoadingWait(); } if (isVisible) Start(); else Stop(); }
以上的代碼主要實現loading圖像的旋轉,這里原理是這樣的:初始化的時候先將9個圓點按照圓形正圓排列(HandleLoaded方法),然后初始化一個DispatcherTimer定時器(知識點:timer和DispatcherTimer的區別),這樣定時觸發HandleAnimationTick方法(該方法會給圓形圖像設置旋轉角度)
最重要的是,這些動作在該圖顯示顯示的時候發生(IsVisibleChanged="HandleVisibleChanged" //這個元素的 IsVisible 屬性值變化時發生),要想不顯示該效果只需要將該元素隱藏即可(this.LoadGrid.Visibility = System.Windows.Visibility.Collapsed;//遮罩層隱藏)。
這塊其實可以單獨提取出來,哪里想要使用直接引用即可。
新建一個usercontrol

<UserControl x:Class="LoadingMask_Demo.LoadingWait" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" IsVisibleChanged="HandleVisibleChanged"> <UserControl.Background> <SolidColorBrush Color="Black" Opacity="0.2" /> </UserControl.Background> <UserControl.Resources> <SolidColorBrush Color="#FF007BE5" x:Key="CirclesColor" /> <!--<SolidColorBrush Color="Black" x:Key="BackgroundColor" Opacity=".20" />--> </UserControl.Resources> <Viewbox Width="100" Height="100" HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid x:Name="LayoutRoot" Background="Transparent" ToolTip="Please wait...." HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock Text="Loading..." HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" Foreground="#FFE3953D" FontWeight="Bold" /> <Canvas RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Height="120" Loaded="HandleLoaded" Unloaded="HandleUnloaded" > <Ellipse x:Name="C0" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="1.0"/> <Ellipse x:Name="C1" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.9"/> <Ellipse x:Name="C2" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.8"/> <Ellipse x:Name="C3" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.7"/> <Ellipse x:Name="C4" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.6"/> <Ellipse x:Name="C5" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.5"/> <Ellipse x:Name="C6" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.4"/> <Ellipse x:Name="C7" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.3"/> <Ellipse x:Name="C8" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Fill="{StaticResource CirclesColor}" Opacity="0.2"/> <Canvas.RenderTransform> <RotateTransform x:Name="SpinnerRotate" Angle="0" /> </Canvas.RenderTransform> </Canvas> </Grid> </Viewbox> </UserControl>
對應的cs文件代碼:

using System; using System.Collections.Generic; using System.Linq; using System.Text; 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; using System.Windows.Threading; namespace LoadingMask_Demo { /// <summary> /// Interaction logic for LoadingWait.xaml /// </summary> public partial class LoadingWait : UserControl { #region Data private readonly DispatcherTimer animationTimer; #endregion #region Constructor public LoadingWait() { InitializeComponent(); animationTimer = new DispatcherTimer( DispatcherPriority.ContextIdle, Dispatcher); animationTimer.Interval = new TimeSpan(0, 0, 0, 0, 90); } #endregion #region Private Methods private void Start() { animationTimer.Tick += HandleAnimationTick; animationTimer.Start(); } private void Stop() { animationTimer.Stop(); animationTimer.Tick -= HandleAnimationTick; } private void HandleAnimationTick(object sender, EventArgs e) { SpinnerRotate.Angle = (SpinnerRotate.Angle + 36) % 360; } private void HandleLoaded(object sender, RoutedEventArgs e) { const double offset = Math.PI; const double step = Math.PI * 2 / 10.0; SetPosition(C0, offset, 0.0, step); SetPosition(C1, offset, 1.0, step); SetPosition(C2, offset, 2.0, step); SetPosition(C3, offset, 3.0, step); SetPosition(C4, offset, 4.0, step); SetPosition(C5, offset, 5.0, step); SetPosition(C6, offset, 6.0, step); SetPosition(C7, offset, 7.0, step); SetPosition(C8, offset, 8.0, step); } private void SetPosition(Ellipse ellipse, double offset, double posOffSet, double step) { ellipse.SetValue(Canvas.LeftProperty, 50.0 + Math.Sin(offset + posOffSet * step) * 50.0); ellipse.SetValue(Canvas.TopProperty, 50 + Math.Cos(offset + posOffSet * step) * 50.0); } private void HandleUnloaded(object sender, RoutedEventArgs e) { Stop(); } private void HandleVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { bool isVisible = (bool)e.NewValue; if (isVisible) Start(); else Stop(); } #endregion } }
調用時前台的代碼:

<Window x:Class="LoadingMask_Demo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:local="clr-namespace:LoadingMask_Demo" > <DockPanel> <StackPanel Orientation="Horizontal" DockPanel.Dock="Top"> <Button Content="show" Width="70" Height="30" Click="ShowButton_Click" /> <Button Content="hide" Width="70" Height="30" Click="HideButton_Click"/> </StackPanel> <Grid Background="#FF484848" DockPanel.Dock="Bottom"> <TextBlock Text="asdfasdfasdf" Foreground="White"/> <local:LoadingWait x:Name="_loading" Visibility="Collapsed"/> </Grid> </DockPanel> </Window>
調用時后台控制顯示隱藏的代碼:

using System; using System.Collections.Generic; using System.Linq; using System.Text; 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 LoadingMask_Demo { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void ShowButton_Click(object sender, RoutedEventArgs e) { this._loading.Visibility = Visibility.Visible; } private void HideButton_Click(object sender, RoutedEventArgs e) { this._loading.Visibility = Visibility.Collapsed; } } }
看一下最后的效果圖: