2009年6月23日 星期二

RunPC172期:Gadget小工具設計實務:以台灣高鐵乘車資訊全方位指南為例(下)

ASP.NET 2.0 CallBack機制撰寫AJAX程式

ASP.NET 2.0中提供有別於PostBackCallBack功能,它讓我們可以在ASP.NET 2.0上撰寫AJAX程式,要在ASP.NET 2.0上撰寫CallBack程式,要先了解 ICallbackEventHandler這個Interface,該Interface有兩個方法:GetCallbackResult ()RaiseCallbackEvent(ByVal eventArgument As String),所以我們可介由繼承ICallbackEventHandler這個Interface並且實作這兩個方法,來完成CallBack機制撰寫AJAX程式,以下是我們Sever-Side的完整程式碼:

 

程式八:小工具CallBack程式Sever-Side程式碼

Partial Class ThsrcDB

    Inherits System.Web.UI.Page

    Implements System.Web.UI.ICallbackEventHandler

    Dim rtnTime As String  '要回傳的時刻字串

    Dim rtnPrice As String  '要回傳的票價字串

 

    Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult

        Return rtnTime & "^" & rtnPrice'時刻字串與票價字串由『^』分隔,查詢後傳回Client-Side

    End Function

'eventArgumentClient-Side傳入

    Public Sub RaiseCallbackEvent(ByVal eventArgument As String) Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent

        Dim A() As String

        A = eventArgument.Split("^")

        Dim SSiteID As String = A(0)

        Dim ESiteID As String = A(1)

        Dim SSiteTime As String = A(2)

        Dim ESiteTime As String = A(3)

        Dim SEType As String = A(4)

        rtnTime = GetTimeData(SSiteID, ESiteID, SSiteTime, ESiteTime, SEType)

        rtnPrice = GetPriceData(SSiteID, ESiteID)

    End Sub

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim cbReference As String

        '建立 Call back程式碼-指定回傳函式為 ReceiveServerData

        Dim strArg As String = ""

        strArg &= "document.all." + ddlTimeFrom.ClientID + ".value +'^'"

        strArg &= "+document.all." + ddlTimeTo.ClientID + ".value +'^'"

        strArg &= "+document.all." + ddlSTime.ClientID + ".value +'^'"

        strArg &= "+document.all." + ddlETime.ClientID + ".value +'^'"

        strArg &= "+document.all." + ddlSE.ClientID + ".value"

        cbReference = Page.ClientScript.GetCallbackEventReference(Me, strArg, "ReceiveServerData", "")

        '註冊

        btnSearch.Attributes("onclick") = cbReference

 

        '設計一個函式(名稱為ReceiveServerData),接收 Server Call Back 回來的值

        Dim ReceiverScript As String = ""

        ReceiverScript += vbCrLf + "<script>"

        ReceiverScript += vbCrLf + " function ReceiveServerData(DataFromServer)"

        ReceiverScript += vbCrLf + "{"

        ReceiverScript += vbCrLf + "var a=DataFromServer.split('^');"

        ReceiverScript += vbCrLf + "document.all.divTime.innerHTML=a[0];"

        ReceiverScript += vbCrLf + "document.all.divPrice.innerHTML=a[1];"

        ReceiverScript += vbCrLf + "document.all.fdsResult.style.display ='block';"

        ReceiverScript += vbCrLf + "document.all.imglodaing.style.display ='none';"

        ReceiverScript += vbCrLf + "}"

        ReceiverScript += vbCrLf + "</script>"

        '在頁面上註冊(寫入)這個函式

        Page.ClientScript.RegisterClientScriptBlock(GetType(String), "ReceiverScript", ReceiverScript)

    End Sub

 

    Function GetTimeData(ByVal SSiteID As String, ByVal ESiteID As String, ByVal SSiteTime As String, ByVal ESiteTime As String, ByVal SEType As String) As String

        Dim sp As New StringBuilder

        Dim dv As DataView

        With Me.sqldsTime

            .SelectParameters(0).DefaultValue = SSiteID

            .SelectParameters(1).DefaultValue = ESiteID

            .SelectParameters(2).DefaultValue = SSiteTime

            .SelectParameters(3).DefaultValue = ESiteTime

            .SelectParameters(4).DefaultValue = SEType

            dv = .Select(New DataSourceSelectArguments)

        End With

 

        For Each dr As DataRowView In dv

            If CType(dr(2), String) <> "" Then

                sp.Append(String.Format("<span style='color: red' alt='車次:{0}({1}行駛)' altbg='red' altcolor='yellow' altborder=yellow>{2}</span>", dr(0), dr(2), dr(1)))

            Else

                sp.Append(String.Format("<span alt='車次:{0}'>{1}</span>", dr(0), dr(1)))

            End If

        Next

        If sp.ToString = "" Then

            Return ""

        Else

            Return sp.ToString.Substring(0, sp.ToString.Length - 1)

        End If

    End Function

 

    Function GetPriceData(ByVal SSiteID As String, ByVal ESiteID As String) As String

        Dim sp As New StringBuilder

        Dim dv As DataView

 

        With Me.sqldsPrice

            .SelectParameters(0).DefaultValue = SSiteID

            .SelectParameters(1).DefaultValue = ESiteID

            dv = .Select(New DataSourceSelectArguments)

        End With

 

        For Each dr As DataRowView In dv

            sp.Append(String.Format("●【{0}:{1}<br>", GetTypeStr(dr(0)), CType(dr(1), String).PadLeft(10, " ")))

        Next

        If sp.ToString = "" Then

            Return ""

        Else

            Return sp.ToString.Substring(0, sp.ToString.Length - 4)

        End If

    End Function

 

    Function GetTypeStr(ByVal str As String) As String

        Dim RTN As String = ""

        Select Case str

            Case "0"

                RTN = "標準車廂-全票"

            Case "1"

                RTN = "商務車廂-全票"

            Case "2"

                RTN = "標準車廂-優待票"

            Case "3"

                RTN = "商務車廂-優待票"

            Case "4"

                RTN = "自由座-全票"

            Case "5"

                RTN = "自由座-優待票"

            Case "6"

                RTN = "標準車廂-團體票"

            Case "7"

                RTN = "商務車廂-團體票"

        End Select

        Return RTN.PadRight(8, " ")

    End Function

 

