ASP.NET Datagrid建立自訂欄

來源:互聯網
上載者:User
asp.net|datagrid|建立 簡介

  不得不承認,為 Microsoft? ASP.NET 編寫 Datagrid 程式碼封裝括大量的重複工作。儘管我深受該控制項的困擾,但我還是不斷尋找簡化這類任務的捷徑。誰都不願意做重複的工作,對不對?為了擺脫這種煩人的工作,我們要將多重專案中的重複代碼封裝到一個可重複使用的程式包中。這才是物件導向的編程工作所要解決的問題,使用 Datagrid 也不例外。對於 Datagrid 控制項來說,要實現該目的,需要將常用的代碼放到一個內建的列類型中(將在第一個樣本中使用),然後建立一個可以在多個 Datagrid 對象中重複使用的自訂欄類型。
  本文介紹使用標準 TemplateColumn 在一個 Datagrid 列中使用 DropDownList 控制項的過程,然後將該邏輯轉換為您的自訂 Datagrid 列類型,我稱其為 DropDownColumn。已經為您建立了一些免費的 Datagrid 列,您可以到 MetaBuilders.com 下載所需的類型。

  重複使用的情況

  如果您的小組與許多組織一樣,已經將商務邏輯和/或資料訪問邏輯分成單獨的組件或組件集,而剩下的 ASP.NET 檔案、ASPX 及其代碼只包含純粹的表示邏輯。(“純粹”是一個相對的詞語。)但是,即使是展示層的邏輯有時也會重複使用,這樣,下次某個使用者來到您門前說,“我想讓我的應用程式在‘財務’方面看起來與蘇茜的一樣”時,您可以重複使用“財務”應用程式的部分表示內容快速為其構建一個這樣的應用程式。您可能還想將一些邏輯打包,在 Web 上銷售或在您的 Web 網站分發。ASP.NET 使這一切比以往更容易實現,因為它使您可以建立自己的伺服器控制項,或從現有的類型匯出列類型,從而獲得所需的功能。

  DropDownList 方案

  假設您正在本地 Microsoft SQL Server? 中編輯 Northwind 資料庫(或做其他工作),您想使您的使用者(我們稱之為 Ed,倉庫保管員)可以編輯 Orders 表。其中一個欄位包含運輸資訊 (ShipVia),Ed 要能夠修改該欄位的資訊。在顯示模式下,運輸公司應顯示為純文字。當 Ed 單擊 Edit(編輯)按鈕時,您不光要為他提供一個 TextBox 以編輯運輸方式代碼(1、2 或 3),還要為他提供一個包含可以選擇不同運輸公司的 DropDownList。(因為 Ed 記不住哪個運輸公司對應哪個號碼,所以,DropDownList 方案可以協助他解決這個問題。)



  內建的 Datagrid 列

  瞭解問題的大概情況後,現在我們後退一步,看一下 ASP.NET 中構建的 5 種 Datagrid 列類型及其父類型 DataGridColumn。

  BoundColumn。這是文字欄位的標準顯示。它顯示為純文字,但是當 Datagrid 處於“編輯”模式時,它將轉換為 TextBox。還可以選擇格式化選項。

  HyperlinkColumn。用於顯示文本資料,還代表一個 Web 地址 (URL)。URL 可以與顯示文本相同,也可以不同,它們都可以單獨設定。它顯示為 <a href=...> 標記。

  ButtonColumn。它使使用者能夠按行與網格進行互動。它可以顯示為超連結 LinkButton (<a href=...>) 或 Pushbutton (<input type="button">)。單擊該按鈕時將觸發 PostBack,而在 Datagrid 上觸發 ItemCommand 事件。

  EditCommandColumn。它與 ButtonColumn 類似,但是它自動建立用於編輯 Datagrid、取消或提交更改的按鈕。觸發 ItemCommand 事件,以及所單擊按鈕的特定事件:EditCommand、CancelCommand 或 UpdateCommand。

  TemplateColumn。用於完全控制顯示給使用者的控制項,分為多種模板,例如 ItemTemplate 和 EditItemTemplate。任何 ASP.NET 或 HTML 控制項或控制群組都可以放置在這些模板中。

  注意:直接使用這些列類型之前,請關閉 AutoGenerateColumns(運行時自動產生列)。然後,您可以在屬性產生器中使用這些列類型,或者直接在 ASPX 檔案的 HTML 程式碼中使用。



  儘管這些列類型非常有用,它們不過是瞭解 Datagrid 列內容的開始。

  傳統方法:TemplateColumn 中的 DropDownList

  在研究如何建立新列類型之前,首先讓我們看一下如何通過直接在 TemplateColumn 內使用 DropDownList 解決下拉式清單的問題,而不用自訂欄。ItemTemplate 將只包含表示當前值的純文字表示,而 EditItemTemplate 包含一個需要在運行時管理的 <asp:DropDownList> 控制項。

<asp:DataGrid id="DataGrid1" runat="server" CssClass="grid" AutoGenerateColumns="False">
<Columns>
 <asp:EditCommandColumn EditText="Edit" CancelText="Cancel" UpdateText="Update" />
 <asp:BoundColumn DataField="OrderID" ReadOnly="True" HeaderText="Order ID" />
 <asp:BoundColumn DataField="ShipName" HeaderText="Ship to" ReadOnly="True" />
 <asp:BoundColumn DataField="ShipCountry" HeaderText="Country" ReadOnly="True" />
 <asp:TemplateColumn HeaderText="Ship Method">
 <ItemTemplate>
  <%#Container.DataItem("ShipVia")%>
 </ItemTemplate>
 <EditItemTemplate>
  <asp:DropDownList runat="server" ID="Dropdownlist1"/>
 </EditItemTemplate>
 </asp:TemplateColumn>
</Columns>
</asp:DataGrid>
  綁定 Datagrid 的代碼:

Sub BindGrid()
 Dim SQL As String = "SELECT OrderID,
 ShipName, ShipCountry, ShipVia FROM Orders"
 Dim DA As SqlDataAdapter = New SqlDataAdapter(SQL, ConnStr)
 Dim DS As New DataSet
 DA.Fill(DS, "Orders")
 DataGrid1.DataSource = DS.Tables("Orders").DefaultView
 DataGrid1.DataBind()
End Sub
  當前編輯的項目是在觸發 Datagrid 的 ItemDataBound 事件時綁定到 DropDownList 的。使用 ItemDataBound 事件時,請檢查當前項目的 ListItemType,否則您可能會發現您正在使用 HeaderItem 或其他不適用的項目類型。為 EditItem 引用 DropDownList 控制項。在下面的代碼中,我直接使用儲存格控制項集進行說明(為了與後面的樣本保持一致),但是,您可以採用簡單的方法,直接為 DropDownList 控制項指定 ID,並使用 Datagrid 項目的 FindControl 方法定位控制項引用。由於 Datagrid 被綁定到 DataTable 的預設視圖,而該視圖的元素屬於 DataRowView 類型,所以您可以將當前項目的 DataItem 屬性轉換為一個 DataRowView 執行個體。這樣,您可以按欄位名直接引用 DataItem 中的欄位。使用這種方法,將“ShipVia”的當前值儲存到該記錄中,並使用它選擇相應的下拉式清單項。

Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) _
Handles DataGrid1.ItemDataBound
 If e.Item.ItemType = ListItemType.EditItem Then
  Dim DRV As DataRowView = CType(e.Item.DataItem, DataRowView)
  Dim CurrentShip As String = DRV("ShipVia")
  Dim DDL As DropDownList = CType(e.Item.Cells(4).Controls(1), DropDownList)
  Dim SQL As String = "SELECT ShipperID, CompanyName FROM Shippers ORDER BY ShipperID"
  Dim DA As SqlDataAdapter = New SqlDataAdapter(SQL, ConnStr)
  Dim DS As New DataSet
  Dim item As ListItem
  DA.Fill(DS, "Shippers")
  DDL.DataSource = DS.Tables("Shippers").DefaultView
  DDL.DataTextField = "CompanyName"
  DDL.DataValueField = "ShipperID"
  DDL.DataBind()
  item = DDL.Items.FindByValue(CurrentShip)
 If Not item Is Nothing Then item.Selected = True
 End If
