此文轉貼於http://mobile.dotblogs.com.tw/topcat/archive/02/23/7266.aspx

 

透過手寫程式了解GridView的運作

緣起:

小喵接觸ASP.NET是從ASP.NET 2.0開始(VS2005),而GridView這個控制項也是從這個時候開始出現,由於有DataSouce的輔助,讓我們在使用上非常的方便。只要拖 拉一下,設定一下,資料就可以透過GridView顯示在網頁上了。不過方便的結果,可能用了一段時間,開發了幾套系統,卻還不知道這GridView到 底是怎麼運作的(因為通通包裝的好好的)。

這一篇是強迫不使用 DataSource(SqlDatasouce,ObjectDataSouce,AccessDataSource,...)的情況下,透過ADO的 存取資料庫,以及GridView的各個事件,來理解GridView的一些運作狀況。小喵會在這篇中,寫下有關GridView的資料繫結、編輯、修 改、刪除、排序、分頁等功能的程式碼。

準備工作:

此篇範例照慣例,使用北風資料庫當做範例。用最簡單的資料表【Region】來當作範例,當然大家在練習時,可以自己去改掉Connection String與Table名稱。

畫面:

畫面上安排很簡單,就是安排一個GridView,然後隨便選一個樣式(可以分辨編輯實的顏色變化),另外加入一個Templete Fields,用來放置【編輯、刪除、維護、取消】的按鈕。另外再安排一個Button,用來第一次繫結資料。相關程式碼如下:

 

        <asp:Label ID="lblMsg" runat="server" Text=""></asp:Label>
<br />
<asp:Button ID="Button1" runat="server" Text="Button" />
<asp:GridView ID="GridView1" runat="server" AllowSorting="True"
BackColor="White" BorderColor="#E7E7FF" BorderStyle="None" BorderWidth="1px"
CellPadding="3" GridLines="Horizontal" AllowPaging="True" PageSize="3">
<RowStyle BackColor="#E7E7FF" ForeColor="#4A3C8C" />
<Columns>
<asp:TemplateField>
<EditItemTemplate>
<asp:Button ID="btnUpdate" runat="server" Text="維護" CommandName="Update" />
<asp:Button ID="btnCancel" runat="server" Text="取消" CommandName="Cancel" />
</EditItemTemplate>
<ItemTemplate>
<asp:Button ID="btnEdit" runat="server" Text="編輯" CommandName="Edit" />
<asp:Button ID="btnDel" runat="server" Text="刪除" CommandName="Delete" OnClientClick="return confirm('您確定要刪除此筆資料嗎??');" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<FooterStyle BackColor="#B5C7DE" ForeColor="#4A3C8C" />
<PagerStyle BackColor="#E7E7FF" ForeColor="#4A3C8C" HorizontalAlign="Right" />
<SelectedRowStyle BackColor="#738A9C" Font-Bold="True" ForeColor="#F7F7F7" />
<HeaderStyle BackColor="#4A3C8C" Font-Bold="True" ForeColor="#F7F7F7" />
<AlternatingRowStyle BackColor="#F7F7F7" />
</asp:GridView>

後置程式碼:

接著就開始來撰寫程式碼的部分。首先,要手動寫程式了,當然要Imports相關的NameSpance

Imports System.Data
Imports System.Data.SqlClient

並且設定一下Connection String

Private ConnStr As String = "Data Source=.\sqlexpress;Initial Catalog=Northwind;Integrated Security=True"

接著撰寫【查詢、修改、刪除】資料的Function,用來【讀取、修改、刪除】Region資料表,讀取的Function傳回DataTable。

    Private Function GetData() As DataTable
Dim Dt As New DataTable
Try
Using Conn As New SqlConnection(ConnStr)
Dim SqlTxt As String = ""
SqlTxt += " SELECT TOP 50 * "
SqlTxt += " FROM [Region] (NOLOCK) "
SqlTxt += " "
Dim Cmmd As New SqlCommand(SqlTxt, Conn)
Dim Da As New SqlDataAdapter(Cmmd)
Da.Fill(Dt)

End Using

Catch ex As Exception
Me.lblMsg.Text = ex.Message

End Try
Return Dt
End Function

Private Function DeleteData(ByVal RegionID As Integer) As String
Dim rc As String = ""
Try
Using Conn As New SqlConnection(ConnStr)
Conn.Open()
Dim SqlTxt As String = ""
SqlTxt += " DELETE Region "
SqlTxt += " WHERE RegionID = @RegionID "
SqlTxt += " "
Using Cmmd As New SqlCommand(SqlTxt, Conn)
Cmmd.Parameters.AddWithValue("@RegionID", RegionID)
Cmmd.ExecuteNonQuery()
End Using

rc = "Success"
End Using

Catch ex As Exception
rc = "False"
Me.lblMsg.Text = ex.Message

End Try
Return rc
End Function

