In this
article, we will see how to create a Picture Album using the ListView control.
We will explore the GroupTemplate of ListView and explore how we can group
multiple images together in the ListView, thereby creating an album effect.
In one of
the previous articles Save and
Retrieve Images from the Database using ASP.NET 2.0 and ASP.NET 3.5 we
had discussed how to use image handlers to save and retrieve images in the
database. In this article, we will build on that concept and use the same
technique to display images in a ListView.
We will
learn how to upload an image and then display the uploaded image on the same
page in an ‘album mode’ using the ListView. At the end of this article, you
will also learn how to use the different templates of a ListView. If you are
unfamiliar with the ListView control, I suggest you to read my article Exploring the
ListView control in ASP.NET 3.5 to get an understanding of the
same. To keep the article simple and easy to understand, I have not covered any
validations associated with image control or other control. The article also
does not suggest you best practices. In this article, we will only discuss how
to read images from the database and display it in the ListView control, and
that would be the focus for this article. I assume you have some knowledge of
creating ASP.NET 3.5 websites. We will be using Visual Studio 2008.
Let us
start off by first creating a sample database and adding a table to it. We will
call the database ‘PictureAlbum’ and the table will be called ‘Album’. This
table will contain an image column along with some other columns. Run the
following script in your SQL 2005 Query window (or server explorer) to
construct the database and the table.
CREATE
DATABASE [PictureAlbum]
GO
USE
[PictureAlbum]
GO
CREATE
TABLE Album
(
pic_id int
IDENTITY NOT NULL,
picture_tag
varchar(50),
pic image
)
Step 1: Create a new ASP.NET website. In the
code-behind, add the following namespace
C#
using
System.Data.SqlClient;
VB.NET
Imports
System.Data.SqlClient
Step 2: Drag and drop two label and one textbox control.
Also drag drop a FileUpload control and a button control to upload the selected
image on button click. As mentioned earlier, there are no validations
performed. The source would look similar to the following:
<html
xmlns="http://www.w3.org/1999/xhtml">
<head
runat="server">
<title>Untitled
Page</title>
</head><body>
<form
id="form1" runat="server">
<div>
Image
<asp:Label
ID="lblTags" runat="server"
Text="Tags"></asp:Label>
<asp:TextBox
ID="txtTags"
runat="server"></asp:TextBox>
<br
/>
<asp:Label
ID="lblImage" runat="server" Text="Upload
Picture"></asp:Label>
<asp:FileUpload
ID="imgUpload" runat="server" />
<br
/>
<br />
<asp:Button
ID="btnSubmit" runat="server"
onclick="btnSubmit_Click"
Text="Submit"
/>
 <asp:Label