End Sub
  最後,編寫從 DropDownList 中檢索當前選定值的代碼,並執行資料庫更新:

Private Sub DataGrid1_UpdateCommand(ByVal source As Object, _
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) _
Handles DataGrid1.UpdateCommand
 Dim DDL As DropDownList = CType(e.Item.Cells(4).Controls(1), DropDownList)
 Dim NewShip As Integer = DDL.SelectedValue
 Dim OrderID As Integer = Int32.Parse(e.Item.Cells(1).Text)
 Dim SQL As String = "UPDATE Orders SET ShipVia=@Ship WHERE OrderID=@ID"
 Dim Conn As SqlConnection = New SqlConnection(ConnStr)
 Dim Cmd As New SqlCommand(SQL, Conn)
 Cmd.Parameters.Add(New SqlParameter("@Ship", NewShip))
 Cmd.Parameters.Add(New SqlParameter("@ID", OrderID))
 Conn.Open()
 Cmd.ExecuteNonQuery()
 Conn.Close()
 DataGrid1.EditItemIndex = -1
 BindGrid()
End Sub

  所有列的基礎:DataGridColumn

  我們回顧一下所有內建列類型的父類型 DataGridColumn。(參見圖 1。)它包含所有 Datagrid 列中常用的屬性和方法。帶星號的類型表示您建立自訂欄類型時要使用的類型。

DataGridColumn 屬性
FooterStyle (TableItemStyle)
FooterText(字串)
HeaderImageUrl(字串)
HeaderStyle (TableItemStyle)
HeaderText(字串)
ItemStyle (TableItemStyle)
SortExpression(字串)
Visible(布爾值)
DataGridColumn 方法
Initialize
InitializeCell
LoadViewState
OnColumnChanged
SaveViewState
TrackViewState
  可重複使用的方法:建立 DropDownColumn

  首先要在 Microsoft Visual Studio .NET 中建立一個新類庫,並將其命名為 MyCustomColumn。添加一個新類 DropDownColumn,並確保在您的類定義中添加命名空間,這樣您的初始代碼應如下所示:

Namespace MyCustomColumn
Public Class DropDownColumn
Inherits DataGridColumn

Public DataSource As ICollection
Public DataField As String
Public DataTextField As String
Public DataValueField As String

End Class
End Namespace
  我還聲明了 4 個公用屬性,如下所示:
 
  DataSource。它是用來填充 DropDownList 的資料集。可以是實現 ICollection 介面的任何內容。在本文的樣本中,我使用 ArrayList 和 DataView。

  DataField。它是父 Datagrid 資料來源中的欄位,它與從下拉式清單中選定的資料相對應。例如,如果DataSource 包含一個狀態集,DataField 將類似於“StateCode”,也可以在表格中使用狀態隨意命名欄位。

  DataTextField。這是要顯示在下拉式清單中的文本,可以是下面的值,也可以不是。

  DataValueField。這是表示特殊下拉選項的值。DataValueField 通常是一個整數值或其他代碼,而 DataTextField 是對使用者來說更有意義的文本說明。

  接下來,覆蓋 InitializeCell,它是 Datagrid 列的一個固有事件。列中的所有儲存格都將發生 InitializeCell,它與直接使用 Datagrid 時的 ItemCreated 事件非常相似。您可以使用它來嵌入式管理單元格內容,例如設定 HeaderText,添加您將向其中添加資料的 DropDownList 控制項。我已經為儲存格的 DataBinding 事件添加了處理常式,需要根據當前是否正在編輯行來採取不同的處理方式。每個 System.Web.UI.Control 都有一個 DataBinding 事件,當資料被綁定到控制項時,您可以從這裡訪問底層的資料,本例中為 Datagrid 中的 TableCell 對象。