Private Function UpdData(ByVal RegionID As Integer, ByVal RegionDescription As String) As String
Dim Rc As String = ""
Try
Using Conn As New SqlConnection(ConnStr)
Conn.Open()
Dim SqlTxt As String = ""
SqlTxt += " UPDATE Region "
SqlTxt += " SET RegionDescription = @RegionDescription "
SqlTxt += " WHERE RegionID = @RegionID "
SqlTxt += " "
Using Cmmd As New SqlCommand(SqlTxt, Conn)
Cmmd.Parameters.AddWithValue("@RegionDescription", RegionDescription)
Cmmd.Parameters.AddWithValue("@RegionID", RegionID)
Cmmd.ExecuteNonQuery()
Rc = "Success"
End Using
End Using

Catch ex As Exception
Rc = "False"
Me.lblMsg.Text = ex.Message
End Try
Return Rc
End Function

接著陸續來看查詢、編輯、修改、刪除、分頁、排序的各個程式碼:

查詢:當按鈕按下去後,將資料繫結給GridView,因此先寫一個將資料繫結的Sub GVGetData()來處理,未來會有很多地方都要呼叫這一個Sub作繫結資料處理

    '抓取資料並繫結GridView
Private Sub GVGetData()
Try
Dim Dt As DataTable = GetData()
Me.GridView1.DataSource = Dt
Me.GridView1.DataBind()

Catch ex As Exception
Me.lblMsg.Text = ex.Message

End Try
End Sub

接著,按鈕按下去的時候,只需要呼叫他就可以了

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
'呼叫資料繫結
GVGetData()
End Sub

接著,再來看分頁如何做。分頁時,要設定GridView的AllowPaging=True,另外,由於這個資料表的資料不多,所以 改一下,一頁的筆數預設是10筆,改為3筆(PageSize="3")。此時就會有分頁的功能,不過當換頁時,會觸發 【PageIndexChanging】與【PageIndexChanged】這兩個事件。程式碼如下:

    Protected Sub GridView1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.PageIndexChanged
'顯示PageIndexChanged事件被呼叫到
Response.Write("PageIndexChanged!!")
End Sub

Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
'設定分頁停在第幾頁
Me.GridView1.PageIndex = e.NewPageIndex
'繫結資料
GVGetData()
End Sub

排序:查詢、分頁有了,接著就是排序。排序的時候,會觸發Sorting與Sorted這兩個事件。不過這個部分稍微麻煩,經測試後發 現,在Sorting的e.SortDirection並沒有記住這次順排(Ascending)→下次就逆排(Descending)的狀況,每次取得 的e.SortDirection通通都是順排(Ascending)。為了達到第一次點順排,再點一次是逆排,因此要透過ViewState來記錄上次 的方式,在加上判斷。

另外,本來的繫結資料時,並沒有排序,只有直接把取得的DataTable給GridView。現在要加上排序的功能 了,那麼就要拿DataTable的資料來做排序的動作,這個部分要借用【DataView】的【Sort】來設定,而且DataView也可以當作 GridView的資料來源。因此我們改寫一下繫結資料的部分先,然後再寫Sorting與Sorted這兩個事件

繫結資料的部分:

透過多型,希望Sorting的時候要繫結資料呼叫GVGetData的另一個型態

    '有指定排序的抓資料並繫結GridView
Private Sub GVGetData(ByVal pSortDirection As SortDirection, ByVal pSortExpression As String)
Try
Dim Dt As DataTable = GetData()
'設定排序的語法
Dim strSort As String = ""

If pSortDirection = SortDirection.Ascending Then
'如果是順排(A~Z)
strSort = pSortExpression
Else
'逆排的時候(Z~A),加上DESC
strSort = pSortExpression & " DESC"
End If

'使用DataView來做GridView的資料來源
Dim Dv As DataView = Dt.DefaultView
'設定DataView的排序方式
Dv.Sort = strSort

Me.GridView1.DataSource = Dv
Me.GridView1.DataBind()

Catch ex As Exception
Me.lblMsg.Text = ex.Message

End Try
End Sub

接著是Sorting與Sorted的部分

    Protected Sub GridView1_Sorted(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.Sorted
'顯示Sorted事件備觸發
Response.Write("Sorted!!")
End Sub

Protected Sub GridView1_Sorting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewSortEventArgs) Handles GridView1.Sorting


Dim NowSE As String = CType(ViewState("NowSE"), String) '現在的排序欄位
Dim NowSD As SortDirection = CType(ViewState("NowSD"), SortDirection) '目前的排序方向

If NowSE Is Nothing Then
'如果沒有ViewState,指定e.SortExpression與順排當作預設的欄位與方向
NowSE = e.SortExpression
NowSD = SortDirection.Ascending
Else
'有ViewState時
If NowSE <> e.SortExpression Then
'如果欄位與本來的不同
'指定目前的欄位為e.SortExpression
NowSE = e.SortExpression
'指定目前的排序方向為順排
NowSD = SortDirection.Ascending
Else
'如果欄位與本來相同
If NowSD = SortDirection.Ascending Then
'當本來為順排→改為逆排
NowSD = SortDirection.Descending
Else
'當本來違逆排→改為順排
NowSD = SortDirection.Ascending
End If
End If
End If
'將得到的欄位與方向,紀錄回ViewState
ViewState("NowSD") = NowSD
ViewState("NowSE") = NowSE

