在ASP.NET 2.0中操作資料之五十三:在Data Web控制項顯示位元據_自學過程

來源:互聯網
上載者:User

導言:

  在前面的教程我們闡述了應用程式處理位元據的2種模式,以及使用FileUpload 控制項從瀏覽器向伺服器檔案系統上傳檔案。當檔案上傳並儲存在檔案系統裡時,應在相應的資料庫記錄裡儲存該檔案的儲存路徑。

  我們先來看如何為終端使用者提供位元據。怎樣展示位元據呢?這取決於其類型。比如圖片,我們將其顯示為image;如果是PDFs,Microsoft Word文檔、ZIP檔案或其它類型的資料,或許提供一個“Download”連結比較妥當。

  在本節,我們看如何在GridView和DetailsView一類的資料Web控制項裡呈現位元據,在後面的教程我們將注意力轉向將上傳檔案和資料庫聯絡起來。

第一步:提供BrochurePath值

  表Categories的Picture列儲存相關類的圖片資訊。具體的講,為16色的低品質位元影像,大小為172乘120像素,約11 KB。另外還包括一個約78位元組的OLE前序,在顯示圖片的時候需要將其剝離。為什麼會有前序資訊呢?因為資料庫Northwind源於微軟的Access資料庫。在Access裡位元據OLE類型來儲存的,該類型會添加前序。現在,我們看如何從圖片剝離前序,以便顯示。在後面的教程我們將建立一個介面,將帶前序的這些位元影像替換為不帶前序的等價的JPG圖片。

  前面我們考察了如何使用FileUpload控制項,讓我們繼續為伺服器檔案系統添加檔案。不過暫時不用更新Categories表的BrochurePath列,那是下一章的內容。我們現在需要手工為BrochurePath賦值。

  在本教程,當你下載東西時,可以看到在~/Brochures7檔案夾有7個PDF小冊子,每個小冊子對應一個種類,Seafood除外。我故意沒為Seafood提供PDF小冊子,以便探討如何處理某些記錄沒有附帶位元據的情況。在伺服器總管裡右鍵點擊Categories,選“查看錶資料”,輸入檔案路徑,如圖1所示。由於Seafood類沒有圖片,將其BrochurePath的值設為“NULL”。 


圖1:手工為表Categories的BrochurePath列鍵入值

第2步:在GridView裡添加一個下載連結

  當為表Categories的BrochurePath列賦值後,我們準備建立一個GridView用於展示每個種類,並附帶一個連結下載每個類的小冊子。在第4步我們將擴充GridView以顯示每個類的圖片。

  開啟BinaryData檔案夾的DisplayOrDownloadData.aspx頁面並進入設計模式,從工具箱裡拖一個GridView控制項到頁面,設其ID為Categories,從其智能標籤選擇綁定到一個名為CategoriesDataSource的ObjectDataSource控制項。該控制項調用類CategoriesBLL的GetCategories()方法。


圖2:建立一個名為CategoriesDataSource的ObjectDataSource控制項


圖3:設定ObjectDataSource使用CategoriesBLL類


圖4:調用GetCategories()方法

  完成設定後,Visual Studio自動的為CategoryID, CategoryName, Description, NumberOfProducts和BrochurePath產生BoundField。移除NumberOfProducts,因為GetCategories()方法用不上,同樣將CategoryID移除了。分別把CategoryName和 BrochurePath的HeaderText屬性改為“Category”和“Brochure”。做上述修改後,你的GridView and ObjectDataSource的聲明代碼看起來應該像下面的這樣:

<asp:GridView ID="Categories" runat="server" AutoGenerateColumns="False" DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource" EnableViewState="False"> <Columns> <asp:BoundField DataField="CategoryName" HeaderText="Category"  SortExpression="CategoryName" /> <asp:BoundField DataField="Description" HeaderText="Description"  SortExpression="Description" /> <asp:BoundField DataField="BrochurePath" HeaderText="Brochure"  SortExpression="BrochurePath" /> </Columns></asp:GridView><asp:ObjectDataSource ID="CategoriesDataSource" runat="server" OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories" TypeName="CategoriesBLL"></asp:ObjectDataSource>

  在瀏覽器查看該頁(如圖5)。列出了所有的8個類,除了Seafood,其它7個類的BoundField列裡顯示各自的BrochurePath值。由於Seafood的BrochurePath為NULL值,看起來為空白格。