Public Overrides Sub InitializeCell(ByVal cell As TableCell, _
ByVal columnIndex As Integer, _
ByVal itemType As ListItemType)
 MyBase.InitializeCell(cell, columnIndex, itemType)
 Select Case itemType
  Case ListItemType.Header
   cell.Text = HeaderText
  Case ListItemType.Item, ListItemType.AlternatingItem
   AddHandler cell.DataBinding, AddressOf ItemDataBinding
  Case ListItemType.EditItem
   AddHandler cell.DataBinding, AddressOf EditItemDataBinding
   Dim DDL As New DropDownList
   cell.Controls.Add(DDL)
 End Select
End Sub
  接下來是 ItemDataBinding 常式,當對 Datagrid 中的 Item 或 AlternatingItem 進行資料時,將觸發該常式。您需要引用回正在綁定的 TableCell,可以直接轉換傳遞給事件的“寄件者”對象,再使用 TableCell 的 NamingContainer 屬性引用當前的 DataGridItem。這裡只能以純文字格式顯示 DataField 的內容,就象顯示在 BoundColumn 中一樣。最後,如果使用者指定的欄位不存在,我將為使用者顯示更友好的錯誤資訊,而不是僅僅顯示“索引超出範圍”這樣的一般資訊。

Private Sub ItemDataBinding(ByVal sender As Object, ByVal e As EventArgs)
Dim cell As TableCell = CType(sender, TableCell)
Dim DGI As DataGridItem = CType(cell.NamingContainer, DataGridItem)
Try
cell.Text = DGI.DataItem(DataField)
Catch RangeEx As IndexOutOfRangeException
Throw New Exception("Specified DataField was not found.")
Catch OtherEx As Exception
Throw New Exception(OtherEx.InnerException.ToString)
End Try
End Sub
  下一步,編寫 EditItemDataBinding 事件的代碼,當某個行進入“編輯”模式時,將在我們的自訂欄儲存格上觸發該事件。再次引用目前的儲存格並在調用 InitializeCell 方法時插入 DropDownList 控制項。在 DropDownList 中添加一個空項目作為第一個選項,如果列中的當前資料與您從 DataSource 集合中選擇並放在列表中的任何項目都不匹配,則選擇該選項。

  然後,需要確定所傳入集合的類型。在本例中,我將處理兩種情況:通過 ArrayList 傳遞一組字串,或者資料表中的 DataView,它由 DataRowView 項目構成。對於字串資料,我將輸入一個新的 ListItem,並設定下拉項的值和文本。由於這兩種情況是相同的,所以這裡只需要文本。但是我將選擇相應的項目來根據值作出選擇,以便與下一個樣本保持一致,下一個樣本將設定一個單獨的值屬性。對於 DataRowView 項目,上一個樣本中已指出,DataRowViewInstance("FieldName") 返回一個表示該欄位中的資料的對象。可以使用同樣的方法檢索 DataTextField 和 DataValueFields 需要的值。

  最後,拋出一些異常以處理開發人員使用列時遇到的常見錯誤,例如向 DataField 屬性發送無效欄位名,或傳入不相容的 DataSource 類型。我已經對要彈出的異常訊息進行了寫入程式碼,但希望您在實際的應用程式中將這些訊息儲存到更容易配置的位置。例如,如果您希望在全球範圍內使用您的應用程式,則可以儲存到您的 web.config 檔案或資源檔中。同樣,您不一定非要再次拋出“未找到指定的 DataField”異常,因為在 Datagrid 被置於“編輯”模式之前可能已經在 ItemDataBinding 事件中捕獲了該異常。

Private Sub EditItemDataBinding(ByVal sender As Object, _
ByVal e As EventArgs)
Dim cell As TableCell = CType(sender, TableCell)
Dim DDL As DropDownList = _
CType(cell.Controls(0), DropDownList)
Dim DataSourceItem As Object
Dim item As ListItem
Dim DGI As DataGridItem