End Class

運作流程如下:在Page_Load事件中指定會觸發CallBack物件與事件(btnSearch物件的onclick事件),且該CallBack會傳送什麼前端資訊(strArg)至伺服器端,同時指定伺服端執行完成後會呼叫前端ReceiveServerData函式;該函式為CallBack程式碼指定回傳函式,接收 Server Call Back 回來的值,且將該函式註冊寫入在前端頁面上,而程式碼中會將從伺服器端接收回來的DataFromServer參數分割再放入對應呈現時刻(divTime)與票價(divPrice)的物件中。

而實作ICallbackEventHandlerGetCallbackResult方法是伺服端傳給客戶端資料,它會對應至前面所述的ReceiveServerData函式中的DataFromServer參數;而實作ICallbackEventHandlerRaiseCallbackEvent方法,其中eventArgument是由客戶端傳入,亦就是前面所說的strArg參數,因為該客戶端傳入的參數只有一個,固我們利用組字串時加入『^』來分隔,在伺服端再以^來分割成各變數,再透過切割後的變數,傳入GetTimeDataGetPriceData兩個方法,分別呼叫GetTimeGetPrice預存程序來取得時刻與票價相關資料,整個完成後,即會觸發ICallbackEventHandlerGetCallbackResult方法將存放時刻rtnTime與票價rtnPrice的字串組合後傳至前端ReceiveServerData函式中的DataFromServer參數。

 

AJAX程式包裹成Web Gadget

至此我們完成小工具資料庫的設計、高鐵資料的取得、UrMap地圖的套用、AJAX程式的撰寫,它是個完整獨立的網頁小程式,在MicrosofWeb GadgetsGoogleUniversal Gadgets都提供單獨網頁嵌入Gadget小工具的方式,在實作MicrosofWeb Gadgets的包裹作法前,需先了解一個基本的Gadget包含下面4個檔案:

  1. Gadget Manifest(配置檔;附檔名:xml):必要檔案,其檔案採用XML結構的形式,檔案裡定義一些屬性與指定所參考的Gadget JavaScriptGadget Style Sheet和圖檔檔案的位置。
  2. Gadget JavaScript(邏輯程式檔;附檔名:js):必要檔案,這個檔案包含一些邏輯程式碼、屬性與定義 Gadget該如何動作。
  3. Gadget Style Sheet(樣式表;附檔名:css):非必要檔案,該CSS檔案為該Gadget的樣式檔,設定它如何呈現外觀與介面。
  4. Gadget 圖檔(附檔名:jpgpng):非必要檔案,指定該Gadget的圖示。

 

本範例的Gadget Manifest配置檔如下,指定它的標題、說明與所參考的Gadget JavaScript(gadget.js)和它的圖示(pic.jpg),要特別注意的是binding:type要與Gadget JavaScript內的建構元件對應起來。

程式九:小工具的Gadget Manifest(gadget.xml)

<?xml version="1.0" encoding="UTF-8"?>

<rss version="2.0" xmlns:binding="http://www.live.com">

     <channel>

           <title>台灣高鐵乘車資訊全方位指南</title>

           <description>提供台灣高鐵乘車資訊全方位指南,除可查各站點之票價、時間、轉乘、訂票資訊與週遭景點資訊外且結合UrMap地圖可友善設定啟到站與查啟到站時間。</description>

           <language>zh-tw</language>

           <binding:type>MLChen.Spaces.Gadget.TaiwanThsrc</binding:type>

           <item>

                <link>gadget.js</link>

           </item>

           <icons>

                <icon height="32" width="32">pic.jpg</icon>

           </icons>

     </channel>

</rss>

至於Gadget JavaScript程式碼如下,除了名稱空間與建構式等要特別注意外,在單獨網頁嵌入Gadget小工具中僅要將url網址改成您所要嵌入Gadget小工具的單獨網頁即可,而其它只要將所屬的Gadget檔案,本例中的gadget.xmlgadget.jspic.jpg壓成一個壓縮檔zip,接著即可至http://gallery.live.com,將辛苦製作的小工具上傳至 Windows Live Gallery透過Gadget的方式分享給大家。

