Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四)
前言:
在前面的系列中,我們雖然完成了其大部分功能,但是,離正真運行,還是有一大段距離當你F5運行時,在彈出對話框之后,如果你不即時點確定,或者上個WC回來之后,你會發現已經提示出錯了
這節開始,我們將對其進行一小步一小步的優化,來避免一些明顯容易引發的錯誤。
?
感知一下最原始的消息彈出框如下圖:
?
?
一:傳統消息框,容易引發命案
?
1:原始的消息框,是線程阻塞類型的,很容易引發超時問題
線程阻塞?怎么理解?
簡單的說就是,WCF服務端給客戶端發送了消息提示之后,一直進入等待狀態,直到玩家點了確定,這時才繼續做其它事情。?
會產生什么問題?
玩家上WC去了?消息沒人確認,自然就會超時引發異常了,而且那線程也沒法接下去干其它活。?
解決方案?
a:傳統解決方案[加上倒計時,還是線程阻塞類型]
?
當初我只是想在這傳統的消息框上加上倒計時自動確認,這樣可以少一點避免超時情況。于是搜了一些資料,發現要用winapi來處理,這個這個....大才小用了吧。
?
b:更優的解決方案
無意中發現Silverlight的ChildWindow,正好解決了這一問題。因為?ChildWindow使用異步方式,非線程阻塞,消息一彈之后線程就回家去了。
而且用Sivlerlight內置的定時器DispatcherTimer,非常容易實現倒計時。
?
二:實現自定義非線程阻塞倒計時對話框,純種Sivlerlight
?
1:看看純種的長成什么樣
新建項目-》Silverlight?子窗口?-》起名叫MsgBox-》找另一個界面調用一下。比如在登陸頁面測試一下:MsgBox?box=new?MsgBox();box.Show();
?
結果所見如圖:
說明:
1:有背景灰色層,界面原生的還傳統消息框好看多了。2:重點提示:當初剛試的時候是直接運行MsgBox,然后在其構造函數中調用Show(),結果是出不來的。
?
2:改造-界面小小改動
我們將原來的xaml改造成如下:
<controls:ChildWindow?x:Class="ChessProject.MsgBox"?...省略一點...??Width="290"?Height="141"??Title="系統消息">????<Grid?x:Name="LayoutRoot"?Margin="2"?Height="97"?Width="270">
????????<Button?Visibility="Collapsed"?x:Name="CancelButton"?Content="取消"?Click="CancelButton_Click"?Width="75"?Height="23"?HorizontalAlignment="Right"?Margin="0,62,93,12"?/>
????????<Button?x:Name="OKButton"?Content="確定"?Click="OKButton_Click"?Width="75"?Height="23"?HorizontalAlignment="Right"?Margin="0,62,10,12"?/>
????????<TextBlock?Height="41"?TextWrapping="Wrap"?HorizontalAlignment="Left"?Margin="15,15,0,0"?Name="tbMsg"?Text="請按確定按鈕確定"?VerticalAlignment="Top"?Width="224"?/>
????</Grid>
</controls:ChildWindow>
?
界面效果如圖,和上圖差不多[這里把取消放在前面,只是為了不顯示取消時,確定還保留在原位好看點]:
?
3:改造,在標題加入倒計時
a:加入計時器并初始化
???????DispatcherTimer?timer;//定時器????????public?MsgBox()
????????{
????????????InitializeComponent();
????????????timer?=?new?DispatcherTimer();
????????????timer.Interval?=?TimeSpan.FromSeconds(1);
????????????timer.Tick?+=?new?EventHandler(timer_Tick);
????????}
b:新加show方法并實現倒計時
???????int?defaultTime?=?3;//默認N秒????????string?userTitle;
???????DispatcherTimer?timer;//定時器
????????public?MsgBox()
????????{
????????????//...省略...
????????}
????????void?timer_Tick(object?sender,?EventArgs?e)
????????{
????????????Title?=?string.Format(userTitle?+?"?[倒計時自動確定:{0}秒]",?defaultTime);
????????????defaultTime--;
????????????if?(defaultTime?==?0)
????????????{
????????????????ResetTimer();
????????????}
????????}
????????void?ResetTimer()
????????{
????????????timer.Stop();
????????????defaultTime?=?3;
????????}
????????public?void?Show(string?msg,?string?title)
????????{
????????????tbMsg.Text?=?msg;
????????????userTitle?=?title;
????????????Show();
????????????timer.Start();
????????}
c:再調用一下看結果
MsgBox?box?=?new?MsgBox();box.Show("http://cyq1162.cnblogs.com","路過秋天");
如圖:
?
4:擴展show函數:加入回調/倒計時時間/按鈕類型/默認確認類型
首先:這個子窗口是異步的,所以,在點擊完確定時,需要增加多一個回調函數;接著:默認3秒,很明顯情況不同,時間也要稍為增加變動一下;
然后:有時候按鈕只是確定,有時候就是取消+確定; 最后:倒計時時間到了,默認執行確定,還是執行取消。
?
于是,要實現了:
a:如何實現回調?
默認子窗口就有Closed事件,我們用它的事件,在點擊確定或取消時,執行Close()方法
????????public?MsgBox()????????{
????????????InitializeComponent();
????????????timer?=?new?DispatcherTimer();
????????????timer.Interval?=?TimeSpan.FromSeconds(1);
????????????timer.Tick?+=?new?EventHandler(timer_Tick);
????????????this.Closed?+=?new?EventHandler(MsgBox_Closed);
????????}
????????void?MsgBox_Closed(object?sender,?EventArgs?e)
????????{
????????????//待實現
?????????}
????????private?void?OKButton_Click(object?sender,?RoutedEventArgs?e)
????????{
????????????this.DialogResult?=?true;
????????????Close();//調用一下關閉
????????}
????????private?void?CancelButton_Click(object?sender,?RoutedEventArgs?e)
????????{
????????????this.DialogResult?=?false;
????????????Close();//調用一下關閉
????????}
?
問題?我們難道對所有的確定都執行相同的代碼?
首先說:異步不能像同步那樣寫if(show(xxx,xxx)){方法}于是說:這是個很嚴重的問題,因為不同的確定,我們執行的事件肯定是不同的。
?
解決問題?匿名委托出手了!!!
匿名委托:[Action<T1,T2,T3...N個重載>],這是個很好用的東東,可以傳進方法名稱,在執行后調用不同的方法。?
匿名委托實現:
Action<bool>?callBackEvent;//全局定義void?MsgBox_Closed(object?sender,?EventArgs?e)
{
????if?(callBackEvent?!=?null)
????{
????????callBackEvent(DialogResult.Value);
????}
}
?
那委托是如何傳入的?Show方法增加擴展參數傳入。
b:這里貼出完整代碼,一并實現:倒計時時間/按鈕類型/默認確認類型
完整的MsgBox代碼 ????public?partial?class?MsgBox?:?ChildWindow????{
????????int?defaultTime?=?3;//默認N秒
????????string?userTitle;
????????DispatcherTimer?timer;//定時器
????????Action<bool>?callBackEvent;
????????bool?autoOKConfirm?=?true;
????????public?MsgBox()
????????{
????????????InitializeComponent();
????????????timer?=?new?DispatcherTimer();
????????????timer.Interval?=?TimeSpan.FromSeconds(1);
????????????timer.Tick?+=?new?EventHandler(timer_Tick);
????????????this.Closed?+=?new?EventHandler(MsgBox_Closed);
????????}
????????void?MsgBox_Closed(object?sender,?EventArgs?e)
????????{
????????????//待實現
????????}
????????void?timer_Tick(object?sender,?EventArgs?e)
????????{
????????????Title?=?string.Format(userTitle?+?"?[倒計時自動確定:{0}秒]",?defaultTime);
????????????defaultTime--;
????????????if?(defaultTime?==?0)
????????????{
????????????????ResetTimer();
????????????????if?(autoOKConfirm)
????????????????{
????????????????????OKButton_Click(null,?null);
????????????????}
????????????????else
????????????????{
????????????????????CancelButton_Click(null,?null);
????????????????}
????????????}
????????}
????????void?ResetTimer()
????????{
????????????timer.Stop();
????????????defaultTime?=?3;
????????}
????????public?void?Show(string?msg,?string?title)
????????{
????????????Show(msg,?title,?defaultTime,?null,?true,?MessageBoxButton.OK);
????????}
????????public?void?Show(string?msg,?string?title,?int?timeSecond,?Action<bool>?callBack)
????????{
????????????Show(msg,?title,?timeSecond,?callBack,?false,?MessageBoxButton.OKCancel);
????????}
????????public?void?Show(string?msg,?string?title,?int?timeSecond,?Action<bool>?callBack,?bool?autoOK,?MessageBoxButton?button)
????????{
????????????tbMsg.Text?=?msg;
????????????userTitle?=?title;
????????????if?(button?==?MessageBoxButton.OK)
????????????{
????????????????OKButton.Content?=?"確定";
????????????????CancelButton.Visibility?=?System.Windows.Visibility.Collapsed;
????????????}
????????????else
????????????{
????????????????CancelButton.Visibility?=?System.Windows.Visibility.Visible;
????????????????OKButton.Content?=?"同意";
????????????????CancelButton.Content?=?"拒絕";
????????????}
????????????defaultTime?=?timeSecond;
????????????autoOKConfirm?=?autoOK;
????????????callBackEvent?=?callBack;
????????????Show();
????????????timer.Start();
????????}
????????private?void?OKButton_Click(object?sender,?RoutedEventArgs?e)
????????{
????????????this.DialogResult?=?true;
????????}
????????private?void?CancelButton_Click(object?sender,?RoutedEventArgs?e)
????????{
????????????this.DialogResult?=?false;
????????}
????}
?
?
三:接下來便是苦力活了,把原來用到傳統對框的提示,通通改過來。
這個改的點有點多,留到下節MsgBox使用時細細說了。?
最后上一實際應用中的圖:
轉載于:https://www.cnblogs.com/cyq1162/archive/2010/10/27/1861281.html
總結
以上是生活随笔為你收集整理的Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于进程和线程以及句柄
- 下一篇: 由浅到深了解JavaScript类