背景
年后來到公司實(shí)習(xí),第一個(gè)星期沒有項(xiàng)目,也就無所事是,此時(shí)有一位前輩和我說,他們有一個(gè)系統(tǒng) 是基于Silverlight研發(fā)的,而其中使用的彈出窗口存在著不少的問題,因此如果可以的話,要我做出一 個(gè)彈出窗口的功能,其子元素可以是自定義的任何控件,
Silverlight的彈出窗口展示
。我很高興進(jìn)入公司才幾天就能有這樣的任務(wù),每一次我去不同的公司實(shí)習(xí),總是能在很短的時(shí)間內(nèi)被 “委以重任(當(dāng)然更多的是我自己在自戀)”去進(jìn)行可利用的基礎(chǔ)設(shè)施的研發(fā),非常感謝從大二開始都一 直如此信任和看得我的各家公司,我想只有在這樣的環(huán)境中才可以全力以赴……
總之接下此任務(wù)的情況是這樣的,那么至此我對(duì)Silverlight到底有多少的知識(shí)呢?答案是,零。認(rèn)識(shí) 我的人都知道,我是非常非常沒有美工水平的,因此對(duì)于幾乎所有前臺(tái)開發(fā)的技術(shù)都敬而遠(yuǎn)之,而其中如 此新穎的Silverlight更是令我望而生怯。
但是事已如此,剛進(jìn)公司也不能說我不會(huì)做,于是就硬著頭皮上了,最終的結(jié)果是這樣的:
首先用半天的時(shí)間基本撐握了Silverlight的模型,包括了解了Xaml的語法如DependencyProperty, AttachedProeprty等,基本熟悉了相關(guān)的API,至于控件樹之類的理念,Winform和Webform也是基本相同 的模型,因此熟悉起來也相對(duì)較快
隨后用半天的時(shí)間,折騰出了一個(gè)彈出窗口的原型,看起來確實(shí)相當(dāng)?shù)厥娣,彈出一個(gè)窗口再關(guān)閉, 彈出兩個(gè)窗口再相繼關(guān)閉,并沒有出現(xiàn)特別大的問題
然后,5分鐘的時(shí)間內(nèi),發(fā)現(xiàn)這東西并不完美,存在著不少的問題,于是從架構(gòu)上完全推倒了前一次的 作品,很明顯我的實(shí)現(xiàn)是基于一個(gè)錯(cuò)誤的設(shè)計(jì),也因此需要將整個(gè)模型進(jìn)行重新的設(shè)計(jì)并進(jìn)行再一次的實(shí) 現(xiàn)
經(jīng)過再半天的努力,終于有了一個(gè)較為理想化的設(shè)計(jì),并完成了這個(gè)版本的實(shí)現(xiàn)
我們的選擇
對(duì)于彈出窗口這樣的功能,我們?cè)赟ilverlight中是有多種選擇的,在介紹我的作品之前,我們先來看 一下各種選擇的優(yōu)點(diǎn)和缺點(diǎn)
選擇1:MessageBox
確實(shí)Silverlight中是有一個(gè)MesasgeBox的,和Winform中的一樣,調(diào)用MessageBox.Show即可,但其也 存在著不少問題,當(dāng)然在這之前我們要先向好的一方面看
優(yōu)點(diǎn):MessageBox是同步的,即Show方法調(diào)用后可以直接取得返回值,同步編程在簡(jiǎn)單性上相比異步 編程有著非常大的優(yōu)勢(shì),因此確實(shí)可以作為一個(gè)好的選擇
缺點(diǎn):知道為什么各JS框架都要出個(gè)MessageBox么,就是因?yàn)閍lert這東西實(shí)在太難看了,而現(xiàn)在我們 面對(duì)著更為絢麗的Silverlight應(yīng)用,在賞心悅目地享受著的同時(shí),難道要時(shí)不時(shí)看到一個(gè)和alert窗口一 模一樣的家伙彈出又消失?
選擇2:Popup
Popup是Silverlight基礎(chǔ)類庫提供的一個(gè)控件,可以直接完成彈出的功能
優(yōu)點(diǎn):操作簡(jiǎn)單,可以用Xaml表述,封裝了彈出的功能,樣式可自定義,作為官方的解決方案甚為強(qiáng) 大
缺點(diǎn):據(jù)前輩說,Popup中包含有DataGrid之類的復(fù)雜控件的時(shí)候,會(huì)有Bug出現(xiàn),這也是需要我去完 全做一個(gè)彈出窗口出來的主要原因……
我的作品—PopupBox
我沒有辦法稱之為MessageBox,因?yàn)榛A(chǔ)類庫中有這東西
我也沒辦法稱之為Popup,因?yàn)榛A(chǔ)類庫中也有這東西
我可不想自己的作品在出現(xiàn)之初就與基礎(chǔ)類庫有著沖突,要求調(diào)用者必須使用全局命名空間引用,更 不想借用官方的名字給人產(chǎn)生混淆的感覺
作為一個(gè)作品的展示,先來看看這東西是怎么使用的。事實(shí)上這并不是一個(gè)控件,而是一個(gè)類,因此 你不能使用Xaml聲明他,作出這種決定的原因,一是我對(duì)Xaml只是掌握,并不熟悉,因此如果要做到使用 Xaml進(jìn)行聲明,可能至今都看不到這家伙的影子,其次是因?yàn)閺棾龃翱谕峭ㄟ^編程來動(dòng)態(tài)確定其內(nèi)容 并控制是否彈出的,因此將之作為一個(gè)類來使用也不會(huì)產(chǎn)生太大的麻煩
為了使用我們的彈出窗口,首先需要獲取一個(gè)稱為PopupService的對(duì)象,其掌管著一切彈出之物,你 不能顯式地通過new來構(gòu)造一個(gè)PopupService,而必須通過工廠方式獲取這個(gè)對(duì)象
PopupService service = PopupService.GetServiceFor(LayoutRoot);
隨后,我們可以使用多種重載,從PopupService中通過調(diào)用GetBoxPage來獲取彈出窗口的實(shí)例,其第 一個(gè)參數(shù)是顯示在彈出窗口中的控件,類型為FrameworkElement,第二個(gè)參數(shù)為窗口的標(biāo)題,后面的參數(shù) 控制著諸如是否可以拖動(dòng),是否顯示關(guān)閉圖標(biāo)等功能,調(diào)用如下
BoxPage box = service.GetBoxPage(
new MyControl(), //顯示的控件
Title.Text, //標(biāo)題
true, //是否可以拖動(dòng)
true //是否顯示關(guān)閉圖標(biāo)
);
你可以給BoxPage加上出現(xiàn)和消失時(shí)的特效,現(xiàn)有支持的特效有淡入、縮放以及無特效,當(dāng)然從設(shè)計(jì)上 可以非常輕松地對(duì)其進(jìn)行擴(kuò)展
box.Effect = Effect.Fade(box);
BoxPage擁有ShowComplete和CloseComplete事件,你可以通過注冊(cè)這些事件來做一些操作
box.ShowComplete += new EventHandler(Box_ShowComplete);
box.CloseComplete += new EventHandler(Box_CloseComplete);
最后調(diào)用Show方法彈出窗口,當(dāng)然也可以調(diào)用ShowAsModal方法來彈出一個(gè)模式窗口,所謂模式窗口就 是在彈出后會(huì)遮住下面所有的控件
box.Show();
box.ShowAsModal();
如果你覺得這樣的使用還算簡(jiǎn)單的話,那么我想我已經(jīng)成功了一半,當(dāng)然我們還有另一個(gè)控件,你可 以通過調(diào)用PopupService的GetMessagePage方法來獲取一個(gè)消息對(duì)話框,這是一個(gè)只用來顯示消息的不可 以自定義控件作為內(nèi)容的簡(jiǎn)單的對(duì)話框,在此放上兩張圖先展示一下效果
在展示以前,我還是想再三聲明,我的美工不是一般地差,因此對(duì)話框的樣式極為難看,請(qǐng)給我時(shí)間 去改進(jìn)樣式,謝謝……
左邊的是彈出窗口,右邊的是消息窗口
這個(gè)版本相比上一個(gè)版本的改進(jìn)
當(dāng)然上一個(gè)版本大家是沒有見過的,也永遠(yuǎn)不會(huì)見到,但作為對(duì)自己的負(fù)責(zé),我還是記錄一下這個(gè)版 本的改進(jìn),并且在此之間應(yīng)當(dāng)也能略窺此彈出窗口的功能
1.解決多個(gè)彈出窗口時(shí)遮罩層重復(fù)問題,現(xiàn)在多個(gè)彈出窗口將共用一個(gè)遮罩層
2.解決多個(gè)彈出窗口中有一個(gè)窗口為模式對(duì)話框的情況下,關(guān)閉此模式對(duì)話框?qū)⒉粫?huì)取消模式遮罩層 的問題
3.解決多個(gè)彈出窗口的情況下,點(diǎn)擊后臺(tái)窗口將其置于最上層的問題
后續(xù)版本將要出現(xiàn)的改進(jìn)
也許是下一個(gè)版本,也許是下n個(gè)版本,但是這些改進(jìn)已經(jīng)列入了計(jì)劃,總有一天他們會(huì)得到實(shí)現(xiàn)
1.多國語言化,主要是按鈕的文字
2.提供更多的樣式自定義功能
3.優(yōu)化PopupService的存儲(chǔ),將已經(jīng)無用的PopupService(即不再管理任何彈出窗)及時(shí)從緩存中清 除
4.BoxPage加上Border
5.當(dāng)前窗口彈出均在遮罩層的中間,改進(jìn)為可以指定窗口彈出時(shí)相對(duì)遮罩層的位置
6.如果彈出窗口的位置已經(jīng)有其他窗口的話,將窗口進(jìn)行一定量的偏移以保證不會(huì)完全擋住原有窗口
7.彈出窗口在拖動(dòng)的時(shí)候可以移出其遮罩層的范圍,最好可以控制遮罩層的大小且不允許彈出窗口隨 意移動(dòng),這樣可以將彈出窗口的可移動(dòng)范圍控制在一個(gè)區(qū)域之內(nèi)
已知的Bug
當(dāng)然我只是一只菜鳥,出來的東西必定有著問題,在此是至今發(fā)現(xiàn)的問題,也希望大家多多提供 Bug
1.當(dāng)在BoxPage中加載圖片時(shí),使用相對(duì)路徑將造成讀取類庫的相對(duì)路徑的圖片,產(chǎn)生圖片讀取錯(cuò)誤, 不知如何才能設(shè)置為去讀取當(dāng)前運(yùn)行項(xiàng)目的相對(duì)路徑
2.MessagePage和BoxPage中依舊存在部分相似、相同代碼,無法完全抽象分離,需要考慮優(yōu)化設(shè)計(jì)
3.MessagePage中的內(nèi)容為一定數(shù)量并且沒有空格的英文字符串時(shí),會(huì)產(chǎn)生最后一個(gè)字符換行的問題
4.使用漸隱特效時(shí),因?yàn)榇翱谙в袝r(shí)間,所以可以多次點(diǎn)擊MessagePage上的不同按鈕,但結(jié)果以最 后一次點(diǎn)擊的按鈕為準(zhǔn),應(yīng)當(dāng)修正為后續(xù)按鈕的點(diǎn)擊都無效
5.無數(shù)未知的問題和BUG……
設(shè)計(jì)及實(shí)現(xiàn)的介紹
寫到這里的時(shí)候我突然發(fā)現(xiàn)自己有點(diǎn)累了,雖然這是最重要的內(nèi)容,但是老媽難得來上?次,現(xiàn)在 正在旁邊,實(shí)在沒有什么心情繼續(xù),因此請(qǐng)?jiān)试S我將這“精彩”的重頭戲留到下一篇
源碼分享
以下是本作品的源碼地址,對(duì)于沒有Silverlight開發(fā)環(huán)境的同學(xué),就不要指望去打開項(xiàng)目了,但是 SilverlightApplication1\debug\bin\TestPage.htm依舊是可以運(yùn)行的,相信你已經(jīng)安裝了Silverlight Runtime,當(dāng)然沒有安裝你也會(huì)被微軟要求安裝的~~
這里是展示頁面的一個(gè)截圖
再次聲明,我的美工非常差,因此界面非常簡(jiǎn)單,我想點(diǎn)一下按鈕這事大家都會(huì)用,所以我就不對(duì)這 個(gè)界面多作解釋了
本文配套源碼