圖5:顯示了每個類別的Name, Description和BrochurePath值

  與其顯示BrochurePath的text值,不如建立一個指向小冊子的連結。移除BrochurePath,代之以HyperLinkField。設它的HeaderText屬性為“Brochure”,Text屬性為“View Brochure”, DataNavigateUrlFields屬性為“ BrochurePath”。

 


圖6:添加一個指向BrochurePath的HyperLinkField

  這樣將在GridView裡添加一列連結,如圖7所示。點“View Brochure”時要麼直接在瀏覽器顯示PDF,要麼提示使用者下載該檔案。這取決於瀏覽器的設定以及是否安裝了PDF閱讀器。


圖7:點擊“View Brochure”訪問某類的Brochure


圖8:顯示某類的PDF檔案

隱藏無小冊子圖片的類的“View Brochure” 文本

  如圖7所示,不管某個類的BrochurePath是否為NULL值,名為BrochurePath的HyperLinkField都呈現為其Text屬性(“View Brochure”) 。當然,如果BrochurePath為NULL值,連結只顯示為文本(而不帶底線),就像Seafood類一樣(見圖7)。與顯示文本“View Brochure”相比,更為可取的是將那些BrochurePath值為空白的類顯示為“No Brochure Available”。

  為達此目的,我們需要用到TemplateField,使其產生一個基於BrochurePath值的合適的結果。我們先來看看如何?,就像在教程之12《在GridView控制項中使用TemplateField》一樣。

  在“編輯列”對話方塊裡選中名為BrochurePath的HyperLinkField,再點“Convert this field into a TemplateField”連結,將其轉換為TemplateField。 


圖9:將HyperLinkField轉換為TemplateField

  這樣將建立一個TemplateField,其ItemTemplate模板包含一個HyperLink Web控制項,該控制項的NavigateUrl屬性為BrochurePath值。用下面的代碼將其替換掉:

<asp:TemplateField HeaderText="Brochure"> <ItemTemplate> <%# GenerateBrochureLink(Eval("BrochurePath")) %> </ItemTemplate></asp:TemplateField>

  然後,在ASP.NET頁面的“後台代碼”裡添加一個protected類型的GenerateBrochureLink方法,它接受一個輸入參數並返回一個字串。

protected string GenerateBrochureLink(object BrochurePath){ if (Convert.IsDBNull(BrochurePath)) return "No Brochure Available"; else return string.Format(@"<a href=""{0}"">View Brochure</a>",  ResolveUrl(BrochurePath.ToString()));}

  該方法判斷傳入的值是否為NULL。如果是,則返回一個訊息指出該類沒有小冊子檔案;相反,如果傳入值不為空白,將顯示為一個連結。我們注意到,當BrochurePath值不為空白時,將調用ResolveUrl(url)方法。該方法的作用在於將傳入的相對路徑轉換為實體路徑。比如應用程式的根目錄在/Tutorial55,ResolveUrl("~/Brochures/Meats.pdf")返回的路徑是/Tutorial55/Brochures/Meat.pdf.

圖10為經過上述修改後的介面。我們注意到Seafood類的BrochurePath列現在顯示為文本“No Brochure Available”.


圖10:沒有小冊子的類將顯示為文本“No Brochure Available”

第3步:新增頁面以顯示類的圖片

  當使用者訪問一個ASP.NET頁面時,他將接收該頁面的HTML代碼。HTML代碼僅僅包含了text文本,而並不包含任何的位元據。任何的位元據,比如圖片,音樂檔案、Flash程式、Windows Media Player視頻等,以獨立資源的形式存放於伺服器。

  HTML只包含了這些檔案的引用,並不包含這些檔案本身。

  比如,在HTML裡<img>元素用來引用一張圖片,其src屬性指向該圖片檔案,如:
