翻译: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

你可能感兴趣的:(ListView)