'首先添加一個空選項
DDL.Items.Add(New ListItem(""))
For Each DataSourceItem In DataSource
 Select Case DataSourceItem.GetType.ToString
  Case "System.String" '應用到 ArrayList 樣本
   item = New ListItem(DataSourceItem, DataSourceItem)
   DDL.Items.Add(item)
  Case "System.Data.DataRowView"
   Dim DRV As DataRowView = _
   CType(DataSourceItem, DataRowView)
   item = New_
   ListItem(DRV(DataTextField), DRV(DataValueField))
   DDL.Items.Add(item)
  Case Else
   Throw New Exception("Invalid DataSource type.")
 End Select
Next

Try
 DGI = CType(cell.NamingContainer, DataGridItem)
 item = DDL.Items.FindByValue(DGI.DataItem(DataField))
Catch RangeEx As IndexOutOfRangeException
 Throw New Exception("Specified DataField was not found.")
Catch OtherEx As Exception
 Throw New Exception(OtherEx.InnerException.ToString)
End Try

If Not item Is Nothing Then item.Selected = True
End Sub

  使用 DropDownColumn

  以上是建立 DropDownColumn 類所需的所有代碼,下面我們看一看如何在應用程式中使用該控制項。如果您是在家中學習,而且還沒有開始做,請將上面建立的命名空間編譯到 MyCustomColumn.dll 中,並將其複製到您想實驗的應用程式的 /bin 檔案夾中。本例中,我建立一個新的 Web 應用程式 UseCustomColumn,並在我的 /bin 目錄的 MyCustomColumn.dll 中添加一個引用。在 ASPX 檔案的頂部,添加 @Register 指令:

<%@ Register TagPrefix="dgg"
Namespace="MyCustomColumn"
Assembly="MyCustomColumn" %>
  請注意,新的 Datagrid 列類型不會為 Datagrid 出現在 Visual Studio .NET 屬性產生器中,因此您需要進入 HTML 視圖並在其中添加列聲明。確保 Datagrid 聲明位於一組 <form runat="server">...</form> 標記之中,這些標記用於處理 PostBack。ASPX 檔案的其餘部分應如下所示:

<%@ Page Language="vb"
AutoEventWireup="false"
Codebehind="WebForm1.aspx.vb"
Inherits="UseCustomColumn.WebForm1"
Trace="False" Debug="True"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>WebForm1</title>
<LINK rel="stylesheet" type="text/css" href="Styles.css">
<meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">
<meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<asp:DataGrid id="DataGrid1"
runat="server" CssClass="grid"
AutoGenerateColumns="False">
<Columns>
<asp:EditCommandColumn
EditText="Edit" CancelText="Cancel"
UpdateText="Update" />
<asp:BoundColumn
DataField="OrderID"
ReadOnly="True"
HeaderText="Order ID"/>
<asp:BoundColumn
DataField="ShipName"
HeaderText="Ship to"
ReadOnly="True"/>
<asp:BoundColumn
DataField="ShipCountry"
HeaderText="Country"
ReadOnly="True"/>
<dgg:DropDownColumn DataField="ShipVia" HeaderText="Ship Method" />
</Columns>
</asp:DataGrid>
</form>
</body>
</HTML>
  Datagrid 被綁定到 Northwind 樣本的 Orders 表,自訂 DropDownColumn 被綁定到 ShipVia 列。現在我只設定 DataField 屬性,因為剛剛綁定到一個簡單的 ArrayList,不需要 DataTextField 和 DataValueField 屬性。如果您有預定義的常數列表或者您需要一個快速設定選項的方法,ArrayList 選項最簡單。DropDownColumn 的 DataSource 在代碼中設定,首先引用 DropDownColumn:

