在 .Net 上實現 Win Form 中 MessageBox 的確認視窗
這篇文章的起源來自於一個小小的需求,就是確認。
寫web form的人都知道,利用JavaScript可以在使用者送出資料之前彈出一對話視窗進行確認,
在點選”是”之後才會對網頁進行回傳資料。
但是,有沒有辦法做到像win form那樣子呢?
例如:
跟JavaScript最大的差異在於:
我希望按下送出之後,會先到server端的DB去尋找是否有相同的資料,
如果沒有,就新增;
反之,則彈出一個對話視窗提醒,
當我按下”是”的時候,server端就會執行我想要的工作。
這個看似如此簡單的動作讓我這新手可是吃足了苦頭,
後來在網路上找到了文章有類似的技術提出,
利用了hidden和PageMethod來實現,
不過這依然不是我想要的,
之後又看到對岸的網友也是相同的問題,
而且還引起了不少討論,
原因是有很多人有同樣的需求:
希望系統能先到server端先去執行一段工作之後,
再把下一步執行的決策權重新送回使用者手中,
例如:假設我需要增加一個原料編號,但是系統發現資料庫中已經有相同的號碼了,
於是詢問我是否要繼續新增,
接著我判斷:雖然料號相同,但是進貨日期不同,
所以這筆資料依然有存在的必要,必須增加到資料庫。
再舉一個例子:
公司的行政在幫新進同事建立檔案,
發現某位新進員工擁有兩個碩士學位,
於是逐一建立,但是當key in第二筆資料時,系統發現了有重複的學歷,
於是詢問是否繼續新增?
當然這時負責的key in的人就要有所處理了,
他必須判斷這是失誤、還是說真的有雙碩士、雙博士學歷。
上面講的功能有經驗的大大也許很早就做過了,
在AJAX環境底下透過某些ControlToolKit也可以完成,
之所以會想把這些記下來是因為小弟我自己基礎不好,
想要從CODE來了解dot net的運作過程,
太依賴套件會養成苟且的心理,
也沒有辦法呈現開發人員真正的核心價值,
想想看,如果隨便一個人靠著拖拉這些工具就可以”寫程式”,
那我們這麼努力是為了甚麼呢?
而所謂的套件、ToolKit,說穿了也是別人包裝好的程式碼,
假如你是老闆,
你會希望請的人是幫你開發套件,創造新的智慧財產,
還是說只是個會照本宣科、拉拉元件的傢伙?
(也不是說貶低拉元件的人…但是會寫網頁程式的人那麼多…想要好的offer,就必須有不同的思維)
扯遠了,
先來談談在對岸看到的三篇文章,
這個議題首先在Bēniaǒ的部落格中提到,
(http://www.cnblogs.com/beniao/archive/2009/09/15/1317317.html)
之後由代碼亂了和volnet以及其他網友一起將這架構建立起來,
(http://www.cnblogs.com/jintan/archive/2008/10/25/1319308.html)
(http://www.cnblogs.com/volnet/archive/2008/12/03/1319609.html)
以下我整理了幾個觀念是急著踏入dot net的朋友來不及建立的,
1. 大多數人認為MessageBox.Show這種使用方式是約定俗成的必然,就好比當年大家在寫第一隻程式的時候,會用各種不同的方法輸出「HelloWorld」一般,包含了使用MessageBox.Show。然而Web的發展相對於Win Form來說,算是晚起步很多,這造成當一個程式開發人員用JavaScript alert出「HelloWorld」時,也會覺得這是一種”必然”,就跟Win Form一樣。
2. 針對進入dot net的程式開發者,微軟包裝了一套平易近人工具,大幅的降低了開發網站所需的時間和精神。藉由這個包裝,微軟想要打造一個跟開發Win Form相似的環境,來讓有Win Form經驗的人可以快速上手。我們可以在這方面推崇微軟,如果不是他們努力,就不會有那麼多生動有趣的網站如雨後春筍般冒出來,但也因此養成了程式開發者的依賴性,甚至有時會搞不清Win Form和Web Form的差異。其實這也不能都怪微軟,因為Visual Studio幾乎是最好整合開發工具,不僅讓寫程式省去了許多麻煩,也讓「寫程式」這件事普遍了起來。
然而,進入門檻的降低不代表每個人都可以解決更難的問題,也因為要讓自己有所提升,我們不可能永遠只停留在拖曳元件的階段,當你覺得開發一個網站變得更快時,往往不是因為自己變得更厲害,而是因為微軟幫你想的更多,這也是微軟程式開發人員貶值這麼快的原因之一。
「你跑的快不是因為你天生過人,是因為這條路已經鋪好柏油了。」
「有天,當大家都在柏油路上面賽跑時,你要怎麼贏過人家呢?」
所以,我認為要讓自己有價值,除了拖曳元件之外,還必須從coding的工夫做起。
3. 從本質上來說,上網是client端發送HTTP Request給server端,然後server端送回資料給瀏覽器,最後斷開聯結。這邊要注意到關鍵點就是斷開的這個動作,在PostBack的架構中,程式開發者會將一些變數(或參數)儲存在頁面上,當form被傳回到server端的時候,server端就會根據那些變數來視情況是否需要執行畫面的更新。
那AJAX呢?AJAX透過非同步的更新機制向server送出要求,這個機制包含了XML檔案的交換,最初的需求是為了因應Outlook而發展的,但後來因為很多原因讓這個技術逐漸普及到Web上,這也應該算是無心插柳的一種結果吧。
那,要怎麼做呢?
來看一下傳統的confirm是在哪邊觸發的:
相信不用說大家也知道,confirm的出現是在送出Request之前。
接著來看我想要達成的功能:
有沒有發現,confirm是在資料庫搜尋完之後才出現的,
我在實作的過程中發現了幾個困難點,
1. 如何在AJAX的環境中,以C#呼叫JS產生confirm視窗?
2. 已經出現了confirm視窗,又要如何在按下”是”之後發送Request回server?
3. 送回去Request有沒有安全性的疑慮?
4. 傳值以及讓類似的副程式可以共用?
先要有個認知,
這個工作要在一次PostBack內完成是幾乎不可能,
因此我用了兩次PostBack來簡化這個流程,
幸好現在大家上網速度都有一定水準了,
多一次PostBack應該不會造成太大困擾…^^”
測試的方法是在頁面上放置一些元件,如下圖,
當使用者按下Button時,會先進行第一次PostBack,檢查TextBox中有沒有值,(步驟(1)(2))
(可以類比成檢查資料庫中是否有相同的資料)
要是有值(檢查出有相同的資料),以程式的方式呼叫JS confirm,(步驟(3))
If(confirm==Yes),去Trigger頁面上的LinkButton,進行第二次的PostBack,(步驟(4))
(LinkButton.Text = null, 避免誤按)
最後由LinkButton_Click的事件去將TextBox的值寫到Label。(步驟(5))
Button1_Click:檢查文字方塊,然後呼叫confirm的函式:
Confirm的副程式:呼叫的方法是利用ScriptManager在頁面上註冊JS碼,
當使用者按下”是”,用AJAX的__doPostBack引發第二次的回傳,
並可藉key來傳遞參數。
最後,進行第二次PostBack的LinkButton_Click事件中,
由 __EVENTARGUMENT 來參數來承接TextBox傳過來的值。
回到頁面上,
當你興高采烈的想要測試時,
畫面上卻出現了令你難以置信的錯誤:
原來問題是出現在微軟的安全性,
頁面的回傳不允許未經授權的回傳,導致EventValidation驗證失敗,
解決的辦法其中之一是按照提示,
將Page裡的EnableEventValidation設定為false就可以了。
但是,這畢竟是個不安全的方法,
有沒有安全點的做法呢?
也是有的,方法就是不用__doPostBack,
改成用JS來 ”Click” 頁面上的LinkButton。
首先,改寫呼叫confirm的函式,解除由 __EVENTARGUMENT 來傳遞值,
然後用 .click() 來觸發LinkButton:
傳值的部分,
有很多種方式,例如session,
不過這邊我就地取材,選擇用LinkButton的CommandArgument來傳:
最後,接收傳回來的值:
來看看結果吧~
成功的輸出文字了!!
而且不必擔心安全性的問題!!
你也可以加上一些安全性的判別,
以及用switch切換你要執行的副程式: