翻译:Picasa Style Photo Album Using ListView Control in ASP.Net 3.5

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表示抱歉。

图1 - 相册image

图2 – 相册缩略图image

图3 – 相片image

接下来,我们将用ListView实现Picasa类似的相册。如前所说,Picasa提供了很多功能,我们仅仅实现上面所说的功能,来帮助理解ListView的灵活性。

数据库设计:

     进入实现之前,帮助理解,我们将看看存储相册信息的数据库如何设计。参考下图,数据库包含2张表:

1. Album(相册) – 存储相册信息。 DefaultPhotID字段存储封面相片。

2. PhotAlbum(相片) –包含相册的所有信息。Photo列存储相片路径。根据需要你可以改变字段大小。

image

接下来,进入实现部分。

创建相册列表:

     相册页面,我们将每行平铺显示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

image

ImageUpload.aspx

image

我不打算讨论这些页面的实现方法,不在此文范畴。你可以下载代码查看。

最后,当用户点击相册,将跳到 (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

posted @ 2009-05-23 14:48  流泉飞石  阅读(599)  评论(0编辑  收藏  举报