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改造成如下:

複製代碼
ExpandedBlockStart.gif
< 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:加入計時器並初始化

複製代碼
ExpandedBlockStart.gif
       DispatcherTimer timer; // 定時器
         public  MsgBox()
        {
            InitializeComponent();
            timer 
=   new  DispatcherTimer();
            timer.Interval 
=  TimeSpan.FromSeconds( 1 );
            timer.Tick 
+=   new  EventHandler(timer_Tick);
        }
複製代碼

b:新加show方法並實現倒計時

複製代碼
ExpandedBlockStart.gif
        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()方法

複製代碼
ExpandedBlockStart.gif
         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代碼

 

 

三:接下來便是苦力活了,把原來用到傳統對框的提示,通通改過來。

這個改的點有點多,留到下節MsgBox使用時細細說了。

 

最後上一實際應用中的圖:

版權聲明:本文原創發表於博客園,作者爲路過秋天,原文鏈接:

http://www.cnblogs.com/cyq1162/archive/2010/10/27/1861281.html