知識社群師生部落格登入
testest
by Willa Hung, 2013-10-16 23:07, 人氣(331)

緣起:

小喵接觸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,用來第一次繫結資料。相關程式碼如下:

 

01<asp:Label ID="lblMsg" runat="server" Text=""></asp:Label>
02<br />
03<asp:Button ID="Button1" runat="server" Text="Button" />
04<asp:GridView ID="GridView1" runat="server" AllowSorting="True"
05    BackColor="White" BorderColor="#E7E7FF" BorderStyle="None" BorderWidth="1px"
06    CellPadding="3" GridLines="Horizontal" AllowPaging="True" PageSize="3">
07    <RowStyle BackColor="#E7E7FF" ForeColor="#4A3C8C" />
08    <Columns>
09        <asp:TemplateField>
10            <EditItemTemplate>
11                <asp:Button ID="btnUpdate" runat="server" Text="維護" CommandName="Update" />
12                <asp:Button ID="btnCancel" runat="server" Text="取消" CommandName="Cancel" />
13            </EditItemTemplate>
14            <ItemTemplate>
15                <asp:Button ID="btnEdit" runat="server" Text="編輯" CommandName="Edit" />
16                <asp:Button ID="btnDel" runat="server" Text="刪除" CommandName="Delete" OnClientClick="return confirm('您確定要刪除此筆資料嗎??');" />
17            </ItemTemplate>
18        </asp:TemplateField>
19    </Columns>
20    <FooterStyle BackColor="#B5C7DE" ForeColor="#4A3C8C" />
21    <PagerStyle BackColor="#E7E7FF" ForeColor="#4A3C8C" HorizontalAlign="Right" />
22    <SelectedRowStyle BackColor="#738A9C" Font-Bold="True" ForeColor="#F7F7F7" />
23    <HeaderStyle BackColor="#4A3C8C" Font-Bold="True" ForeColor="#F7F7F7" />
24    <AlternatingRowStyle BackColor="#F7F7F7" />
25</asp:GridView>

後置程式碼:

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

1Imports System.Data
2Imports System.Data.SqlClient

並且設定一下Connection String

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

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

01Private Function GetData() As DataTable
02    Dim Dt As New DataTable
03    Try
04        Using Conn As New SqlConnection(ConnStr)
05            Dim SqlTxt As String = ""
06            SqlTxt += " SELECT TOP 50 * "
07            SqlTxt += " FROM [Region] (NOLOCK) "
08            SqlTxt += "  "
09            Dim Cmmd As New SqlCommand(SqlTxt, Conn)
10            Dim Da As New SqlDataAdapter(Cmmd)
11            Da.Fill(Dt)
12 
13        End Using
14 
15    Catch ex As Exception
16        Me.lblMsg.Text = ex.Message
17 
18    End Try
19    Return Dt
20End Function
21 
22Private Function DeleteData(ByVal RegionID As Integer) As String
23    Dim rc As String = ""
24    Try
25        Using Conn As New SqlConnection(ConnStr)
26            Conn.Open()
27            Dim SqlTxt As String = ""
28            SqlTxt += " DELETE Region "
29            SqlTxt += " WHERE RegionID = @RegionID "
30            SqlTxt += "  "
31            Using Cmmd As New SqlCommand(SqlTxt, Conn)
32                Cmmd.Parameters.AddWithValue("@RegionID", RegionID)
33                Cmmd.ExecuteNonQuery()
34            End Using
35 
36            rc = "Success"
37        End Using
38 
39    Catch ex As Exception
40        rc = "False"
41        Me.lblMsg.Text = ex.Message
42 
43    End Try
44    Return rc
45End Function
46 
47Private Function UpdData(ByVal RegionID As Integer, ByVal RegionDescription As String) As String
48    Dim Rc As String = ""
49    Try
50        Using Conn As New SqlConnection(ConnStr)
51            Conn.Open()
52            Dim SqlTxt As String = ""
53            SqlTxt += " UPDATE Region "
54            SqlTxt += " SET RegionDescription = @RegionDescription "
55            SqlTxt += " WHERE RegionID = @RegionID "
56            SqlTxt += "  "
57            Using Cmmd As New SqlCommand(SqlTxt, Conn)
58                Cmmd.Parameters.AddWithValue("@RegionDescription", RegionDescription)
59                Cmmd.Parameters.AddWithValue("@RegionID", RegionID)
60                Cmmd.ExecuteNonQuery()
61                Rc = "Success"
62            End Using
63        End Using
64 
65    Catch ex As Exception
66        Rc = "False"
67        Me.lblMsg.Text = ex.Message
68    End Try
69    Return Rc
70End Function

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

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

01'抓取資料並繫結GridView
02Private Sub GVGetData()
03    Try
04            Dim Dt As DataTable = GetData()
05            Me.GridView1.DataSource = Dt
06            Me.GridView1.DataBind()
07 
08    Catch ex As Exception
09        Me.lblMsg.Text = ex.Message
10 
11    End Try
12End Sub

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

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

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

01Protected Sub GridView1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.PageIndexChanged
02    '顯示PageIndexChanged事件被呼叫到
03    Response.Write("PageIndexChanged!!")
04End Sub
05 
06Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
07    '設定分頁停在第幾頁
08    Me.GridView1.PageIndex = e.NewPageIndex
09    '繫結資料
10    GVGetData()
11End Sub

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

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

繫結資料的部分:

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