<img src="MyPicture.jpg" ... />

  當瀏覽器收到HTML代碼時,它向伺服器發送擷取圖片的請求並將其顯示在瀏覽器中,該模式對所有的位元據都適用。在第2步中,我們沒有在頁面的HTML標記裡將小冊子顯示在瀏覽器,而是在HTML標記裡提供一個超連結,當點擊它是,導致瀏覽器直接請求PDF檔案。

  為了顯示或允許使用者下載儲存在資料庫中的位元據,我們需要另外建立一個頁面,用於從資料庫返回所需的資料。對我們的應用程式而言,由於直接儲存在資料庫中的位元據只有一項——類的圖片,所以我們需要一個頁面,當需要時從資料庫返回某個特定類的圖片。

  在BinaryData檔案夾添加一個DisplayCategoryPicture.aspx頁面,注意不要使用主版頁面。該頁面接受一個包含CategoryID值的查詢字串,返回Picture列的位元據。由於該頁只返回位元據,所以我們不需要頁面的HTML部分有任何代碼。進入頁面的“源碼”模式,刪除頁面的所有代碼,只保留<%@ Page %>部分。也即:DisplayCategoryPicture.aspx頁面的聲明代碼應該只由如下的單獨行構成:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DisplayCategoryPicture.aspx.cs" Inherits="BinaryData_DisplayCategoryPicture" %>

如果<%@ Page %>裡包含有MasterPageFile屬性,將其刪除,同時在後台代碼類的Page_Load事件處理器裡添加如下代碼:

