在windows phone開發中,難免要遇到與伺服器互動或者本地進行資料處理的時候,在這個時候系統要有很好的提示功能,告訴使用者現在不要以為系統死機了,就好比安裝軟體的時候progressbar能告訴我們進度,那個小綠條能讓我們安心。在手機上,我們應該也要實現這樣的功能,這樣才能算是友好的介面設計。
首先給出實現效果,如所示:
可以看到,當前介面是由兩塊組成的,一個是後台背景,一個前台的progressoverlay。在這裡我的後台其實就是一個簡單的textblock,當progressoverlay出現的時候自動讓後台變灰,隱藏於後端,可以說這是一個非常好的介面設計。如果就在textblock上面疊加,介面將會是這樣:
你說你還能看清progress提示的是什麼嗎?
更多例子請從這裡下載:
http://www.windowsphonegeek.com/upload/articles/ProgressOverlayDemo.zip
下面就說說實現:
1、首先下載coding4fun這個類庫,http://coding4fun.codeplex.com/ 這絕對是大大的好東西
2、添加dll到工程中,在前一篇中已經講過了,如下:
3、與toastpromote不同的是,這裡我們不是在頁面後台.cs檔案中調用,而是直接放在前台xaml檔案之中
在xaml中添加命名空間
xmlns:Controls="clr-namespace:Coding4Fun.Phone.Controls;assembly=Coding4Fun.Phone.Controls"
然後使用控制項即可
<Controls:ProgressOverlay Name="progressOverlay" > <Controls:ProgressOverlay.Content> <TextBlock>國慶節千萬不要來北京玩啊,人擠死人</TextBlock> </Controls:ProgressOverlay.Content> </Controls:ProgressOverlay>
有一點需要注意,這個添加的控制項代碼的位置應該放在其他控制項的後面,這樣才能實現把前一個控制項進行後台隱藏化的效果,例如和剛才的textblock搭配就是這樣:
<Grid x:Name="LayoutRoot" Background="Transparent"> <TextBlock Height="691" HorizontalAlignment="Left" Margin="33,45,0,0" Name="text" Text="我是中國人,釣魚島是中國的 " VerticalAlignment="Top" Width="447" /> <Controls:ProgressOverlay Name="progressOverlay" > <Controls:ProgressOverlay.Content> <TextBlock>國慶節千萬不要來北京玩啊,人擠死人</TextBlock> </Controls:ProgressOverlay.Content> </Controls:ProgressOverlay> </Grid>
於是上面的第一個效果就這樣實現了。
當然,我敢保證很多人按照我的這個方法並沒有實現這樣的效果,我看了程式碼範例後也覺得很困惑,為什麼我和程式碼範例一模一樣,可偏偏實現不了呢?在coding4fun討論區我也看到一群外國人在討論這個ProgressOverlay無法顯示問題。最終,我發現了原來程式碼範例用的是老的dll,而現在更新的dll實現方式變了,通過查詢,我找到解決方案,新浪部落格上面居然也有技術文章,讓我狂汗:http://blog.sina.com.cn/s/blog_94000f5201012t56.html
解決方案就是:
一:還是添加引用和命名空間
xmlns:slToolkit ="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"xmlns:c4f="clr-namespace:Coding4Fun.Phone.Controls;assembly=Coding4Fun.Phone.Controls"xmlns:Converters="clr-namespace:Coding4Fun.Phone.Controls.Converters;assembly=Coding4Fun.Phone.Controls"
二:這樣寫控制項代碼:
c4f:ProgressOverlay Name="progressOverlay" Visibility="{Binding OverlayVis}"><c4f:ProgressOverlay.Resources><Converters:VisibilityToBooleanConverter x:Key="VisToBoolConverter" /></c4f:ProgressOverlay.Resources><StackPanel><TextBlock HorizontalAlignment="Center">Loading</TextBlock><slToolkit:PerformanceProgressBar IsIndeterminate="{Binding ElementName=progressOverlay, Path=Visibility, Converter={StaticResource VisToBoolConverter}}"/></StackPanel></c4f:ProgressOverlay>
我想這樣改正以後就能真正實現效果了。
當然,也許還有一些人會疑惑這樣沒什麼用,畢竟這是頁面中寫死的,根本不像按鈕點擊那樣進行相應,而經過事件觸發產生這樣的效果才是可用的。於是,我覺得我應該這樣做:
1、建立一個使用者控制項頁面,在該使用者控制項頁面中使用這個progressoverlay控制項
xmal代碼如下:
<UserControl x:Class="UserControls.ProgressControl" 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:slToolkit ="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" xmlns:c4f="clr-namespace:Coding4Fun.Phone.Controls;assembly=Coding4Fun.Phone.Controls" xmlns:Converters="clr-namespace:Coding4Fun.Phone.Controls.Converters;assembly=Coding4Fun.Phone.Controls" mc:Ignorable="d" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" d:DesignHeight="768" d:DesignWidth="480"> <Grid x:Name="LayoutRoot" Background="Transparent" Width="480" Height="800" > <c4f:ProgressOverlay Name="progressOverlay" Visibility="{Binding OverlayVis}"> <c4f:ProgressOverlay.Resources> <Converters:VisibilityToBooleanConverter x:Key="VisToBoolConverter" /> </c4f:ProgressOverlay.Resources> <StackPanel> <TextBlock HorizontalAlignment="Center" Name="textBlockStatus">Loading</TextBlock> <slToolkit:PerformanceProgressBar IsIndeterminate="{Binding ElementName=progressOverlay, Path=Visibility, Converter={StaticResource VisToBoolConverter}}"/> </StackPanel> </c4f:ProgressOverlay> </Grid></UserControl>
後台.cs代碼如下:
using System;using System.Windows;using System.Windows.Controls;using System.Windows.Controls.Primitives;namespace UserControls{public partial class ProgressControl : UserControl{public ProgressControl(){InitializeComponent();}internal Popup ChildWindowPopup { get; private set; }public void SetMessage(string message){textBlockStatus.Text = message;}public void Show(){if (this.ChildWindowPopup == null){this.ChildWindowPopup = new Popup();try{this.ChildWindowPopup.Child = this;}catch (ArgumentException){throw new InvalidOperationException("The control is already shown.");}}if (this.ChildWindowPopup != null && Application.Current.RootVisual != null){this.ChildWindowPopup.IsOpen = true;}}public void Hide(){// Restore system traythis.ChildWindowPopup.IsOpen = false;}}}
2、在需要調用該控制項的事件函數中使用該控制項,例如我在同步的時候調用該控制項,添加引用然後建立該對象即可
//執行同步的響應函數public class SyncHandler{ProgressControl progressDialog; //ProgressIndicator progressDialog;DoEndEventHandler doEndHandler;public SyncHandler(DoEndEventHandler doEnd){doEndHandler = doEnd;}public void HandleMessage(object sender, SyncEventArgs e){ //非同步呼叫顯示輸出Deployment.Current.Dispatcher.BeginInvoke(() =>{if (progressDialog == null){ progressDialog = new ProgressControl();}progressDialog.Show();if (e.MsgID == SyncService.BEGIN_SYNC_MSG){progressDialog.SetMessage("開始同步");}else if (e.MsgID == SyncService.BEGIN_GOOGLE_SYNC){progressDialog.SetMessage("開始同步Google日曆");}else if (e.MsgID == SyncService.BEGIN_365_SYNC){progressDialog.SetMessage("開始同步");}else if (e.MsgID == SyncService.SYNC_GOOGLE_ERROR){ var toast = new ToastPrompt { Message = "同步Google日曆出錯", }; toast.Show();}else if (e.MsgID == SyncService.END_SYNC_MSG){progressDialog.Hide(); var toast = new ToastPrompt { Message = "同步完成", }; toast.Show();doEndHandler();}else if (e.MsgID == SyncService.START_REC_MSG){progressDialog.SetMessage("正在處理第" + e.Number + "條");}else if (e.MsgID == SyncService.END_REC_MSG){progressDialog.SetMessage("資料處理完畢");}else if (e.MsgID == SyncService.SYNC_SEND_NUM){progressDialog.SetMessage("正在發送第" + e.Number + "條");}else if (e.MsgID == SyncService.SYNC_REC_NUM){progressDialog.SetMessage("正在接收第" + e.Number + "條");}else if (e.MsgID == SyncService.SYNC_NO_NETWORK){ var toast = new ToastPrompt { Message = "無法訪問網路,請檢查網路連接", }; toast.Show();}else if (e.MsgID == SyncService.SYNC_NO_CRED){ var toast = new ToastPrompt { Message = "帳號認證失敗,請檢查365帳號設定", }; toast.Show();}else if (e.MsgID == SyncService.START_CALENDAR_SYNC){progressDialog.SetMessage("開始同步日曆");}else if (e.MsgID == SyncService.START_SCHEDULE_SYNC){progressDialog.SetMessage("開始同步議程");}else if (e.MsgID == SyncService.START_NOTE_SYNC){progressDialog.SetMessage("開始同步待辦");}else if (e.MsgID == SyncService.GOOGLE_TOKEN_ERROR){ var toast = new ToastPrompt { Message = "Google認證失敗", }; toast.Show();AccountEntity account = AccountControl.GetAccount();account.GoogleAccountState = AccountEntity.GOOGLE_USER_TOKEN_INVALIDATE;AccountControl.SaveAccount(account);}else if (e.MsgID == SyncService.SHOW_SLOW_SYNC){ var toast = new ToastPrompt { Message = "正在同步全部資料", }; toast.Show();//MessageBox.Show("正在同步全部資料");}else if (e.MsgID == SyncService.SYNC_RUNNING){ var toast = new ToastPrompt { Message = "後台運行同步", }; toast.Show();//MessageBox.Show("後台運行同步");}else{progressDialog.SetMessage("出錯了,親");}});}}
這下就大功告成了,而且完全能保證progressoverlay能出現在任何頁面之前把後台頁面進行隱藏化。同時,你還可以在progressoverlay結束時調用toastpromote,實現更好的使用者互動性。