2012年7月13日 星期五

GridView中和「刪除」事件有關的事件常式

和刪除的事件常式有GridView.RowDeleting 事件和GridView.RowDeleted事件。關聯著不同的事件常式,我們可以利用事件順序中提供的事件常式來加載一些自已設計的程序。

先了解事件發生的順序,從字面上翻譯的話不難理解。

-ing 現在進行式,正在發生的事件(但還沒發生)
-ed 過去式,已經發生的事件

所以GridView刪除資料的事件順序應該是:
按一下GridView的刪除按鈕→(GridView的RowDeleting 事件)→刪除資料列→(GridView的RowDeleted事件)。

上面的順序中,括號( )內是可有可無,所以我們可以用既有的事件常式,自已在一連串的事件過程,撰寫自已的程式碼,以下是測試網頁,當按下刪除會出現」你沒有權限刪除資料」的文字,刪除完資料會顯示「刪除成功」文字。

◎以上程式範例AspNet43_1.aspx,如在頁框下不能操作,請開新視窗操作
◎如果有問題歡迎您提出,dnowba很需要有人和我一起討論


首先我們先設計頁面:

在頁面上加入GridView控制項。並設定資料來源,記得「進階」產生INSERT 、UPDATE、DELETE 陳述式。
image

GridView 上啟用刪除功能
image

從控制項的屬性視窗中,可以檢視GridView有哪些事件,每個事件都會引發事件常式,若要自已撰寫的話,在上頭點二下就會進入程式設計頁。後面就用範例來說說和刪除有關的二個事件:GridView.RowDeleting 和GridView.RowDeleted
image


