在開發Silverlight或者WPF項目時,當我們調用Web服務來加載一些數據時,由於數據量比較大需要較長的時間,需要用戶等待,為了給用戶友好的提示和避免用戶在加載數據過程中進行重復操作,我們通常使用BusyIndicator這個控件來鎖定當前頁面。然而,有時候BusyIndicator這個控件的風格和我們的界面風格並不搭配,而且修改起來也比較麻煩,今天我們就來自己寫一個BusyIndicator控件,實現自定義的忙碌提示。
后面會提供源碼下載。
我們先來看下面這段代碼,如圖:
我們添加了三個矩形在Grid中,我們設置了矩形的寬度和高度,那么矩形會怎么顯示呢?從上到下順序顯示嗎?NO!不是這樣的,我們來看看顯示結果:
三個矩形層疊在了一起,按照代碼的順序,依次從下往上顯示,代碼中放在最后的矩形顯示在最頂層。這是Grid的一個特性,當然在Canvas中也可以層疊顯示,不過不是居中顯示,是右上腳對齊顯示的。如果是StackPanel則是從上到下一次顯示。
根據這個特性,我們知道在Grid中后添加的UI元素會顯示在其他元素的最頂層,所以我們可以在運行時通過代碼來動態的向Grid中添加元素,並且這個元素處於最頂層,從而可以遮擋其他頁面元素。
下面我們來看看最終的實現效果:
是不是有一種中國風的味道啊!下面我們來詳細說明實現方法。
這里我是用Silverlight來演示,用WPF也是一樣的。首先新建項目,添加一個Silverlight user Control,這里我起的名字就叫Load,頁面XAML代碼如下:
<UserControl x:Class="SilverlightBusy.Load" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.Resources> <Storyboard x:Name="fadeStoryboard"> <DoubleAnimation x:Name="fadeAnimation" BeginTime="00:00:00" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Opacity" From="0.9" To="0" Duration="0:0:01"> </DoubleAnimation> </Storyboard> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="#cccccc" Opacity="0.9"> <Grid.Resources> <Storyboard x:Name="fadeImgStoryboard"> <DoubleAnimation x:Name="fadeImgAnimation" BeginTime="00:00:00" Storyboard.TargetName="LoadImg" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:01"> </DoubleAnimation> </Storyboard> </Grid.Resources> <Image x:Name="LoadImg" Source="/SilverlightBusy;component/Images/Loading.png" Width="128" Height="128"> </Image> <TextBlock x:Name="txtLoading" Width="60" VerticalAlignment="Center" HorizontalAlignment="Center" Text="Loading..."/> </Grid> </UserControl>
其實這個頁面很簡單,就是一個Grid、一個Image和一個TextBlock,添加兩個Storyboard是為了有個過渡效果,這樣看起來更加平滑一下,直接隱藏掉Image和TextBlock的話,會讓人感覺閃一下。其設計視圖如圖:
其后台代碼如下:
public partial class Load : UserControl { private int _counter = 0; private DispatcherTimer timer = new DispatcherTimer(); private RotateTransform rt = new RotateTransform(); private bool _isBusy = false; public bool IsBusy { get { return _isBusy; } set { _isBusy = value; if (value) { this.LayoutRoot.Visibility = Visibility.Visible; this.LayoutRoot.Opacity = 0.9; timer.Start(); } else { //首先隱藏圖片,圖片隱藏后隱藏掉透明的背景層。 fadeImgStoryboard.Begin(); fadeImgStoryboard.Completed += (sender, e) => { txtLoading.Visibility = Visibility.Collapsed; fadeStoryboard.Begin(); }; fadeStoryboard.Completed += (sender, e) => { timer.Stop(); this.LayoutRoot.Visibility = Visibility.Collapsed; }; } } } public Load() { InitializeComponent(); timer.Interval = new TimeSpan(200000); timer.Tick += new EventHandler(timer_Tick); timer.Start(); } void timer_Tick(object sender, EventArgs e) { _counter++; //設置旋轉中心點,根據圖片大小設置,值為圖片尺寸/2. rt.CenterX = 64; rt.CenterY = 64; rt.Angle -= 10; //旋轉圖片,每次旋轉10度,可自定義旋轉方向 LoadImg.RenderTransform = rt; //讓Loading后面的點閃的不要太快 if (_counter % 8 == 0) { if (txtLoading.Text.Equals("Loading...")) { txtLoading.Text = "Loading."; } else if (txtLoading.Text.Equals("Loading.")) { txtLoading.Text = "Loading.."; } else if (txtLoading.Text.Equals("Loading..")) { txtLoading.Text = "Loading..."; } } } }
后台代碼主要控制圖片旋轉動畫和問題動畫,還有就是數據加載完畢時,隱藏頁面元素。
在MainPage中添加一個按鈕,添加click事件,代碼如下:
public partial class MainPage : UserControl { private Load load = null; public MainPage() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { load = new Load(); LayoutRoot.Children.Add(load);//將Load添加到頁面,會顯示在最頂層 load.IsBusy = true; //在線程中調用,否則會造成UI線程阻塞。 new System.Threading.Thread(() => { for (int i = 0; i < 10; i++) { System.Threading.Thread.Sleep(500); } this.Dispatcher.BeginInvoke(() => { load.IsBusy = false; }); }).Start(); } }
添加完成后按F5執行,我們在打開的頁面中單擊按鈕,就可以看到效果了。
當然,這里只是實現了和BusyIndicator一樣的效果,如果想像使用BusyIndicator那樣的話,我們還要進一步的進行封裝。
作者:雲霏霏
QQ交流群:243633526
博客地址:http://www.cnblogs.com/yunfeifei/
聲明:本博客原創文字只代表本人工作中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關系。非商業,未授權,貼子請以現狀保留,轉載時必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
如果大家感覺我的博文對大家有幫助,請推薦支持一把,給我寫作的動力。