2012年7月14日 星期六

自行撰寫GridView的RowCommand處理常式

目前沒想到什麼應用範例,所以學習一下MSDN現有的範本改寫一下,範本實作的是,把GridView的資料列「加入到ListBox」或「從ListBox移除」

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


畫面設定:
加入一個GridView,完成和資料庫的資料繫結(要啟用進階功能)。
編輯資料行→加入TemplateField,.NET自動幫你在HTML上寫好<asp:TemplateField></asp:TemplateField>標記。(所以你對「按按按」很反感的話,也可以直接在GridView裡寫<asp:TemplateField></asp:TemplateField>的標記。不過在一般情況下不可以自已加特殊名稱的標記,比如把上面改成<asp:myField></asp:myField>,會顯示「未知的伺服器標記」的錯誤。反正GridView裡的東西是被包裝再包裝的,用的關鍵字就是不能亂改,不然都會發生識別錯誤。
image

再來在樣板的ItemTemplate加入二個按鈕,一個Button控制項作加入的功能,一個ListBox控制項作移除的功能
image

重點在這邊,設定Button按鈕的CommandName="Add" ,                          CommandArgument="<%# Container.DataItemIndex %>"
image

LinkButton也是類似的設定,CommandName="Delete" ,                            CommandArgument="<%# Container.DataItemIndex %>
image

CommandArgument="<%# Container.DataItemIndex %>若要用中文解釋的話,就是設定CommandArgument屬性和資料行索引(Container.DataItemIndex)繫結。這樣按鈕按下就可以透過 CommandArgument 間接得知我們按的是哪一資料列的按鈕。

這邊放二個不同的按鈕,目的只是要告訴大家…Button、LinkButton、ImageButton都有CommandName和CommandArgument 可以設定。


程式碼:

    Protected Sub GridView1_RowCommand(sender As Object, e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView1.RowCommand
        If e.CommandName = "Add" Then
            ' 設計一個add_item物件,屬性繼承ListItem,方便使用
            Dim add_item As New ListItem()

            ' 設定add_item的文字=GridView裡被點選的某個資料料的第三個欄位
            add_item.Text = Me.GridView1.Rows(CInt(e.CommandArgument)).Cells(2).Text

            ' 如果ListBox上不包含add_item這個項目的的話
            If Not Me.ListBox1.Items.Contains(add_item) Then

                '把add_item加入到ListBox裡
                Me.ListBox1.Items.Add(add_item)
            End If
        End If

        If e.CommandName = "Delete" Then
            Dim remove_item As New ListItem()
            remove_item.Text = Me.GridView1.Rows(CInt(e.CommandArgument)).Cells(2).Text
            If ListBox1.Items.Contains(remove_item) Then
                Me.ListBox1.Items.Remove(remove_item)
            End If
        End If
        '以上改寫自MSDN範例
        'http://msdn.microsoft.com/zh-tw/library/system.web.ui.webcontrols.gridview.rowcommand.aspx
        'If e.CommandName = "Add" Then
        '    Dim index As Integer = Convert.ToInt32(e.CommandArgument)
        '    Dim row As GridViewRow = Me.GridView1.Rows(index)
        '    Dim item As New ListItem()
        '    item.Text = Server.HtmlDecode(row.Cells(2).Text) & " " & _
        '    Server.HtmlDecode(row.Cells(3).Text)
        '    If Not Me.ListBox1.Items.Contains(item) Then
        '        Me.ListBox1.Items.Add(item)
        '    End If
        'End If
    End Sub

    Protected Sub GridView1_RowDeleting(sender As Object, e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
        If Me.GridView1.Rows(e.RowIndex).Cells(1).Text <> "&nbsp;" Then
            e.Cancel = True
            Me.Label1.Text = "大膽,你用了.NET 在CommandName預設的保留字…直呼名諱的結果就是滿門抄斬,還好我擋住了,不然資料列就被你砍掉了。"
        End If
    End Sub

程式碼解釋:

◎ 只要是GridView裡頭的按鈕都可以 引發RowCommand 事件。我們可以把程式範例中對CommandName的判斷句拿掉 (行2),這樣,不管是點選哪個按鈕都會啟動事件。換句話說,CommandName在這裡的功能就是一種辨識的作用。當然你也可以用別的方式識別,比如說用Button.Text。

◎ 行18 Dim remove_item As New ListItem(),定義為ListItem而不用ListBox當繼承的容器,這樣的話,不只是ListBox適用這個方式,像DropDownList、CheckBoxList都可以用。

◎行38-43,這是重點,因為我們在設計「移除」功能時用了 .NET 在 CommandName 的內建字「Delete」,所以當按下按鈕時,網頁會邊進行我們給的RowCommand事件處理常式,一邊引發RowDeleting事件按照 .NET 的設計去做資料列刪除的動作,為了讓範例在部落格上存活,我就在RowDeleting 裡取消刪除。大家實作時可以把這段刪掉試試看動用CommandName 的內建字的下場是什麼。而Button1的CommandName「Add」其實也是保留字,但它是作用在DetailsView身上的,所以這邊拿來用是沒關係的。


從MSDN提供的範例來看,我想RowCommand事件在GridView進行刪除、新增資料時…應該多多少少有一些關聯。

例如:GridView整個刪除的流程是:

按一下GridView的刪除按鈕 → (GridView的RowDeleting 事件) →
刪除資料列 → (GridView的RowDeleted事件)。

前一篇文章 GridView中和「刪除」事件有關的事件常式 已經交待了在 RowDeleting 事件與RowDeleted事件中,利用二個重要的參數來撰寫常式。

這篇文章的重點就放在 按GridView的刪除按鈕→刪除資料列,控制項和資料庫是如何完成聯繫並達成工作的。

我們在頁面上加入GridView控制項,並繫結資料,整個都是交給ADO.NET來自動生成。當完成資料的綁定,HTML 碼上其實就幫我們寫好了和資料庫繫結的要項了。如圖,紅色的框線是與資料庫連結的資料,底下有DeleteCommand、InsertComman、SelectCommand、UpdateCommand,後面接寫的是資料庫使用的陳述式。
image

在browser端,當GridView的某個按鈕按下去的時候,要怎麼讓系統知道現在按的是要呼叫資料庫的Delete 陳述式還是Update陳述式呢?這就要使用Button的CommandName和CommandArgument屬性了,如果有興趣請看
活用Button 控制項:CommandName、CommandArgument屬性介紹

但判別哪個CommandName用哪個CommandArgument 的判斷程式要寫在哪?我想「應該」就是寫在RowCommand事件的處理常式底下。

上面只是個臆測,從使用Button控制項得來的經驗來推測,但是只能說是猜測,因為我們在ADO.NET幫我們和資料庫聯繫完畢後,ASP.NET底下的RowCommand事件下也沒有自已生成像 if CommandName = “Update” then CommandArgumet 的常式。不過也不是子虛烏有,在MSDN裡的GridView.RowCommand 事件寫著

按一下 GridView 控制項中的按鈕時,會引發 RowCommand 事件。 這可讓您在每次發生這個事件時,提供執行自訂常式的事件處理方法。GridView 控制項內的按鈕也可以叫用此控制項的某些內建功能。 若要執行這些作業的其中一個,請將按鈕的 CommandName 屬性設為「Cancel / Delete / Edit / Page / Select / Sort / Update」其中一個值。

所謂的內建功能,就是那幾個Command的值,我們在使用CommandField 的編輯按鈕、刪除按鈕…時,可以把這個欄位轉成TemplateField,然後去看看這些按鈕原來的樣子 (註:不轉成樣板的話看不到)

前面提到,不把CommandField轉成TemplateField是看不到的CommandName的
在GridView上「編輯資料行」中,加入CommandField (或是CommandField下的子項目),右側的屬性也是針對整個欄位(Field)提供外觀、行為…等設定。
image

在GridView的HTML上也只會呈現CommandField,標記裡找不到CommandName的蹤跡。
image

只有把欄位轉成Template 的時候,才能讓這些Button原形畢露,Button標記下也才可以看得到CommandName
image

如上圖,更新按鈕的CommandName 就是內建的字「Update」,對應的是ADO.NET的UpdateCommand進而去使用資料庫的Update陳述式;而編輯按鈕的CommandName 就是內建的字「Edit」,不過並沒有對應到EditCommand,和資料庫沒有什麼關聯,諸如此類…

由MSDN的資料、以及從實作GridView、ListView等控制項得來的心得看來,當使用者按下編輯的按鈕,系統會由RowCommand去分析是哪一個資料列引發,(分析的依據是???又是sender這個物件吧 ) ,然後透過CommandName來判斷是要執行什麼動作,因為編輯按鈕的CommandName 是 Edit,所以會觸發GridView的RowEditing事件,進入編輯模式。
進入編輯模式後,如果使用者按下更新按鈕,因為CommandName是Update,就去執行SqlDataSource的UpdateCommand…

以上還是推論(我還是看不到ASP.NET怎麼完成這個工作的),不過至少我們可以應用像RowCommand這樣的事件,去設計一個像內建Command按鈕的處理常式。不過使用的時候,我們就要避免去使用系統內建的關鍵字。

以下整理一下這些大型控制項的CommandName

CommandName GridView:RowCommand // ListView:ItemCommand // FormView:ItemCommand // DetailsView:ItemCommand   描述
Edit 將目前的資料錄置於編輯模式。 引發: RowEditing // ItemEditing // ModeChangedModeChanging //ModeChangingModeChanged
Update 更新資料來源中目前的資料錄。 引發: RowUpdatingRowUpdated // ItemUpdatingItemUpdated // ItemUpdatedItemUpdating // ItemUpdatingItemUpdated
Cancel 取消編輯 / 編輯或刪除 作業。 引發: RowCancelingEdit // ItemCanceling // ModeChangedModeChanging // ModeChangingModeChanged
Delete 將目前的資料錄從資料來源中刪除。 引發: RowDeletingRowDeleted // ItemDeletedItemDeleting // ItemDeletedItemDeleting //ItemDeletingItemDeleted
Select 選取目前的資料錄。 引發: SelectedIndexChangingSelectedIndexChanged //SelectedIndexChangingSelectedIndexChanged // FormView無 // DetailsView無
Sort 對控制項進行排序。 引發: SortingSorted //SortingSorted //FormView無 //DetailsView無
Page 執行分頁作業。引發: PageIndexChangingPageIndexChanged // ListView無 //PageIndexChangedPageIndexChanging //PageIndexChangingPageIndexChanged
Insert 新增資料。引發: GridView無 //  ItemInsertingItemInserted // ItemInsertedItemInserting //ItemInsertingItemInserted
New 新增資料。 引發: GridView無 // ListView無 // ModeChangedModeChanging //ModeChangingModeChanged
Add 新增資料。引發: GridView無 // ListView無 // FormView無 //ItemCreated 事件

參考資料:
GridView的 RowCommand 事件、ListView的ItemCommand 事件、FormView的ItemCommand 事件、DetailsView的ItemCommand 事件

整理完畢後,其實可以發現GridView和其他控制項的最大差異,就是GridView是以資料列(ROW)方式來呈現的,所以像在辨別CommandName時,也需要考慮是哪一「列」觸發的,不像其他控制項,只要管好一個資料項「Item」就好了,而GridView也是ASP.NET控制項裡提供功能比較複雜的,學習完GridView的事件後 (尤其熟悉每個事件可以使用的二大參數),後面再去學其他的控制項就容易理解許多。

沒有留言:

張貼留言

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