為GridView.RowDeleting 和GridView.RowDeleted撰寫程式

    Protected Sub GridView1_RowDeleting(sender As Object, e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
        Dim cell As TableCell
        cell = Me.GridView1.Rows(e.RowIndex).Cells(3)
        ' 不可以用 If cell.Text = "" Then
        If cell.Text = " " Then
            Me.Label1.Text = ""
        Else
            ' e代表GridViewDeleteEventArgs,意指「提供 RowDeleting 事件的資料」
            ' e.Cancel,就是取消DeleteEvent(刪除事件)
            e.Cancel = True

            ' e.RowIndex 是由0算起,0=第1列…5=第6列,所以這邊+1
            Me.Label1.Text = "你沒有權限刪除第" & e.RowIndex + 1 & "列"

        End If
    End Sub

    Protected Sub GridView1_RowDeleted(sender As Object, e As System.Web.UI.WebControls.GridViewDeletedEventArgs) Handles GridView1.RowDeleted
        ' 使用GridViewDeletedEventArgs類別下的Exception 屬性來判斷例外(刪除不成功)狀況
        If e.Exception Is Nothing Then
            ' 使用GridViewDeletedEventArgs類別下的AffectedRows取得刪除作業所影響的資料列數目來當判斷依據,刪除成功資料庫會擲回刪除了一筆資料列的訊息
            If e.AffectedRows = 1 Then
                Me.Label2.Text = "刪除成功"
            Else
                Me.Label2.Text = "在刪除過程中遇到錯誤"
            End If
        Else
            Me.Label2.Text = "在刪除過程中遇到錯誤"
            ' 使用GridViewDeletedEventArgs類別下的ExceptionHandled屬性表示例外狀況已處理
            e.ExceptionHandled = True
        End If
    End Sub

程式碼中比較有趣的是,行4的 If cell.Text = " "
IE 7以前,TableCell 產生出HTML的TD 時,若 TD 中沒有任何資料,TD周圍的框線會不顯示 (就好像沒有<td>一樣),如下圖
image

所以 TableCell 內的資料若為空字串時,GridView會強制輸出『&nbsp;』,此為一個空白字元,使 Cell 的框線可以呈現。
這是當時 IE 瀏覽器的問題,後來的IE就解決這個問題,資料就算是空白也會顯示欄位旁的框線了。不過GridView的TABLE產生目前還是會輸出『&nbsp;』
可以在這個demo 的第一筆資料看看,我故意不填 title 欄位的資料,請用ie瀏覽器檢視原始檔,看看這欄是不是 <td>&nbsp;</td>
所以判斷式不能用 If cell.Text = "” 或是 If cell.Text = nothing
但你輸出cell.text的時候當然還是看不到東西,以為是空白或是沒資料,但其實是因為&nbsp; 本來在瀏覽器上就是顯示就是空白的 (不過會多一個半形的字符,反白可以看到)

所以也可以取得 TableCell.Text 時,可以把 『&nbsp;』取代為空字串
Strings.Replace(TableCell.Text, "&nbsp;", "")


關於ASP.NET的事件驅動

以我目前的能力,也許我自已不可能寫一個新的控制項
所以這些介紹事件和委派的內容可能也不需要懂
但是我真的想理解,我在控制項上點了二下是在做什麼?這些自動生成的程式碼有什麼意義?所以有了以下內容,以我的理解能力,就只能這樣了。

◎先看Button的click事件


拉一個Button控制項到畫面上,在Button上點二下,會code自動生成事件程序
Protected Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click

Protected Sub Button1_Click
宣告 程序 名為Button1_Click(可自訂)

sender As Object
事件傳送者,傳遞sender裡參數值,參數指出是哪個物件引發的
(如本例是Button1控制項的click行為引發的 )

e As System.EventArgs
事件處理資料,使用 e 作參數值,類型是System.EventArgs,可以使用System.EventArgs類別下的設好的參照資料

Handles Button1.Click
控制項Button1 的 Click行為引發事件處理的常式
(控制項有自已行為,每種行為就是一個事件)

(sender As Object, e As System.EventArgs) 可以說是.NET 事件驅動的精華,在.NET的Framework裡面,事件是以委派模型(delegate model)為基礎 ,透過事件委派的二個參數來傳遞訊息。

◎再看刪除GridView的deleting事件


Protected Sub GridView1_RowDeleting(sender As Object, e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting

比較一下,真的差不多,我們看到的都是提供Object類型的參數sender和一個XXXEventArgs類別的參數e (像GridView裡的GridViewDeleteEventArgs)
XXXEventArgs 是一個繼承自System.EventArgs的類別,裡頭設計了針對xxx控制項的參數字典供調用。

一般來說,一般事件不會產生事件資料,以Button的click事件通常只是處理宣告下的程序,所以設計件,事件處理常式就是直接使用System.EventArgs類別,類別下的成員只有empty, 也就是初始化 EventArgs 類別的新執行個體。所以按完按鈕,執行完程序後就把事件給初始化,除非再按一次才回重新執行程序。從下圖我們可以看出來,我們用在程序下打「e.」叫出 Intellisense介面,e的對應的欄位只有一個(圖示為藍色方塊的),就是empty。
image

而GridView的GridViewDeleteEventArgs,從字面上可以看出來這個類別是處理GridView刪除事件的參數。裡頭的成員就有可調用的屬性了(圖示有一隻手的),GridViewDeleteEventArgs是繼承自System.EventArgs而來的衍生類別…(雖然命名空間不大一樣,不過是透過public宣告,互相可以繼承來繼承去的)
image


這種設計我覺得可以最大限度的讓所有事件處理過程有相似的簽名
比如若事件設計成這樣:

Event DnowEvent (sender As Object, index As Integer, product As String)

當需求改變,需要再多傳遞一個Decimal類型的price參數時,系統中所有響應這個事件的過程都需要增加一個參數,那麼就會大亂了。

如果將所有要傳遞的數據封裝在一個繼承自EventArgs的類型——DnowEventArgs中,代碼就能寫成這樣:

Event DnowEvent (sender As Object, e As DnowEventArgs)

那麼當需求改變的時候,只需要修改一下​​DnowEventArgs的成員即可

多數情況下,事件是不需要傳遞參數的。因此用系統定義的System.EventHandler是非常好的選擇,就算是要進行參數回傳,EventArgs也能夠滿足大部分設計的需要

 

◎.NET的事件處理模型

在我自已能理解的範圍寫下來的…事件處理機制的幾個重點

Events (事件)
當browser 做了什麼事 (按下按鈕、下拉選單),如果希望 server 端 (或是 瀏覽器) 的程式對應狀況做出某些處理,那麼這一連串的訊息傳遞就是事件,事件是通知應用程式有事情發生的信號。不過設計宣告了一個事件,這個事件要用什麼方式回應呢?

Events Handler (事件處理常式)
當按下按鈕,程式端應該要有一段程式來回應brower按下按鈕的狀況,像這樣的因應事件叫做事件處理常式。而要把「事件」和「事件處理常式」互相繫結的話,事件處理常式就需要唯一識別,然後用關鍵字「Handles」來建立二者的關聯。所以當使用者按下按鈕,就引發click事件,然後透過handles來呼叫處理的常式。

補充:我在「讓不同個控制項呼叫同一事件(以Button為例)」便有實作,讓不同的Button的Click事件使用同一個事件處理常式來回應browser。

.NET 是一種事件驅動,中間藏了很多事件委派,將回傳的事件分別交待給微軟建立的不同的類別來處理,整個程式看不到委派的程序,我想是交給某個機制去處理了,這個機制是什麼我也不知道。反正就是透過 sender 和 e 來當訊息交換的參數。總之重點就是一個:

每個事件裡的的 e 參數,是不一樣的意思

(以下也是自已理解畫的圖,理解錯誤請指正)
整個事件就是由二個物件「事件接收者」和「事件傳送者」交換訊息
image

整個應用程序就好像一根一根的水管(pipe),每次的一個事件都像水流(flow)…水流各自依照不同的簽章(sign) 去找到(refer) 被引流到不同的水管。下圖是參考GUI 的事件處理模型畫的,我想WEB應用程序「應該」差不多。
image

主要參考:
MSDN 有關「處理和引發事件」下的章節,目錄為
http://msdn.microsoft.com/zh-tw/library/edzehd2t

維基上解釋「事件驅動」(Event-driven programming)
http://zh.wikipedia.org/wiki/%E4%BA%8B%E4%BB%B6%E9%A9%85%E5%8B%95%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88

沒有留言:

張貼留言

Related Posts Plugin for WordPress, Blogger...
// Dnow Function