程式十:小工具的Gadget JavaScript

    // 註冊小工具的名稱空間 (namespace)

    registerNamespace("MLChen.Spaces.Gadget");

 

    //// 定義此小工具的建構元 。

    //(名稱必須相同於清單檔(XML)的設定)

    MLChen.Spaces.Gadget.TaiwanThsrc = function(p_elSource, p_args, p_namespace) {

    // 做任何事之前必須先呼叫 initializeBase 函式。

     MLChen.Spaces.Gadget.TaiwanThsrc.initializeBase(this, arguments);

 

    // 設定一些私有成員變數 (private member variables)

     var m_el = p_elSource;

     var m_module = p_args.module;

      

     /****************************************

     **          initialize Method (初始化方法)                 

     ****************************************/

     // 當你的物件開始執行時,這個 initialize 函式會永遠立即被呼叫。

     this.initialize = function(p_objScope)                       

     {                                                                       

           // 總是先呼叫 Base 物件的 initialize 函式。   

           MLChen.Spaces.Gadget.TaiwanThsrc.getBaseMethod(this, "initialize", "Web.Bindings.Base").call(this, p_objScope);

                                                                                                                  

           //  小工具背景透明化 。                                               

           if (window.parent != window.self) {                                         

                document.body.style.backgroundColor = "transparent";

           }                                                                                

          

           var url ="http://www.abc.com.tw/Thsrc.aspx";

           m_el.innerHTML = "<iframe src=\"" + url + "\" frameborder=\"0\" scrolling=\"auto\" height=\"500\" width=\"466\"/>"

          

     };                                                                       

     MLChen.Spaces.Gadget.TaiwanThsrc.registerBaseMethod(this, "initialize");

      

     

     /****************************************      

     **           dispose Method (解除方法)                    

     ****************************************/

     this.dispose = function(p_blnUnload) {      

           // 清除所有的成員變數                          

           m_this = null;                         

           m_el = null;                         

           m_module = null;                         

                                               

           // 最後總是呼叫 base 物件的 dispose 函式

           MLChen.Spaces.Gadget.TaiwanThsrc.getBaseMethod(this, "dispose", "Web.Bindings.Base").call(this, p_blnUnload);

     };                                                                             

         MLChen.Spaces.Gadget.TaiwanThsrc.registerBaseMethod(this, "dispose");

    };

    MLChen.Spaces.Gadget.TaiwanThsrc.registerClass("MLChen.Spaces.Gadget.TaiwanThsrc", "Web.Bindings.Base");

 

總結:

網路邁入Web 2.0的時代,有別於Web 1.0網友僅能單項接收資訊或服務,此處我們借由MicrosoftGoogle提供的平台,依各平台規格撰寫服務或小工具程式,即可提供我們開發的服務給其它人使用,而該台灣高鐵乘車資訊全方位指南小工具又以混搭(mashup)的方式,使用到地圖供應商UrMap提供的地圖服務,且查詢方式又以AJAX方式呈現,豐富使用者體驗,故我們慢慢可以了解Yahoo!奇摩總經理鄒開蓮表示:『小工具正是Web 2.0精神的展現』這句話的意思。

這篇Gadget小工具設計實務是以筆者參加台灣微軟所主辦、捨得資訊協辦的2007 Windows Live Spaces Gadgets部落格小工具設計大賽的佳作作品,唯筆者在看這場競賽時,實覺十分可惜,在一再強調使用者體驗(User Experience)Gadget小工具上,反諷的是協辦單位所開發舉辦Gadget競賽活動平台竟沒有讓筆者有絲毫感到使用者體驗的部分,光作品需上傳至Windows Live Gallery外還要再上傳一次至競賽網站這一點筆者就十分不能理解,更不用說該競賽平台竟有一堆Bug,反應協辦單位後亦沒有多大改善,或許這只是個小活動、小競賽,無須太過認真,但如此就會失去辦這活動的意義了。

 

參考資料:

Live.com Windows Live Spaces 網頁小工具 Gadget 開發手冊 (上)

Live.com Windows Live Spaces 網頁小工具 Gadget 開發手冊 (中)

Live.com Windows Live Spaces 網頁小工具 Gadget 開發手冊 (下)

英文版 Web Gadget SDK 文件集

UrMap API v1.06 說明文件

台灣高鐵官方網站

相關連結:

台灣高鐵乘車資訊全方位指南Gadget小工具位址:http://gallery.live.com/LiveItemDetail.aspx?li=1cc833af-4048-4d25-aad5-2280948bfa59

台灣高鐵乘車資訊全方位指南Gadget小工具使用簡報:

http://cid-f315ca8945fc025a.skydrive.live.com/self.aspx/%e5%85%ac%e9%96%8b/TwThsrc.ppt

加入書籤: MyShare HemiDemi Baidu Google Bookmarks Yahoo! My Web PChome Del.icio.us Digg technorati furludn bookmark 其他更多書籤

BOOKS:New and Upcoming