Dim DDC As MyCustomColumn.DropDownColumn
DDC = CType(DataGrid1.Columns(4), MyCustomColumn.DropDownColumn)
Dim AL As New ArrayList
AL.Add("Shipping Company A")
AL.Add("Shipping Company B")
AL.Add("Shipping Company C")
DDC.DataSource = AL
  下面是運行此代碼的結果:



  接下來,我需要轉換該樣本以便使用資料庫中的活動表。ShipVia 是尋找表 Shippers 的外鍵,我在代碼中將其指定為 DropDownColumn 的 DataSource。我還需要改變 DropDownColumn 聲明,以包括與 Shippers 表中的相應欄位匹配的 DataTextField 和 DataValueField 名稱:

<dgg:DropDownColumn DataField="ShipVia" DataTextField="CompanyName"
DataValueField="ShipperID" HeaderText="Ship Method" />
  然後將兩個 Orders 表綁定到 Datagrid,將 Shippers 表綁定到自訂欄:

Dim SQL As String =
"SELECT OrderID, ShipName, ShipCountry, ShipVia FROM Orders"
Dim DA As SqlDataAdapter = New SqlDataAdapter(SQL, ConnStr)
Dim DS As New DataSet
DA.Fill(DS, "Orders")
'Dim Cmd As SqlCommand = New SqlCommand(SQL, Conn)
'Conn.Open()
'DataGrid1.DataSource = _
Cmd.ExecuteReader(CommandBehavior.CloseConnection)
DataGrid1.DataSource = DS.Tables("Orders").DefaultView
SQL = "SELECT ShipperID, CompanyName " & _
"FROM Shippers ORDER BY ShipperID"
DA.SelectCommand.CommandText = SQL
DA.Fill(DS, "Shippers")
DDC.DataSource = DS.Tables("Shippers").DefaultView
DataGrid1.DataBind()
  DataGridColumn 使用活動資料,根據 Orders 表中的值(1、2 或 3)自動選擇正確的項目,如下所示:




  使用 DropDownColumn 的最後一步是檢索選定的值以傳遞迴資料庫更新。為此,只需在儲存格內引用 DropDownList 控制項,並確定其 SelectedValue 屬性:

Private Sub DataGrid1_UpdateCommand( ByVal source As Object, _
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) _
Handles DataGrid1.UpdateCommand
 Dim CustomDDL As DropDownList = _
  CType(e.Item.Cells(4).Controls(0), DropDownList)
 Dim NewShip As Integer = CustomDDL.SelectedValue
 Dim OrderID As Integer = Int32.Parse(e.Item.Cells(1).Text)
 Dim SQL As String = "UPDATE Orders SET ShipVia=@Ship WHERE OrderID=@ID"
 Dim Conn As SqlConnection = New SqlConnection(ConnStr)
 Dim Cmd As New SqlCommand(SQL, Conn)
 Cmd.Parameters.Add(New SqlParameter("@Ship", NewShip))
 Cmd.Parameters.Add(New SqlParameter("@ID", OrderID))
 Conn.Open()
 Cmd.ExecuteNonQuery()
 Conn.Close()
 DataGrid1.EditItemIndex = -1
 BindGrid()
End Sub
  小結

  上文概述了如何以 DataGridColumn 為父類型建立一個新類型、如何進行資料繫結以及如何將其應用到實際應用程式中。這隻是可重複使用的 Datagrid 列的一個樣本,因此,您需要檢查您自己的應用程式,以確定哪些重複的功能可以封裝到其自己的自訂 Datagrid 列中。您可以開發自己的列,以解決常見問題(例如,在列中顯示 DropDownList),或滿足您公司的特殊需要。您也不必拘泥於本文的樣本,只在自訂欄中包含一個 ASP.NET 控制項,您可以編寫更複雜的結構,例如將一系列控制項、第三方內容或整個 Datagrid 控制項嵌套到列中,以表現多層資訊。總之,您可以充分發揮您的想象力。

  5個內建的列類型非常有用,它們可以滿足使用 Datagrid 控制項進行顯示的大多數情況下的需要。現在並沒有開發您自己的控制項,只是將一些有意義的內容隨便放到 TemplateColumn 中。建立自訂欄使您可以突破這些限制,在您的 Datagrid 應用程式中添加豐富的功能。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.