前言:
在前面的系列中,我們雖然完成了其大部分功能,但是,離正真運行,還是有一大段距離
當你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代碼
三:接下來便是苦力活了,把原來用到傳統對框的提示,通通改過來。
這個改的點有點多,留到下節MsgBox使用時細細說了。
最後上一實際應用中的圖:
版權聲明:本文原創發表於博客園,作者爲路過秋天,原文鏈接:
http://www.cnblogs.com/cyq1162/archive/2010/10/27/1861281.html