01'有指定排序的抓資料並繫結GridView
02Private Sub GVGetData(ByVal pSortDirection As SortDirection, ByVal pSortExpression As String)
03    Try
04        Dim Dt As DataTable = GetData()
05        '設定排序的語法
06        Dim strSort As String = ""
07 
08        If pSortDirection = SortDirection.Ascending Then
09            '如果是順排(A~Z)
10            strSort = pSortExpression
11        Else
12            '逆排的時候(Z~A),加上DESC
13            strSort = pSortExpression & " DESC"
14        End If
15 
16        '使用DataView來做GridView的資料來源
17        Dim Dv As DataView = Dt.DefaultView
18        '設定DataView的排序方式
19        Dv.Sort = strSort
20 
21        Me.GridView1.DataSource = Dv
22        Me.GridView1.DataBind()
23 
24    Catch ex As Exception
25        Me.lblMsg.Text = ex.Message
26 
27    End Try
28End Sub

接著是Sorting與Sorted的部分

01Protected Sub GridView1_Sorted(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.Sorted
02    '顯示Sorted事件備觸發
03    Response.Write("Sorted!!")
04End Sub
05 
06Protected Sub GridView1_Sorting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewSortEventArgs) Handles GridView1.Sorting
07 
08 
09    Dim NowSE As String = CType(ViewState("NowSE"), String) '現在的排序欄位
10    Dim NowSD As SortDirection = CType(ViewState("NowSD"), SortDirection)   '目前的排序方向
11 
12    If NowSE Is Nothing Then
13        '如果沒有ViewState,指定e.SortExpression與順排當作預設的欄位與方向
14        NowSE = e.SortExpression
15        NowSD = SortDirection.Ascending
16    Else
17        '有ViewState時
18        If NowSE <> e.SortExpression Then
19            '如果欄位與本來的不同
20            '指定目前的欄位為e.SortExpression
21            NowSE = e.SortExpression
22            '指定目前的排序方向為順排
23            NowSD = SortDirection.Ascending
24        Else
25            '如果欄位與本來相同
26            If NowSD = SortDirection.Ascending Then
27                '當本來為順排→改為逆排
28                NowSD = SortDirection.Descending
29            Else
30                '當本來違逆排→改為順排
31                NowSD = SortDirection.Ascending
32            End If
33        End If
34    End If
35    '將得到的欄位與方向,紀錄回ViewState
36    ViewState("NowSD") = NowSD
37    ViewState("NowSE") = NowSE
38 
39    '呼叫繫結資料,並指定排序欄位與方向
40    GVGetData(NowSD, NowSE)
41End Sub

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

01'抓取資料並繫結GridView
02Private Sub GVGetData()
03    Try
04        '判斷是否有排序過
05        If ViewState("NowSE") Is Nothing Then
06            '沒有排序過,直接抓DataTable
07            Dim Dt As DataTable = GetData()
08            Me.GridView1.DataSource = Dt
09            Me.GridView1.DataBind()
10        Else
11            '排序過,因此除了抓資料,還要排序
12            Dim NowSE As String = CType(ViewState("NowSE"), String)
13            Dim NowSD As SortDirection = CType(ViewState("NowSD"), SortDirection)
14            GVGetData(NowSD, NowSE)
15        End If
16 
17    Catch ex As Exception
18        Me.lblMsg.Text = ex.Message
19 
20    End Try
21End Sub

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

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

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

刪除資料:

01Protected Sub GridView1_RowDeleted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeletedEventArgs) Handles GridView1.RowDeleted
02    '顯示RowDeleted備觸發→事實上用程式碼並不會觸發此事件!!
03    Response.Write("RowDeleted")
04    'GVGetData()
05End Sub
06 
07Protected Sub GridView1_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
08    Try
09 
10        Dim RegionID As Integer '刪除的Key值
11        '取得刪除的Key
12        RegionID = CType(Me.GridView1.Rows(e.RowIndex).Cells(1).Text, Integer)
13        '呼叫刪除的Function
14        Dim rc As String = DeleteData(RegionID)
15        If rc = "Success" Then
16            Me.lblMsg.Text = "刪除成功!!"
17            '呼叫繫結資料重新繫結
18            GVGetData()
19        End If
20 
21    Catch ex As Exception
22        Me.lblMsg.Text = ex.Message
23    End Try
24End Sub

編輯:

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

取消:

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

修改:

01Protected Sub GridView1_RowUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) Handles GridView1.RowUpdated
02    '離開編輯模式
03    'Me.GridView1.EditIndex = -1
04    'GVGetData()
05 
06    Response.Write("RowUpdated")
07End Sub
08 
09Protected Sub GridView1_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView1.RowUpdating
10    Try
11 
12        Dim RegionID As Integer
13        Dim RegionDescription As String
14 
15        '取得畫面中的資料
16        Dim tGvRw As GridViewRow = Me.GridView1.Rows(e.RowIndex)
17        RegionID = CType(CType(tGvRw.Cells(1).Controls(0), TextBox).Text, Integer)
18        RegionDescription = CType(tGvRw.Cells(2).Controls(0), TextBox).Text
19 
20        '進行維護
21        Dim Rc As String = UpdData(RegionID, RegionDescription)
22        If Rc = "Success" Then
23            Me.lblMsg.Text = "維護成功"
24            '離開編輯模式
25            Me.GridView1.EditIndex = -1
26            GVGetData()
27        End If
28 
29    Catch ex As Exception
30        Me.lblMsg.Text = ex.Message
31    End Try
32End Sub

後記

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

發表討論