ID="lblResult" runat="server"
ForeColor="#0066FF"></asp:Label>
<br
/>
<hr
/>
</div>
</form>
</body>
</html>
Also in the
web.config, add a <connectionStrings> tag as displayed below:
<connectionStrings>
<add
name="albumConnString" connectionString="Data Source=(local);
Initial Catalog = PictureAlbum; Integrated
Security=True;"providerName="System.Data.SqlClient" />
</connectionStrings>
Step 3: In the button click event, add the following
code:
C#
protected
void btnSubmit_Click(object sender, EventArgs e)
{
SqlConnection
connection = null;
try
{
FileUpload
img = (FileUpload)imgUpload;
Byte[]
imgByte = null;
if
(img.HasFile && img.PostedFile != null)
{
//To create a PostedFile
HttpPostedFile
File = imgUpload.PostedFile;
//Create
byte Array with file len
imgByte =
new Byte[File.ContentLength];
//force the
control to load data in array
File.InputStream.Read(imgByte,
0, File.ContentLength);
}
// Insert
the picture tag and image into db
string conn
= ConfigurationManager.ConnectionStrings["albumConnString"].ConnectionString;
connection
= new SqlConnection(conn);
connection.Open();
string sql
= "INSERT INTO Album(picture_tag,pic) VALUES(@tag,@pic) SELECT
@@IDENTITY";
SqlCommand
cmd = new SqlCommand(sql, connection);
cmd.Parameters.AddWithValue("@tag",
txtTags.Text);
cmd.Parameters.AddWithValue("@pic",
imgByte);
int id =
Convert.ToInt32(cmd.ExecuteScalar());
lblResult.Text
= String.Format("Picture ID is {0}", id);
}
catch
{
lblResult.Text
= "There was an error";
}
finally
{
connection.Close();
}
}
VB.NET
Protected
Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim
connection As SqlConnection = Nothing
Try
Dim img As FileUpload = CType(imgUpload, FileUpload)
Dim imgByte
As Byte() = Nothing
If
img.HasFile AndAlso Not img.PostedFile Is Nothing Then
'To create
a PostedFile
Dim File As
HttpPostedFile = imgUpload.PostedFile
'Create
byte Array with file len
imgByte =
New Byte(File.ContentLength - 1){}
'force the
control to load data in array
File.InputStream.Read(imgByte,
0, File.ContentLength)
End If
' Insert
the picture tag and image into db
Dim conn As
String = ConfigurationManager.ConnectionStrings("albumConnString").ConnectionString
connection
= New SqlConnection(conn)
connection.Open()
Dim sql As
String = "INSERT INTO Album(picture_tag,pic) VALUES(@tag,@pic) SELECT
@@IDENTITY"
Dim cmd As
SqlCommand = New SqlCommand(sql, connection)
cmd.Parameters.AddWithValue("@tag",
txtTags.Text)
cmd.Parameters.AddWithValue("@pic",
imgByte)
Dim id As
Integer = Convert.ToInt32(cmd.ExecuteScalar())
lblResult.Text
= String.Format("Picture ID is {0}", id)
Catch
lblResult.Text = "There was an error"
Finally
connection.Close()
End Try
End Sub
In the code
above, we are creating a byte array equal to the length of the file. The byte
array will store the image. We then load the image data into the array. The
record containing the Picture Tags and Image is then inserted into the database
using the ADO.NET code. The ID inserted is returned back using the @@Identity.
We will shortly use this ID and pass it as a query string parameter to the
ShowImage handler. The image will then be fetched against the Picture ID
(pic_id). If you run the application as of now, you should be able to upload
the images to the database.
Step 4: In order to display the image on the page, we
will create an Http handler. To do so, right click project > Add New
Item > Generic Handler > ShowImage.ashx. In the code shown below,
we are using the Request.QueryString[“id”] to retrieve the PictureID(pic_id)
from the handler url. The ID is then passed to the ‘ShowAlbumImage()’ method
where the image is fetched from the database and returned in a MemoryStream
object. We then read the stream into a byte array. Using the
OutputStream.Write(), we write the sequence of bytes to the current stream and
you get to see your image.
C#
<%@
WebHandler Language="C#" Class="ShowImage" %>
using System;
using
System.Configuration;
using System.Web;
using
System.IO;
using System.Data;
using
System.Data.SqlClient;
public
class ShowImage : IHttpHandler
{
public void
ProcessRequest(HttpContext context)
{
Int32
picid;
if
(context.Request.QueryString["id"] != null)
picid =
Convert.ToInt32(context.Request.QueryString["id"]);
else
throw new
ArgumentException("No parameter specified");
context.Response.ContentType = "image/jpeg";
Stream strm
= ShowAlbumImage(picid);
byte[]
buffer = new byte[4096];
int byteSeq = strm.Read(buffer, 0, 4096);
while (byteSeq > 0)
{
context.Response.OutputStream.Write(buffer,
0, byteSeq);
byteSeq = strm.Read(buffer, 0, 4096);
}
//context.Response.BinaryWrite(buffer);
}
public Stream ShowAlbumImage(int picid)
{
string conn =
ConfigurationManager.ConnectionStrings["albumConnString"].ConnectionString;
SqlConnection
connection = new SqlConnection(conn);
string sql = "SELECT pic FROM Album WHERE Pic_ID
= @ID";
SqlCommand
cmd = new SqlCommand(sql, connection);
cmd.CommandType
= CommandType.Text;
cmd.Parameters.AddWithValue("@ID",
picid);
connection.Open();
object img
= cmd.ExecuteScalar();
try
{
return new
MemoryStream((byte[])img);
}
catch
{
return
null;
}
finally
{
connection.Close();
}
}
public bool
IsReusable
{
get
{
return
false;
}
}
}
VB.NET
<%@
WebHandler Language="vb" Class="ShowImage" %>
Imports System
Imports
System.Configuration
Imports System.Web
Imports
System.IO
Imports System.Data
Imports
System.Data.SqlClient
Public
Class ShowImage
Implements IHttpHandler
Public Sub
ProcessRequest(ByVal context As HttpContext) Implements
IHttpHandler.ProcessRequest
Dim picid As Int32
If Not
context.Request.QueryString("id") Is Nothing Then
picid =
Convert.ToInt32(context.Request.QueryString("id"))
Else
Throw New ArgumentException("No parameter
specified")
End If
context.Response.ContentType = "image/jpeg"
Dim strm As
Stream = ShowAlbumImage(picid)
Dim buffer As Byte() = New Byte(4095){}
Dim byteSeq
As Integer = strm.Read(buffer, 0, 4096)
Do While byteSeq > 0
context.Response.OutputStream.Write(buffer,
0, byteSeq)
byteSeq = strm.Read(buffer, 0, 4096)
Loop
'context.Response.BinaryWrite(buffer);
End Sub
Public
Function ShowAlbumImage(ByVal picid As Integer) As Stream
Dim conn As String =
ConfigurationManager.ConnectionStrings("albumConnString").ConnectionString
Dim
connection As SqlConnection = New SqlConnection(conn)
Dim sql As String = "SELECT pic FROM Album WHERE
Pic_ID = @ID"
Dim cmd As
SqlCommand = New SqlCommand(sql, connection)
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("@ID",
picid)
connection.Open()
Dim img As
Object = cmd.ExecuteScalar()
Try
Return New
MemoryStream(CType(img, Byte()))
Catch
Return
Nothing
Finally
connection.Close()
End Try
End
Function
Public
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return
False
End Get
End
Property
End Class
Step 5: We will now add the ListView to our page. We
will see how to use the ‘GroupTemplate’ to display images in multiple columns
(in our case 4 images). Add a SQLDataSource control to the page. After
configuring it with the database, the code will look similar to the following
<asp:SqlDataSource
ID="SqlDataSource1" runat="server"
ConnectionString="<%$
ConnectionStrings:albumConnString %>"
ProviderName="System.Data.SqlClient"
SelectCommand="SELECT
[pic_id],picture_tag, [pic] FROM [Album]"></asp:SqlDataSource>
Now add a
ListView Control to the page and set its DataSource property to
‘SqlDataSource1’. After adding the LayoutTemplate, ItemTemplate and
GroupTemplate the code will look similar to the following:
<asp:ListView
ID="ListView1" GroupItemCount="4" runat="server"
DataKeyNames="pic_id"
DataSourceID="SqlDataSource1">
<LayoutTemplate>
<asp:Placeholder
id="groupPlaceholder"
runat="server"
/>
</LayoutTemplate>
<GroupTemplate>
<div>
<asp:Placeholder
id="itemPlaceholder"
runat="server"
/>
</div>
</GroupTemplate>
<ItemTemplate>
<asp:Image
id="picAlbum"
runat="server" AlternateText='<%
#Eval("picture_tag") %>'
ImageUrl='<%#
"ShowImage.ashx?id=" + Eval("pic_id") %>' />
</ItemTemplate>
<EmptyItemTemplate>
</EmptyItemTemplate>
</asp:ListView>
If you
observe, the <LayoutTemplate> contains a placeholder called
‘groupPlaceholder’. When the page is rendered, the groupPlaceholder is replaced
with the contents of GroupTemplate. Similarly, the
<GroupTemplate> includes the ‘itemPlaceholder’ placeholder. The
itemPlaceholder is replaced with the contents of the ItemTemplate, which is an
image. As you know, the <ItemTemplate> renders each time there is
an item from the source. The ‘GroupItemCount’ attribute decides the number of
items displayed in a <GroupTemplate> before a new row is created.
Here we have set the ImageUrl to an expression which makes a call to the
handler and displays the images from the database. In the code below, we pass
the pic_id as a query string parameter to the Http Handler. Similarly the tags entered
by you are shown as alternate text on the images. To see the text, hover your
mouse over the image, when the application is run.
Note: One last thing. In order to display images as
they are added, just add this line of code (ListView1.DataBind()) in the
btnSubmit_Click, just before the try block ends.
...
lblResult.Text
= String.Format("Picture ID is {0}", id);
ListView1.DataBind();
We are all
set. It’s time to you run the application!! Start uploading images and you will
observe that as you upload the images, the gallery gets updated and the image
is displayed in an album mode using the ListView control as shown below:
The source code for this article in C# and VB.NET can be downloaded from here. I hope you liked the article and I thank you for viewing it.