protected void Page_Load(object sender, EventArgs e){ int categoryID = Convert.ToInt32(Request.QueryString["CategoryID"]); // Get information about the specified category CategoriesBLL categoryAPI = new CategoriesBLL(); Northwind.CategoriesDataTable categories = categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID); Northwind.CategoriesRow category = categories[0]; // Output HTTP headers providing information about the binary data Response.ContentType = "image/bmp"; // Output the binary data // But first we need to strip out the OLE header const int OleHeaderLength = 78; int strippedImageLength = category.Picture.Length - OleHeaderLength; byte[] strippedImageData = new byte[strippedImageLength]; Array.Copy(category.Picture, OleHeaderLength, strippedImageData, 0, strippedImageLength);  Response.BinaryWrite(strippedImageData);}

  代碼先讀取查詢字串的CategoryID值,並對名為categoryID的變數賦值。然後,通過調用CategoriesBLL類的
GetCategoryWithBinaryDataByCategoryID(categoryID)方法擷取圖片資料,再通過Response.BinaryWrite(data)方法向用戶端返回資料。不過在此之前先要剝離資料的OLE前序。怎麼實現呢?建立一個名為strippedImageData的byte數組,它包含的位元組剛好比Picture列的資料少78。而Array.Copy方法將從category.Picture的第78個位元組開始複製資料(即剛好剝離OLE前序)。

  代碼中的Response.ContentType屬性指定了要返回內容的MIME type,以便瀏覽器知道如何顯示資料。由於Categories表的Picture列儲存的是位元影像圖片,故在這裡,位元影像圖片的MIME type是(image/bmp). 如果你忽視了MIME type,絕大多數瀏覽器也可以正確的顯示映像,因為,它們能根據影像檔的位元據的內容而推斷其類型。即便如此,還是儘可能的使用MIME type。

建立頁面後,可以訪問頁面

DisplayCategoryPicture.aspx?CategoryID=categoryID來查看某個特定類的圖片。圖11顯示的是Beverages類的圖片,頁面為
DisplayCategoryPicture.aspx?CategoryID=1.


圖11:顯示類Beverages的圖片

  有時候,當你訪問DisplayCategoryPicture.aspx?CategoryID=categoryID頁面時,有可能顯示這樣的提示:“Unable to cast object of type 'System.DBNull' to type 'System.Byte[]'”。原因有可能是如下2方面。第一,表Categories的Picture列允許為NULL值,而DisplayCategoryPicture.aspx page頁面總是假定傳入的為非NULL值。當Picture為NULL值時,不能直接存取CategoriesDataTable的Picture屬性。如果你允許Picture為NULL值,添加如下代碼:

if (category.IsPictureNull()){ // Display some "No Image Available" picture Response.Redirect("~/Images/NoPictureAvailable.gif");}else{ // Send back the binary contents of the Picture column // ... Set ContentType property and write out ... // ... data via Response.BinaryWrite ...}

  上述代碼假定在Images檔案夾裡存在名為NoPictureAvailable.gif的圖片,當某個類沒有圖片時,就顯示該圖片。

  另一種情況:當你在嚮導裡選用“使用SQL語句”的模式再次運行主查詢時,它將影響GetCategoryWithBinaryDataByCategoryID方法的SELECT命令返回的列(換句話說,主查詢沒有返回Picture列,再次運行主查詢時將使GetCategoryWithBinaryDataByCategoryID方法也不會返回Picture列)。所以,應確保GetCategoryWithBinaryDataByCategoryID方法的SELECT命令返回Picture列。

  注意:每次訪問DisplayCategoryPicture.aspx頁面時,都會訪問資料庫並返回所需的圖片。如果圖片自最近一次訪問以來沒有改變過的話,這樣每次訪問資料庫再返回資料的做法效率是不高的。幸運的是,HTTP允許使用conditional GETs,這樣的話,用戶端使HTTP請求發送一個If-Modified-Since HTTP header。If-Modified-Since HTTP header包含了用戶端最近一次從伺服器擷取的資料以及時間。如果請求的內容沒有發生改變,伺服器響應為Not Modified status code (304),並不返回請求的內容。簡而言之,如果請求的資源自最近一次訪問以來沒發送改變的話,伺服器將不會回傳該資源,以達到減輕伺服器負荷的目的。

第四步:在GridView控制項裡顯示Category Pictures

  現在我們有一個web頁面來顯示某個特定種類的圖片的。通過Image Web控制項或 HTML <img>元素來指向DisplayCategoryPicture.aspx?CategoryID=categoryID頁面,從而達到顯示該圖片的目的。我們可以在GridView控制項或DetailsView控制項的 ImageField裡顯示圖片。ImageField的DataImageUrlField屬性、DataImageUrlFormatString屬性與HyperLinkField的DataNavigateUrlFields屬性、DataNavigateUrlFormatString屬性用法相似。

  讓我們對DisplayOrDownloadData.aspx頁面裡名為Categories的GridView控制項進行擴充。添加一個ImageField,設其DataImageUrlField屬性為CategoryID;
DataImageUrlFormatString屬性為DisplayCategoryPicture.aspx?CategoryID={0}。這樣將為GridView增加一列,呈現為一個<img>元素,其src屬性為DisplayCategoryPicture.aspx?CategoryID={0},其中{0}將由GridView row的CategoryID值填充。


圖12:為GridView控制項添加一個ImageField

添加完成後,你的GridView控制項的聲明代碼看起來應像下面這樣:

<asp:GridView ID="Categories" runat="server" AutoGenerateColumns="False" DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource" EnableViewState="False"> <Columns> <asp:BoundField DataField="CategoryName" HeaderText="Category"  SortExpression="CategoryName" /> <asp:BoundField DataField="Description" HeaderText="Description"  SortExpression="Description" /> <asp:TemplateField HeaderText="Brochure">  <ItemTemplate>  <%# GenerateBrochureLink(Eval("BrochurePath")) %>  </ItemTemplate> </asp:TemplateField> <asp:ImageField DataImageUrlField="CategoryID"  DataImageUrlFormatString="DisplayCategoryPicture.aspx?CategoryID={0}"> </asp:ImageField> </Columns></asp:GridView>

花幾分鐘在瀏覽器裡查看該頁面,注意每一行記錄現在都包含一張該類的圖片。


圖13:每一行記錄都顯示一張圖片

總結:

  在本節我們探討了如何顯示位元據,資料是如何呈現的取決於它的類型。對PDF小冊子檔案來說,我們提供了一個“View Brochure”連結,當點擊它時,直接將使用者指向PDF小冊子檔案。對某個種類的圖片,我們先是建立一個頁面來從資料庫擷取並顯示它,然後再在一個GridView控制項裡顯示圖片。既然看到了如何展示位元據,我們準備探討如何對其展開插入、更新、刪除操作。接下來的教程我們看如何將上傳檔案和相應的資料庫記錄聯絡起來。然後,再探討如何更新現存的位元據,以及當刪除資料庫記錄時如何刪除相應的位元據。

  祝編程快樂!

作者簡介

  本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創始人,自1998年以來一直應用 微軟Web技術。大家可以點擊查看全部教程《[翻譯]Scott Mitchell 的ASP.NET 2.0資料教程》,希望對大家的學習ASP.NET有所協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.