'呼叫繫結資料,並指定排序欄位與方向
GVGetData(NowSD, NowSE)
End Sub

這樣子,排序就OK了。不過小喵發現,這樣子排序配合分頁的切換,由於本來的沒有考慮排序,所以每次分頁一切換,就會弄亂排序的狀況。因此要改一下資料繫結的部分,檢查ViewState中是否有設定排序的欄位與方向。改一下本來的GVGetData()

    '抓取資料並繫結GridView
Private Sub GVGetData()
Try
'判斷是否有排序過
If ViewState("NowSE") Is Nothing Then
'沒有排序過,直接抓DataTable
Dim Dt As DataTable = GetData()
Me.GridView1.DataSource = Dt
Me.GridView1.DataBind()
Else
'排序過,因此除了抓資料,還要排序
Dim NowSE As String = CType(ViewState("NowSE"), String)
Dim NowSD As SortDirection = CType(ViewState("NowSD"), SortDirection)
GVGetData(NowSD, NowSE)
End If

Catch ex As Exception
Me.lblMsg.Text = ex.Message

End Try
End Sub

這樣無論排序、分頁的部分都可以正常運作了。

接著,就是編輯、修改、刪除的程式碼。這部分小喵發現,在預期的狀況下,修 改、刪除的時候,會觸發RowUpdating與RowUpdated / 或者 RowDeleting與RowDeleted。但是實際Step By Step的運作下,令人驚訝的發現,維護後的RowUpdated與刪除後的RowDeleted這兩個事件並不會被觸發。這與小喵以往的印象ing:處 理中/ed:處理後的理解與期望不同。小喵特別發了一個討論在小舖中【手動寫程式處理GridView的維護,為何沒有觸發RowUpdated事件】, 看來GridView沒有使用DataSourceID去繫結DataSource控制項的狀況下,不會觸發這兩個ed的事件

以下為編輯、修改、取消、刪除的程式碼:

刪除資料:

    Protected Sub GridView1_RowDeleted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeletedEventArgs) Handles GridView1.RowDeleted
'顯示RowDeleted備觸發→事實上用程式碼並不會觸發此事件!!
Response.Write("RowDeleted")
'GVGetData()
End Sub

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

Dim RegionID As Integer '刪除的Key值
'取得刪除的Key
RegionID = CType(Me.GridView1.Rows(e.RowIndex).Cells(1).Text, Integer)
'呼叫刪除的Function
Dim rc As String = DeleteData(RegionID)
If rc = "Success" Then
Me.lblMsg.Text = "刪除成功!!"
'呼叫繫結資料重新繫結
GVGetData()
End If

Catch ex As Exception
Me.lblMsg.Text = ex.Message
End Try
End Sub

編輯:

    Protected Sub GridView1_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles GridView1.RowEditing
'設定編輯的Index
Me.GridView1.EditIndex = e.NewEditIndex
'繫結資料
GVGetData()
End Sub

取消:

    Protected Sub GridView1_RowCancelingEdit(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCancelEditEventArgs) Handles GridView1.RowCancelingEdit
'取消編輯模式→設定GridView的EditIndex = -1
Me.GridView1.EditIndex = -1
GVGetData()
End Sub

修改:

    Protected Sub GridView1_RowUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) Handles GridView1.RowUpdated
'離開編輯模式
'Me.GridView1.EditIndex = -1
'GVGetData()

Response.Write("RowUpdated")
End Sub

Protected Sub GridView1_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView1.RowUpdating
Try

Dim RegionID As Integer
Dim RegionDescription As String

'取得畫面中的資料
Dim tGvRw As GridViewRow = Me.GridView1.Rows(e.RowIndex)
RegionID = CType(CType(tGvRw.Cells(1).Controls(0), TextBox).Text, Integer)
RegionDescription = CType(tGvRw.Cells(2).Controls(0), TextBox).Text

'進行維護
Dim Rc As String = UpdData(RegionID, RegionDescription)
If Rc = "Success" Then
Me.lblMsg.Text = "維護成功"
'離開編輯模式
Me.GridView1.EditIndex = -1
GVGetData()
End If

Catch ex As Exception
Me.lblMsg.Text = ex.Message
End Try
End Sub

後記

再經過這樣的練習後,對於GridView的一些運作,會有比較清楚了瞭解。據說這樣的能力在以前DataGrid 的時代,是基本的能力,也就是大家都必須這麼寫。自從ASP.NET 2.0開始,GridView搭配DataSource控制項實在太好用了。簡單的使用SqlDataSource只需要拖拉、設定就可以通通達成。進一 步需要透過程式處理,也可以寫成Class透過ObjectDataSource來達成。不過,當系統的需求越來越複雜,有時候就需要去透過 GridView各項事件去處理一些狀況。透過這樣的練習可以來了解一下各個事件的用法。小喵因此將過程筆記下來,也提供大家參考。

arrow
arrow
    全站熱搜

    suhsienchin 發表在 痞客邦 留言(0) 人氣()