Picasa Style Photo Album Using ListView Control in ASP.Net 3.5
今天看到一篇比較好的文章,特此翻譯出來,原文地址:http://www.codedigest.com/Articles/ASPNET/232_Picasa_Style_Photo_Album_Using_ListView_Control_in_ASPNet_35.aspx
源碼下載: http://www.codedigest.com/Articles/ArticleFiles/ZIPS/232.zip
簡介:
ListView 是ASP.Net 3.5中新發布的數據綁定控件. 我在 ListView Control in ASP.Net 3.5 一文中初步介紹了其用法.ListView是數據綁定控件中最靈活的控件,可以用任何自定義格式顯示數據。此文將用ListView創建Google’s Picasa 類型相冊. 但是 picasa 功能強大,我們只是實現顯示相冊和圖片。
預覽:
不需要介紹Google’s Picasa 了,在相片共享方面它已得到廣泛應用。Picasa 是基於web 的 相冊,用戶可以再此創建相冊、上傳相片,與親朋好友共享。閱讀此片文章之前,最好對它的工作方式做一些瞭解,至少要知道我們用ListView要實現的功能。Picasa 顯示相冊的列表,以其中一種相片做爲封面(圖1)。點擊相冊,將會進入顯示上傳相片縮略圖的列表界面(圖2)。點擊縮略圖,可以看到原始相片。在相片全圖下,可以向前後導航(圖3). 我不善於UI設計; 對如此差的UI表示抱歉。
接下來,我們將用ListView實現Picasa類似的相冊。如前所說,Picasa提供了很多功能,我們僅僅實現上面所說的功能,來幫助理解ListView的靈活性。
數據庫設計:
進入實現之前,幫助理解,我們將看看存儲相冊信息的數據庫如何設計。參考下圖,數據庫包含2張表:
1. Album(相冊) – 存儲相冊信息。 DefaultPhotID字段存儲封面相片。
2. PhotAlbum(相片) –包含相冊的所有信息。Photo列存儲相片路徑。根據需要你可以改變字段大小。
接下來,進入實現部分。
創建相冊列表:
相冊頁面,我們將每行平鋪顯示3個相冊,例如,水平重複顯示相片,參考圖1。要建立新相冊,在ListView的最下面有個“Create New Album” 鏈接。點擊此鏈接,將移動到ListView的最後一列,下面我們來看看如何實現。
要在ListView中顯示數據,首先,我們必須要定義好如下模版,Layout Template 和 Item Template,可在ListView Control in ASP.Net 3.5 瞭解更多。
另外,我們用Group Template 來平鋪分組。 用GroupItemCount屬性來限制每行顯示項的數量。
要顯示“Create New Album” 鏈接, 要用到ListView 的另一個模版InsertItemTemplate。InsertItemTemplate中的內容將被顯示爲新增項。 設置InsertItemPosition屬性 決定InsertItemTemplate的顯示位置。此文中是LastItem。ListView 最終代碼如下:
<asp:ListView ID="lvAlbums" runat="server"
DataSourceID="SqlDataSource1" GroupItemCount="3"
InsertItemPosition="LastItem">
<LayoutTemplate>
<table border="1">
<tr ID="groupPlaceholder" runat="server">
tr>
table>
LayoutTemplate>
<GroupTemplate>
<tr>
<td ID="itemPlaceholder" runat="server">
td>
tr>
GroupTemplate>
<ItemTemplate>
<td id="Td3" width="150px" height="150px" align="center" style="background-color: #e8e8e8;color: #333333;">
<asp:HiddenField ID="hfPhotoID" runat="server" Value='<%# Eval("DefaultPhotID") %>' />
<a href='<%# "Photos.aspx?AlbumID="+Eval("AlbumID") %>'>
<asp:Image CssClass="Timg" runat="server" ID="imPhoto" ImageUrl='<%# "ThumbNail.ashx?ImURL="+Eval("Photo") %>' />
a>
<br />
<b><asp:Label ID="lblAlbumName" runat="server" Text='<%# Eval("AlbumName") %>'>asp:Label> b>
td>
ItemTemplate>
<InsertItemTemplate>
<td id="Td3" width="150px" height="150px" runat="server" align="center" style="background-color: #e8e8e8;color: #333333;">
<a href="CreateAlbum.aspx">
Create New Album
a>
td>
InsertItemTemplate>
asp:ListView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="SELECT Album.AlbumID, Album.DefaultPhotID, Album.AlbumName, PhotAlbum.Photo FROM Album INNER JOIN PhotAlbum
ON Album.DefaultPhotID = PhotAlbum.PhotoID">
asp:SqlDataSource>
在上面代碼中, 我設置GroupItemCount 爲 3。增加這個值可以增加相冊每行顯示的數量。數據綁定用的是SqlDataSource。
既然,相冊封面爲相冊中的相片(Album表DefaultPhotID列), 要將縮略圖做爲相冊封面. 要這樣做, 就要用HttpHandler[ThumbNail.ashx] 將原始相片轉換爲縮略圖.
下面就是HttpHanlder 實現從原始圖生成(100x100)縮略圖.
<%@ WebHandler Language="C#" Class="ThumbNail" %> using System; using System.Web; using System.Drawing; using System.IO; public class ThumbNail : IHttpHandler { public void ProcessRequest (HttpContext context) { string imageurl = context.Request.QueryString["ImURL"]; string str = context.Server.MapPath(".") + imageurl; Bitmap bmp = new Bitmap(str); System.Drawing.Image img = bmp.GetThumbnailImage(100, 100, null, IntPtr.Zero); MemoryStream ms = new MemoryStream(); img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); byte[] bmpBytes = ms.GetBuffer(); img.Dispose(); ms.Close(); context.Response.BinaryWrite(bmpBytes); context.Response.End(); } public bool IsReusable { get { return false; } } }
下一步, 點擊 “Create New Album” 鏈接到CreateAlbum.aspx 頁面創建新相冊. 一旦相冊建立之後, 將顯示(ImageUpload.aspx) 頁面進行相片上傳. 參考下圖:
CreateAlbum.aspx
ImageUpload.aspx
我不打算討論這些頁面的實現方法,不在此文範疇。你可以下載代碼查看。
最後,當用戶點擊相冊,將跳到 (photos.aspx)頁面,在此顯示相片縮略圖列表。
Displaying photos in Thumbnail View:
在photos.aspx 頁面, 將從QueryString中獲取AlbumId。同樣, 用GroupTemplatee每行顯示3個.參考圖2. 在圖2,相片縮略圖列表(右邊內容)又ListView顯示,而左邊的顯示相冊信息的內容是分開處理的.
要顯示每幅照片的縮略圖, 同樣用HttpHandler [ThumbNail.ashx]. 可以考慮在上傳時就存儲縮略圖,可以改進性能。本方法中,用戶每次查看相冊都會生成縮略圖,這可以通過在上傳時就存儲縮略圖才避免。可以參考此處 Upload image to file system and create thumbnail image on the fly in C# and ASP.Net
最終, ListView 類似如,
<asp:ListView ID="lvPhotos" runat="server" DataKeyNames="AlbumID" DataSourceID="SqlDataSource1" GroupItemCount="3"> <LayoutTemplate> <table ID="groupPlaceholderContainer" runat="server" border="0" cellpadding="0" cellspacing="0"> <tr ID="groupPlaceholder" runat="server"> tr> table> LayoutTemplate> <GroupTemplate> <tr ID="itemPlaceholderContainer" runat="server"> <td ID="itemPlaceholder" runat="server"> td> tr> GroupTemplate> <ItemTemplate> <td runat="server" align="center" style="background-color: #e8e8e8;color: #333333;"> <a href='<%# "PhotoViewer.aspx?PhotoID="+Eval("PhotoID")+"&AlbumID="+ Eval("AlbumID") %>'> <asp:Image CssClass="Timg" runat="server" ID="imPhoto" ImageUrl='<%# "ThumbNail.ashx?ImURL="+Eval("Photo") %>' /> a> td> ItemTemplate> asp:ListView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>" SelectCommand="SELECT [PhotoID], [Photo], [PhotoName], [AlbumID] FROM [PhotAlbum] WHERE ([AlbumID] = @AlbumID) ORDER By [PhotoID] ASC" onselected="SqlDataSource1_Selected"> <SelectParameters> <asp:QueryStringParameter DefaultValue="1" Name="AlbumID" QueryStringField="AlbumID" Type="Int32" /> SelectParameters> asp:SqlDataSource>
同樣用SqlDataSource做爲數據綁定源。
要顯示全圖,用戶點擊縮略圖將加載全圖,帶有next和previous按鈕. 下節我們會實現這個功能。
顯示全圖:
點擊縮量圖將加載ListView中的全圖,(參考PhotoViewer.aspx) 以AlbumId 和PhotoID 做爲參數。參考圖 3. 同時還顯示next 和previous 按鈕來做相片導航。不同於其他兩個頁面,我們用代碼進行數據綁定。
在這種情況下,我們每次在ListView中顯示一張相片,如圖3所示。同樣用GroupTemplate 在ListView顯示相片。
說明:
也可以不用GroupTemplate. 用GroupTemplate,我們可以用GroupItemCount 屬性來增加每次顯示的相片的數量 .
Next 和 Previous 按鈕在DataPager中顯示. 閱讀我的文章- Paging in ListView in ASP.Net 3.5 ,瞭解更多用DataPager分頁ListView.
所以, ListView應該像這樣,
<table> <tr> <td> <asp:ListView ID="lvPhotoViewer" runat="server" GroupItemCount="1"> <LayoutTemplate> <table ID="groupPlaceholderContainer" runat="server" border="1"> <tr ID="groupPlaceholder" runat="server"> tr> table> LayoutTemplate> <ItemTemplate> <td id="Td4" align="center" style="background-color: #eeeeee;"> <asp:Image runat="server" ID="imPhoto" Height="450px" Width="450px" ImageUrl='<%# "~"+Eval("Photo") %>' /> <br /> <asp:Label ID="DefaultPhotIDLabel" runat="server" Text='<%# Eval("PhotoName") %>' /> td> ItemTemplate> <GroupTemplate> <tr ID="itemPlaceholderContainer" runat="server"> <td ID="itemPlaceholder" runat="server"> td> tr> GroupTemplate> asp:ListView> td> tr> <tr> <td align="center"> <asp:DataPager ID="DataPager1" runat="server" PagedControlID="lvPhotoViewer" PageSize="1" onprerender="DataPager1_PreRender"> <Fields> <asp:NextPreviousPagerField ButtonType="Link" PreviousPageText="<< " NextPageText=" >>" /> Fields> asp:DataPager> td> tr> table>
CS代碼:
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { string photoID = Request.QueryString["PhotoID"]; string albumID = Request.QueryString["AlbumID"]; ViewState["hfAlbumID"] = albumID; //Get Page number by passing photo id int index = GetPageNumber(int.Parse(photoID), int.Parse(albumID)); DataPager1.SetPageProperties(index, 1, true); } } /// <summary> /// Since the pagesize is 1 the row number can be taken as page number /// summary> /// <param name="PhotoID">param> /// <param name="AlbumID">param> /// <returns>returns> public int GetPageNumber(int PhotoID,int AlbumID) { SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString); con.Open(); SqlCommand com = new SqlCommand("SELECT PageNumber FROM (SELECT row_number() Over (order by photoid asc) AS PageNumber,photoid,Albumid "+ " FROM PhotAlbum where Albumid=" + AlbumID.ToString() + ") As Photos where photoid=" + PhotoID.ToString() + " and Albumid=" + AlbumID.ToString(), con); SqlDataReader dr = com.ExecuteReader(); int pageno = 1; if (dr.Read()) { pageno = int.Parse(dr["PageNumber"].ToString()); } dr.Close(); con.Close(); return (pageno - 1); } public DataTable GetPhoto(string query) { SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString); SqlDataAdapter ada = new SqlDataAdapter(query, con); DataTable dtEmp = new DataTable(); ada.Fill(dtEmp); return dtEmp; } protected void DataPager1_PreRender(object sender, EventArgs e) { lvPhotoViewer.DataSource = GetPhoto("Select * from PhotAlbum where AlbumID = " + ViewState["hfAlbumID"].ToString()); lvPhotoViewer.DataBind(); }
既然我們每次顯示一張相片,例如 PageSize 爲1,從SqlServer 2005中獲取的page number 和 Row number 是一樣的. 所以, GetPageNumber() 方法將返回縮略圖的Row_Number() ,用來顯示ListView的特定頁.
說明:
Row_Number() 只適用於Sql Server 2005及以上版本. 我用行內查詢綁定到數據庫. 你可以用存儲過程來提高性能,以及避免sql注入攻擊。
本文代碼下載:Download Source