Chapter 4. Using the Rich Controls

<feature><title>In this Chapter</title> <objective>

Accepting File Uploads

</objective>
<objective>

Displaying a Calendar

</objective>
<objective>

Displaying Advertisements

</objective>
<objective>

Displaying Different Page Views

</objective>
<objective>

Displaying a Wizard

</objective>
<objective>

Summary

</objective>
</feature>

In previous chapters we examined the ASP.NET controls that you will use in just about any application. In this chapter we examine a more specialized set of controls known collectively as the rich controls.

In the first section, you learn how to accept file uploads at your website. For example, you learn how to enable users to upload images, Microsoft Word documents, or Microsoft Excel spreadsheets.

Next, you learn how to work with the Calendar control. You can use the Calendar control as a date picker. You can also use the Calendar control to display upcoming events (such as a meeting schedule).

In this chapter, we also discuss the AdRotator control. This control enables you to display banner advertisements randomly on your website. The control enables you to store a list of advertisements in an XML file or a database table.

Next, you will learn about the MultiView control. This control enables you to hide and display areas of content on a page. You learn how to use this control to divide a page into different tabs.

Finally, you will learn about the Wizard control, which enables you to display multi-step forms. This control is useful when you need to divide a long form into multiple sub-forms.

Accepting File Uploads

The FileUpload control enables users to upload files to your web application. After the file is uploaded, you can store the file anywhere you please. Normally, you store the file either on the file system or in a database. This section explores both options.

The FileUpload control supports the following properties (this is not a complete list):

  • Enabled—Enables you to disable the FileUpload control.

  • FileBytes—Enables you to get the uploaded file contents as a byte array.

  • FileContent—Enables you to get the uploaded file contents as a stream.

  • FileName—Enables you to get the name of the file uploaded.

  • HasFile—Returns True when a file has been uploaded.

  • PostedFile—Enables you to get the uploaded file wrapped in the HttpPostedFile object.

The FileUpload control also supports the following methods:

  • Focus—Enables you to shift the form focus to the FileUpload control.

  • SaveAs—Enables you to save the uploaded file to the file system.

The FileUpload control’s PostedFile property enables you to retrieve the uploaded file wrapped in an HttpPostedFile object. This object exposes additional information about the uploaded file.

The HttpPostedFile class has the following properties (this is not a complete list):

  • ContentLength—Enables you to get the size of the uploaded file in bytes.

  • ContentType—Enables you to get the MIME type of the uploaded file.

  • FileName—Enables you to get the name of the uploaded file.

  • InputStream—Enables you to retrieve the uploaded file as a stream.

The HttpPostedFile class also supports the following method:

SaveAs—Enables you to save the uploaded file to the file system.

Notice that there is some redundancy here. For example, you can get the name of the uploaded file by using either the FileUpload.FileName property or the HttpPostedFile.FileName property. You can save a file by using either the FileUpload.SaveAs() method or the HttpPostedFile.SaveAs() method.

Note

Adding a FileUpload control to a page automatically adds a enctype="multipart/form-data" attribute to the server-side <form> tag.

Saving Files to the File System

The page in Listing 4.1 illustrates how you can upload images to an application by using the FileUpload control.

Example 4.1. FileUploadFile.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.IO" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Sub btnAdd_Click(ByVal sender As Object, ByVal e As EventArgs)
        If (upImage.HasFile) Then
            If (CheckFileType(upImage.FileName)) Then
                Dim filePath As String = "~/UploadImages/" & upImage.FileName
                upImage.SaveAs(MapPath(filePath))
            End If
        End If
    End Sub

    Function CheckFileType(ByVal fileName As String) As Boolean
        Dim ext As String = Path.GetExtension(fileName)
        Select Case ext.ToLower()
            Case ".gif"
                Return True
            Case ".png"
                Return True
            Case ".jpg"
                Return True
            Case ".jpeg"
                Return True
            Case Else
                Return False
        End Select
    End Function

    Sub Page_PreRender()
        Dim upFolder As String = MapPath("~/UploadImages/")
        Dim dir As New DirectoryInfo(upFolder)
        dlstImages.DataSource = dir.GetFiles()
        dlstImages.DataBind()
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">

    <title>FileUpload File</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Label
        id="lblImageFile"
        Text="Image File:"
        AssociatedControlID="upImage"
        Runat="server" />

    <asp:FileUpload
        id="upImage"
        Runat="server" />

    <br /><br />

    <asp:Button
        id="btnAdd"
        Text="Add Image"
        OnClick="btnAdd_Click"
        Runat="server" />

    <hr />

    <asp:DataList
        id="dlstImages"
        RepeatColumns="3"
        runat="server">
        <ItemTemplate>
        <asp:Image ID="Image1"
            ImageUrl='<%# Eval("Name", "~/UploadImages/{0}") %>'
            style="width:200px"
            Runat="server" />
        <br />
        <%# Eval("Name") %>
        </ItemTemplate>
    </asp:DataList>

    </div>
    </form>
</body>
</html>

Listing 4.1 includes both a FileUpload control and a DataList control. When you upload a file, the file is saved to a folder named ImageUploads. The DataList control automatically displays the contents of the ImageUploads folder. The result is an image gallery (see Figure 4.1).

Displaying a photo gallery.

Figure 4.1. Displaying a photo gallery.

Notice that the page includes a method named CheckFileType(), which prevents users from uploading a file that does not have the .gif, .jpeg, .jpg, or .png extension. The method restricts the type of file that can be uploaded based on the file extension.

Note

The HTML 4.01 specifications define an accept attribute that you should be able to use to filter the files that can be uploaded. Unfortunately, no browser supports the accept attribute, so you must perform filtering on the server (or use some JavaScript to check the filename extension on the client).

To save a file to the file system, the Windows account associated with the ASP.NET page must have sufficient permissions to save the file. For Windows 2003 Servers, an ASP.NET page executes in the security context of the NETWORK SERVICE account. In the case of every other operating system, an ASP.NET page executes in the security context of the ASPNET account.

To enable the ASP.NET framework to save an uploaded file to a particular folder, you need to right-click the folder within Windows Explorer, select the Security tab, and provide either the NETWORK SERVICE or ASPNET account Write permissions for the folder (see Figure 4.2).

Adding Write permissions for the ASPNET account.

Figure 4.2. Adding Write permissions for the ASPNET account.

Saving Files to a Database

You also can use the FileUpload control to save files to a database table. Saving and retrieving files from a database can place more stress on your server. However, it does have certain advantages. First, you can avoid file system permissions issues. Second, saving files to a database enables you to more easily back up your information.

The page in Listing 4.2 enables you to save Microsoft Word documents to a database table (see Figure 4.3).

Example 4.2. FileUploadDatabase.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.IO" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Sub btnAdd_Click(ByVal sender As Object, ByVal e As EventArgs)
        If upFile.HasFile Then
            If CheckFileType(upFile.FileName) Then
                srcFiles.Insert()

            End If
        End If
    End Sub

    Function CheckFileType(ByVal fileName As String) As Boolean
        Return Path.GetExtension(fileName).ToLower() = ".doc"
    End Function

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .fileList li
        {
            margin-bottom:5px;
        }
    </style>
    <title>FileUpload Database</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Label
        id="lblFile"
        Text="Word Document:"
        AssociatedControlID="upFile"
        Runat="server" />

    <asp:FileUpload
        id="upFile"
        Runat="server" />

    <asp:Button
        id="btnAdd"
        Text="Add Document"
        OnClick="btnAdd_Click"
        Runat="server" />

    <hr />

    <asp:Repeater
        id="rptFiles"

        DataSourceID="srcFiles"
        Runat="server">
        <HeaderTemplate>
        <ul class="fileList">
        </HeaderTemplate>
        <ItemTemplate>
        <li>
        <asp:HyperLink
            id="lnkFile"
            Text='<%#Eval("FileName")%>'
            NavigateUrl='<%#Eval("Id", "~/FileHandler.ashx?id={0}")%>'
            Runat="server" />
        </li>
        </ItemTemplate>
        <FooterTemplate>
        </ul>
        </FooterTemplate>
    </asp:Repeater>

    <asp:SqlDataSource
        id="srcFiles"
        ConnectionString="Server=.SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|FilesDB.mdf;User Instance=True"
        SelectCommand="SELECT Id,FileName FROM Files"
        InsertCommand="INSERT Files (FileName,FileBytes) VALUES (@FileName,@FileBytes)"
        Runat="server">
        <InsertParameters>
            <asp:ControlParameter Name="FileName" ControlID="upFile" PropertyName="FileName" />
            <asp:ControlParameter Name="FileBytes" ControlID="upFile" PropertyName="FileBytes" />
        </InsertParameters>
    </asp:SqlDataSource>

    </div>
    </form>
</body>
</html>
Uploading Microsoft Word documents.

Figure 4.3. Uploading Microsoft Word documents.

When you submit the form in Listing 4.2, the btnAdd_Click() method executes. This method checks the file extension to verify that the file is a Microsoft Word document. Next, the SqlDataSource control’s Insert() method is called to insert the values of the FileUpload control’s FileName and FileBytes properties into a local SQL Express database table. The SQL Express database table, named Files, looks like this:

Column Name

Data Type

Id

Int (IDENTITY)

FileName

NVarchar(50)

FileBytes

Varbinary(max)

The page also displays a list of the current Microsoft Word documents in the database. You can click any file and view the contents of the file. Exactly what happens when you click a file is browser (and browser settings) dependent. With Microsoft Internet Explorer, for example, the document opens directly in the browser.

Clicking the name of a document links you to a page named FileHandler.ashx. The FileHandler.ashx file is a generic HTTP Handler file. Chapter 25 discusses HTTP Handlers in detail. An HTTP Handler enables you to execute code when someone makes a request for a file with a certain path.

The FileHandler.ashx file is contained in Listing 4.3.

Example 4.3. FileHandler.ashx

<%@ WebHandler Language="VB" Class="FileHandler" %>

Imports System
Imports System.Web
Imports System.Data
Imports System.Data.SqlClient

Public Class FileHandler
    Implements IHttpHandler

    Const conString As String = "Server=.SQLExpress;Integrated Security=True;AttachDbFileName=|DataDirectory|FilesDB.mdf;User Instance=True"

    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        context.Response.ContentType = "application/msword"

        Dim con As SqlConnection = New SqlConnection(conString)
        Dim cmd As SqlCommand = New SqlCommand("SELECT FileBytes FROM Files WHERE Id=@Id", con)
        cmd.Parameters.AddWithValue("@Id", context.Request("Id"))
        Using con
            con.Open()
            Dim file() As Byte = CType(cmd.ExecuteScalar(), Byte())
            context.Response.BinaryWrite(file)
        End Using
    End Sub

    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

 End Class

When the FileHandler.aspx page is requested, the ProcessRequest() method executes. This method grabs a query string item named Id and retrieves the matching record from the Files database table. The record contains the contents of a Microsoft Word document as a byte array. The byte array is sent to the browser with the Response.BinaryWrite() method.

Uploading Large Files

You must do extra work when uploading large files. You don’t want to consume all your server’s memory by placing the entire file in memory. When working with a large file, you need to work with the file in more manageable chunks.

First, you need to configure your application to handle large files. Two configuration settings have an effect on posting large files to the server: the httpRuntime maxRequestLength and httpRuntime requestLengthDiskThreshold settings.

The maxRequestLength setting places a limit on the largest form post that the server will accept. By default, you cannot post a form that contains more than 4MB of data—if you try, you’ll get an exception. If you need to upload a file that contains more than four megabytes of data, then you need to change this setting.

The requestLengthDiskThreshold setting determines how a form post is buffered to the file system. In the previous version of ASP.NET (ASP.NET 1.1), uploading a large file could do horrible things to your server. The entire file was uploaded into the server memory. While a 10-megabyte video file was uploaded, for example, 10 megabytes of server memory was consumed.

The ASP.NET 2.0 Framework enables you to buffer large files onto the file system. When the size of the file passes the requestLengthDiskThreshold setting, the remainder of the file is buffered to the file system (in the Temporary ASP.NET Files folder).

By default, the ASP.NET framework is configured to buffer any post larger than 80KB to a file buffer. If you are not happy with this setting, then you can modify the requestLengthDiskThreshold to configure a new threshold. (The requestLengthDiskThreshold setting must be less than the maxRequestLength setting.)

The web configuration file in Listing 4.4 enables files up to 10MB to be posted. It also changes the buffering threshold to 100KB.

Example 4.4. Web.Config

<?xml version="1.0"?>
<configuration>
<system.web>
  <httpRuntime
       maxRequestLength="10240"
       requestLengthDiskThreshold="100" />
</system.web>
</configuration>

When working with large files, you must be careful about the way that you handle the file when storing or retrieving the file from a data store. For example, when saving or retrieving a file from a database table, you should never load the entire file into memory.

The page in Listing 4.5 demonstrates how you can save a large file to a database table efficiently.

Example 4.5. FileUploadLarge.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Const conString As String = "Server=.SQLExpress;Integrated Security=True;AttachDbFileName=|DataDirectory|FilesDB.mdf;User Instance=True"

    Sub btnAdd_Click(ByVal s As Object, ByVal e As EventArgs)
        If upFile.HasFile Then
            If CheckFileType(upFile.FileName) Then
                AddFile(upFile.FileName, upFile.FileContent)
                rptFiles.DataBind()
            End If
        End If
    End Sub

    Function CheckFileType(ByVal fileName As String) As Boolean
        Return Path.GetExtension(fileName).ToLower() = ".doc"
    End Function

    Sub AddFile(ByVal fileName As String, ByVal upload As Stream)
        Dim con As New SqlConnection(conString)

        Dim cmd As New SqlCommand("INSERT Files (FileName) Values (@FileName);SELECT @Identity = SCOPE_IDENTITY()", con)

        cmd.Parameters.AddWithValue("@FileName", fileName)
        Dim idParm As SqlParameter = cmd.Parameters.Add("@Identity", SqlDbType.Int)
        idParm.Direction = ParameterDirection.Output

        Using con
            con.Open()
            cmd.ExecuteNonQuery()
            Dim newFileId As Integer = CType(idParm.Value, Integer)
            StoreFile(newFileId, upload, con)
        End Using
    End Sub

    Sub StoreFile(ByVal fileId As Integer, ByVal upload As Stream, ByVal connection As SqlConnection)

        Dim bufferLen As Integer = 8040
        Dim br As New BinaryReader(upload)
        Dim chunk As Byte() = br.ReadBytes(bufferLen)

        Dim cmd As New SqlCommand("UPDATE Files SET FileBytes=@Buffer WHERE Id=@FileId", connection)
        cmd.Parameters.AddWithValue("@FileId", fileId)
        cmd.Parameters.Add("@Buffer", SqlDbType.VarBinary, bufferLen).Value = chunk
        cmd.ExecuteNonQuery()


        Dim cmdAppend As New SqlCommand("UPDATE Files SET FileBytes .WRITE(@Buffer, NULL, 0) WHERE Id=@FileId", connection)
        cmdAppend.Parameters.AddWithValue("@FileId", fileId)
        cmdAppend.Parameters.Add("@Buffer", SqlDbType.VarBinary, bufferLen)
        chunk = br.ReadBytes(bufferLen)

        While chunk.Length > 0
            cmdAppend.Parameters("@Buffer").Value = chunk
            cmdAppend.ExecuteNonQuery()
            chunk = br.ReadBytes(bufferLen)
        End While

        br.Close()
    End Sub

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>FileUpload Large</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Label
        id="lblFile"
        Text="Word Document:"
        AssociatedControlID="upFile"
        Runat="server" />

    <asp:FileUpload
        id="upFile"
        Runat="server" />

    <asp:Button
        id="btnAdd"
        Text="Add Document"
        OnClick="btnAdd_Click"
        Runat="server" />

    <hr />

    <asp:Repeater
        id="rptFiles"
        DataSourceID="srcFiles"
        Runat="server">
        <HeaderTemplate>
        <ul class="fileList">
        </HeaderTemplate>
        <ItemTemplate>
        <li>
        <asp:HyperLink
            id="lnkFile"
            Text='<%#Eval("FileName")%>'
            NavigateUrl='<%#Eval("Id", "~/FileHandlerLarge.ashx?id={0}")%>'
            Runat="server" />
        </li>
        </ItemTemplate>
        <FooterTemplate>
        </ul>
        </FooterTemplate>
    </asp:Repeater>

    <asp:SqlDataSource
        id="srcFiles"
        ConnectionString="Server=.SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|FilesDB.mdf;User Instance=True"
        SelectCommand="SELECT Id,FileName FROM Files"
        Runat="server" />

    </div>
    </form>
</body>
</html>

In Listing 4.5, the AddFile() method is called. This method adds a new row to the Files database table that contains the filename. Next, the StoreFile() method is called. This method adds the actual bytes of the uploaded file to the database. The file contents are divided into 8040-byte chunks. Notice that the SQL UPDATE statement includes a .WRITE clause that is used when the FileBytes database column is updated.

Note

Microsoft recommends that you set the buffer size to multiples of 8040 when using the .WRITE clause to update database data.

The page in Listing 4.5 never represents the entire uploaded file in memory. The file is yanked into memory from the file system in 8040-byte chunks and fed to SQL Server in chunks.

When you click a filename, the FileHandlerLarge.ashx HTTP Handler executes. This handler retrieves the selected file from the database and sends it to the browser. The handler is contained in Listing 4.6.

Example 4.6. FileHandlerLarge.ashx

<%@ WebHandler Language="VB" Class="FileHandlerLarge" %>

Imports System
Imports System.Web
Imports System.Data
imports System.Data.SqlClient

Public Class FileHandlerLarge
    Implements IHttpHandler

    Const conString As String = "Server=.SQLExpress;Integrated Security=True;AttachDbFileName=|DataDirectory|FilesDB.mdf;User Instance=True"

    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        context.Response.Buffer = False
        context.Response.ContentType = "application/msword"

        Dim con As New SqlConnection(conString)
        Dim cmd As New SqlCommand("SELECT FileBytes FROM Files WHERE Id=@Id", con)
        cmd.Parameters.AddWithValue("@Id", context.Request("Id"))
        Using con
            con.Open()
            Dim reader As SqlDataReader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)
            If reader.Read() Then
                Dim bufferSize As Integer = 8040
                Dim chunk(bufferSize - 1) As Byte

                Dim retCount As Long
                Dim startIndex As Long = 0

                retCount = reader.GetBytes(0, startIndex, chunk, 0, bufferSize)

                While retCount = bufferSize
                    context.Response.BinaryWrite(chunk)

                    startIndex += bufferSize
                    retCount = reader.GetBytes(0, startIndex, chunk, 0, bufferSize)
                End While

                Dim actualChunk(retCount - 1) As Byte
                Buffer.BlockCopy(chunk, 0, actualChunk, 0, retCount - 1)
                context.Response.BinaryWrite(actualChunk)

            End If
        End Using
    End Sub

    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

 End Class

The HTTP Handler in Listing 4.6 uses a SqlDataReader to retrieve a file from the database. Notice that the SqlDataReader is retrieved with a CommandBehavior.SequentialAccess parameter. This parameter enables the SqlDataReader to load data as a stream. The contents of the database column are pulled into memory in 8040-byte chunks. The chunks are written to the browser with the Response.BinaryWrite() method.

Notice that response buffering is disabled for the handler. The Response.Buffer property is set to the value False. Because buffering is disabled, the output of the handler is not buffered in server memory before being transmitted to the browser.

Warning

The method of working with large files described in this section works only with SQL Server 2005. When using earlier versions of SQL Server, you need to use the TEXTPTR() function instead of the .WRITE clause.

Displaying a Calendar

The Calendar control enables you to display a calendar. You can use the calendar as a date picker or you can use the calendar to display a list of upcoming events.

The page in Listing 4.7 displays a simple calendar with the Calendar control (see Figure 4.4).

Example 4.7. ShowCalendar.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Calendar</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Calendar
        id="Calendar1"

        Runat="server" />

    </div>
    </form>
</body>
</html>
Displaying a calendar with the Calendar control.

Figure 4.4. Displaying a calendar with the Calendar control.

The Calendar control supports the following properties (this is not a complete list):

  • DayNameFormat—Enables you to specify the appearance of the days of the week. Possible values are FirstLetter, FirstTwoLetters, Full, Short, and Shortest.

  • NextMonthText—Enables you to specify the text that appears for the next month link.

  • NextPrevFormat—Enables you to specify the format of the next month and previous month link. Possible values are CustomText, FullMonth, and ShortMonth.

  • PrevMonthText—Enables you to specify the text that appears for the previous month link.

  • SelectedDate—Enables you to get or set the selected date.

  • SelectedDates—Enables you to get or set a collection of selected dates.

  • SelectionMode—Enables you to specify how dates are selected. Possible values are Day, DayWeek, DayWeekMonth, and None.

  • SelectMonthText—Enables you to specify the text that appears for selecting a month.

  • SelectWeekText—Enables you to specify the text that appears for selecting a week.

  • ShowDayHeader—Enables you to hide or display the day names at the top of the Calendar control.

  • ShowNextPrevMonth—Enables you to hide or display the links for the next and previous months.

  • ShowTitle—Enables you to hide or display the title bar displayed at the top of the calendar.

  • TitleFormat—Enables you to format the title bar. Possible values are Month and MonthYear.

  • TodaysDate—Enables you to specify the current date. This property defaults to the current date on the server.

  • VisibleDate—Enables you to specify the month displayed by the Calendar control. This property defaults to displaying the month that contains the date specified by TodaysDate.

The Calendar control also supports the following events:

  • DayRender—Raised as each day is rendered.

  • SelectionChanged—Raised when a new day, week, or month is selected.

  • VisibleMonthChanged—Raised when the next or previous month link is clicked.

Notice that the SelectionMode property enables you to change the behavior of the calendar so that you can not only select days, but also select weeks or months. The page in Listing 4.8 illustrates how you can use the SelectionMode property in conjunction with the SelectedDates property to select multiple dates (see Figure 4.5).

Example 4.8. CalendarSelectionMode.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Sub btnSubmit_Click(sender As Object, e As EventArgs)
        bltResults.DataSource = Calendar1.SelectedDates
        bltResults.DataBind()
    End Sub

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Calendar SelectionMode</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Calendar
        id="Calendar1"
        SelectionMode="DayWeekMonth"
        runat="server" />

    <br /><br />

    <asp:Button
        id="btnSubmit"
        Text="Submit"
        OnClick="btnSubmit_Click"
        Runat="server" />

    <hr />

    <asp:BulletedList
        id="bltResults"
        DataTextFormatString="{0:d}"
        Runat="server" />

    </div>
    </form>
</body>
</html>
Selecting weeks and months with a Calendar control.

Figure 4.5. Selecting weeks and months with a Calendar control.

When you select a date, or group of dates, from the Calendar control in Listing 4.8, the set of selected dates are displayed in a BulletedList control.

Creating a Pop-up Date Picker

You can use a Calendar control to create a fancy pop-up date picker if you are willing to add a little JavaScript and some Cascading Style Sheet rules to a page. The page in Listing 4.9 contains a TextBox and Calendar control (see Figure 4.6).

Example 4.9. CalendarJS.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Sub calEventDate_SelectionChanged(ByVal sender As Object, ByVal e As EventArgs)
        txtEventDate.Text = calEventDate.SelectedDate.ToString("d")
    End Sub

    Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs)
        lblResult.Text = "You picked: " & txtEventDate.Text
    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <script type="text/javascript">

        function displayCalendar()
        {
            var datePicker = document.getElementById('datePicker'),
            datePicker.style.display = 'block';
        }

    </script>
    <style type="text/css">
        #datePicker
        {
            display:none;
            position:absolute;
            border:solid 2px black;
            background-color:white;
        }
        .content
        {
            width:400px;
            background-color:white;
            margin:auto;
            padding:10px;
        }
        html
        {
            background-color:silver;
        }
    </style>
    <title>Calendar with JavaScript</title>
</head>
<body>
    <form id="form1" runat="server">
    <div class="content">

    <asp:Label
        id="lblEventDate"

        Text="Event Date:"
        AssociatedControlID="txtEventDate"
        Runat="server" />
    <asp:TextBox
        id="txtEventDate"
        Runat="server" />
    <img src="Calendar.gif" onclick="displayCalendar()" />

    <div id="datePicker">
    <asp:Calendar
        id="calEventDate"
        OnSelectionChanged="calEventDate_SelectionChanged"
        Runat="server" />
    </div>

    <br />
    <asp:Button
        id="btnSubmit"
        Text="Submit"
        Runat="server" OnClick="btnSubmit_Click" />

    <hr />

    <asp:Label
        id="lblResult"
        Runat="server" />

    </div>
    </form>
</body>
</html>
Displaying a pop-up calendar.

Figure 4.6. Displaying a pop-up calendar.

The Calendar control is hidden until you click the calendar image. The #datePicker style sheet rules sets the display property to none. When you click the image of the calendar, the JavaScript displayCalendar() function executes and sets the CSS display property to the value block.

When you select a date from the calendar, the page is posted back to the server and the SelectionChanged server-side event is raised. The SelectionChanged event handler updates the TextBox control with the selected date.

Rendering a Calendar from a Database Table

You also can use the Calendar control to display events in a calendar. In this section, we build a simple schedule application that enables you to insert, update, and delete calendar entries. Each schedule entry is highlighted in a Calendar control (see Figure 4.7).

Displaying a calendar from a database.

Figure 4.7. Displaying a calendar from a database.

The code for the schedule application is contained in Listing 4.10.

Example 4.10. CalendarDatabase.aspx

<%@ Page Language="VB" ValidateRequest="false" %>
<%@ Import Namespace="System.Data" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Private schedule As New DataView()

    Sub Page_Load()
        If calSchedule.SelectedDate = DateTime.MinValue Then
            calSchedule.SelectedDate = calSchedule.TodaysDate
        End If
    End Sub

    Sub Page_PreRender()
        schedule = CType(srcCalendar.Select(DataSourceSelectArguments.Empty), DataView)
        schedule.Sort = "EntryDate"
    End Sub

    Sub calSchedule_DayRender(ByVal sender As Object, ByVal e As DayRenderEventArgs)
        If schedule.FindRows(e.Day.Date).Length > 0 Then
            e.Cell.BackColor = System.Drawing.Color.Yellow
        End If
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Calendar Database</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Calendar
        id="calSchedule"
        OnDayRender="calSchedule_DayRender"
        Runat="server" />

    <br />

    <asp:FormView
        id="frmSchedule"
        AllowPaging="True"
        DataKeyNames="EntryDate"
        DataSourceID="srcSchedule"
        Runat="server">
        <EmptyDataTemplate>
        <asp:LinkButton
            id="btnNew"
            Text="Add Entry"
            CommandName="New"
            Runat="server" />
        </EmptyDataTemplate>
        <ItemTemplate>
        <h1><%# Eval("EntryDate", "{0:D}") %></h1>
        <%# Eval("Entry") %>
        <br /><br />
        <asp:LinkButton
            Id="btnEdit"
            Text="Edit Entry"
            CommandName="Edit"
            Runat="server" />

        <asp:LinkButton
            Id="lnkDelete"
            Text="Delete Entry"
            CommandName="Delete"
            OnClientClick="return confirm('Delete entry?'),"
            Runat="server" />
        </ItemTemplate>
        <EditItemTemplate>
        <asp:Label
            id="lblEntry"
            Text="Entry:"
            AssociatedControlID="txtEntry"
            Runat="server" />
        <br />
        <asp:TextBox
            id="txtEntry"
            Text='<%#Bind("Entry") %>'
            TextMode="MultiLine"
            Columns="40"
            Rows="8"
            Runat="server" />
        <br />
        <asp:LinkButton
            id="btnUpdate"
            Text="Update"
            CommandName="Update"
            Runat="server" />
        </EditItemTemplate>
        <InsertItemTemplate>
        <asp:Label
            id="lblEntry"
            Text="Entry:"
            AssociatedControlID="txtEntry"
            Runat="server" />
        <br />
        <asp:TextBox
            id="txtEntry"
            Text='<%#Bind("Entry") %>'
            TextMode="MultiLine"
            Columns="40"
            Rows="8"
            Runat="server" />
        <br />
        <asp:Button

            id="btnInsert"
            Text="Insert"
            CommandName="Insert"
            Runat="server" />
        </InsertItemTemplate>
    </asp:FormView>

    <asp:SqlDataSource
        id="srcSchedule"
        ConnectionString="Server=.SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|ScheduleDB.mdf;User Instance=True"
        SelectCommand="SELECT EntryDate,Entry FROM Schedule WHERE EntryDate=@EntryDate"
        InsertCommand="INSERT Schedule (EntryDate,Entry) VALUES (@EntryDate,@Entry)"
        UpdateCommand="UPDATE Schedule SET Entry=@Entry WHERE EntryDate=@EntryDate"
        DELETECommand="DELETE Schedule WHERE EntryDate=@EntryDate"
        Runat="server">
        <SelectParameters>
        <asp:ControlParameter
            Name="EntryDate"
            ControlID="calSchedule"
            PropertyName="SelectedDate" />
        </SelectParameters>
        <InsertParameters>
        <asp:ControlParameter
            Name="EntryDate"
            ControlID="calSchedule"
            PropertyName="SelectedDate" />
        </InsertParameters>
    </asp:SqlDataSource>

    <asp:SqlDataSource
        id="srcCalendar"
        ConnectionString="Server=.SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|ScheduleDB.mdf;User Instance=True"
        SelectCommand="SELECT EntryDate FROM Schedule"
        Runat="server">
    </asp:SqlDataSource>

    </div>
    </form>
</body>
</html>

The page in Listing 4.10 saves and loads entries from a SQL Express database named ScheduleDB. The contents of the schedule are contained in a table named Schedule which has the following schema:

Column Name

Data Type

EntryDate

DateTime

Entry

Nvarchar(max)

The tricky part in Listing 4.10 is the code for highlighting the current entries in the calendar. In the Page_PreRender event handler, a list of all the current entries is retrieved from the database. The list is represented by a DataView object.

The DayRender event is raised when the Calendar renders each day (table cell). In the DayRender event handler in Listing 4.10, if there is an entry in the database that corresponds to the day being rendered, then the day is highlighted with a yellow background color.

Displaying Advertisements

The AdRotator control enables you to randomly display different advertisements in a page. You can store the list of advertisements in either an XML file or in a database table.

The AdRotator control supports the following properties (this is not a complete list):

  • AdvertisementFile—Enables you to specify the path to an XML file that contains a list of banner advertisements.

  • AlternateTextField—Enables you to specify the name of the field for displaying alternate text for the banner advertisement image. The default value is AlternateText.

  • DataMember—Enables you to bind to a particular data member in the data source.

  • DataSource—Enables you to specify a data source programmatically for the list of banner advertisements.

  • DataSourceID—Enables you to bind to a data source declaratively.

  • ImageUrlField—Enables you to specify the name of the field for the image URL for the banner advertisement. The default value for this field is ImageUrl.

  • KeywordFilter—Enables you to filter advertisements by a single keyword.

  • NavigateUrlField—Enables you to specify the name of the field for the advertisement link. The default value for this field is NavigateUrl.

  • Target—Enables you to open a new window when a user clicks the banner advertisement.

The AdRotator control also supports the following event:

  • AdCreated—Raised after the AdRotator control selects an advertisement but before the AdRotator control renders the advertisement.

Notice that the AdRotator control includes a KeywordFilter property. You can provide each banner advertisement with a keyword and then filter the advertisements displayed by the AdRotator control by using the value of the KeywordFilter property.

This property can be used in multiple ways. For example, if you are displaying more than one advertisement in the same page, then you can filter the advertisements by page regions. You can use the KeywordFilter to show the big banner advertisement on the top of the page and box ads on the side of the page.

You can also use the KeywordFilter property to filter advertisements by website section. For example, you might want to show different advertisements on your website’s home page than on your website’s search page.

Note

If you cache a page that contains an AdRotator control, then the AdRotator control is excluded from the cache. In other words, even if you cache a page, randomly selected banner advertisements are still displayed. The AdRotator control takes advantage of a new feature of the ASP.NET 2.0 Framework called post-cache substitution. You learn more about this feature in Chapter 23, “Caching Application Pages and Data.”

Storing Advertisements in an XML File

You can store the list of advertisements that the AdRotator displays in an XML file by setting the AdRotator control’s AdvertisementFile property. For example, the page in Listing 4.11 contains three AdRotator controls that retrieve banner advertisements from an XML file named AdList.xml (see Figure 4.8).

Example 4.11. AdRotatorXML.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        html
        {
            background-color:silver;
        }
        .content
        {

            background-color:white;
            padding:10px;
            border:solid 1px black;
            margin:auto;
            width:400px;
            text-align:center;
        }
        .box
        {
            float:right;
            padding:10px;
            border-left:solid 1px black;
        }
        .clear
        {
            clear:both;
        }
    </style>
    <title>AdRotator XML</title>
</head>
<body>
    <form id="form1" runat="server">
    <div class="content">

    <asp:AdRotator
        id="AdRotator1"
        AdvertisementFile="~/App_Data/AdList.xml"
        KeywordFilter="banner"
        CssClass="banner"
        Runat="server" />

    <br />

    <div class="box">
        <asp:AdRotator
            id="AdRotator2"
            AdvertisementFile="~/App_Data/AdList.xml"
            KeywordFilter="box"
            Runat="server" />
        <br /><br />
        <asp:AdRotator
            id="AdRotator3"
            AdvertisementFile="~/App_Data/AdList.xml"
            KeywordFilter="box"

            Runat="server" />
    </div>


    <br />Here is the body text in the page.
    <br />Here is the body text in the page.
    <br />Here is the body text in the page.
    <br />Here is the body text in the page.

    <br class="clear" />
    </div>
    </form>
</body>
</html>
Displaying advertisements from an XML file.

Figure 4.8. Displaying advertisements from an XML file.

The page in Listing 4.11 contains an AdRotator control that displays a banner advertisement at the top of the page. The page also contains two AdRotator controls that display box advertisements on the right of the page.

Notice that the first AdRotator has a KeyworldFilter property that has the value banner, and the remaining two AdRotator controls have KeywordFilter properties with the value box. The first AdRotator displays only banner advertisements, and the remaining two AdRotator controls display only box advertisements.

All three AdRotator controls get their list of banner advertisements from a file named AdList.xml. This file is located in the App_Data folder for security reasons. The files in the App_Data folder cannot be opened in a web browser.

Note

There is nothing wrong with assigning different XML files to different AdRotator controls. For example, you could create distinct BannerAd.xml and BoxAd.xml files and then you would not have to worry about the KeywordFilter property.

The file in Listing 4.12 contains the contents of the AdList.xml file.

Example 4.12. AdList.xml

<?xml version="1.0" encoding="utf-8" ?>
<Advertisements>
  <!-- Banner Advertisements -->
  <Ad>
    <ImageUrl>~/Ads/BannerAd1.gif</ImageUrl>
    <Width>300</Width>
    <Height>50</Height>
    <NavigateUrl>http://www.AspWorkshops.com</NavigateUrl>
    <AlternateText>Banner Advertisement 1</AlternateText>
    <Impressions>50</Impressions>
    <Keyword>banner</Keyword>
  </Ad>
  <Ad>
    <ImageUrl>~/Ads/BannerAd2.gif</ImageUrl>
    <Width>300</Width>
    <Height>50</Height>
    <NavigateUrl>http://www.AspWorkshops.com</NavigateUrl>
    <AlternateText>Banner Advertisement 2</AlternateText>
    <Impressions>25</Impressions>
    <Keyword>banner</Keyword>
  </Ad>
  <Ad>
    <ImageUrl>~/Ads/BannerAd3.gif</ImageUrl>
    <Width>300</Width>
    <Height>50</Height>
    <NavigateUrl>http://www.AspWorkshops.com</NavigateUrl>
    <AlternateText>Banner Advertisement 3</AlternateText>
    <Impressions>25</Impressions>
    <Keyword>banner</Keyword>

  </Ad>
  <!-- Box Advertisements -->
  <Ad>
    <ImageUrl>~/Ads/BoxAd1.gif</ImageUrl>
    <Width>150</Width>
    <Height>150</Height>
    <NavigateUrl>http://www.AspWorkshops.com</NavigateUrl>
    <AlternateText>Box Advertisement 1</AlternateText>
    <Impressions>50</Impressions>
    <Keyword>box</Keyword>
  </Ad>
  <Ad>
    <ImageUrl>~/Ads/BoxAd2.gif</ImageUrl>
    <Width>150</Width>
    <Height>150</Height>
    <NavigateUrl>http://www.AspWorkshops.com</NavigateUrl>
    <AlternateText>Box Advertisement 2</AlternateText>
    <Impressions>50</Impressions>
    <Keyword>box</Keyword>
  </Ad>
 </Advertisements>

The Impressions attribute in the file in Listing 4.12 determines how often each banner advertisement is displayed. For example, the first banner advertisement is displayed 50% of the time, and the remaining two banner advertisements are displayed 25% of the time.

Storing Advertisements in a Database Table

Rather than store the list of advertisements in an XML file, you can store the list in a database table. For example, the AdRotator control contained in Listing 4.13 is bound to a SqlDataSource control. The SqlDataSource control represents the contents of a database table named AdList, which is located in a SQL Express database named AdListDB.

Example 4.13. AdRotatorDatabase.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>AdRotator Database</title>
</head>
<body>
    <form id="form1" runat="server">

    <div>

    <asp:AdRotator
        id="AdRotator1"
        DataSourceID="srcAds"
        Runat="server" />

    <asp:SqlDataSource
        id="srcAds"
        ConnectionString="Server=.SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|AdListDB.mdf;User Instance=True"
        SelectCommand="SELECT ImageUrl, Width, Height, NavigateUrl, AlternateText, Keyword, Impressions
            FROM AdList"
        Runat="server" />

    </div>
    </form>
</body>
</html>

To use the page in Listing 4.13, you need to create the AdList database table. This table has the following schema:

Column Name

Data Type

Id

Int (IDENTITY)

ImageUrl

Varchar(250)

Width

Int

Height

Int

NavigateUrl

Varchar(250)

AlternateText

NVarchar(100)

Keyword

NVarchar(50)

Impressions

Int

Notice that the columns in the AdList database table correspond to the attributes in the AdList.xml file discussed in the previous section.

Tracking Impressions and Transfers

Normally, when you are displaying advertisements, you are doing it to make money. Your advertisers will want statistics on how often their advertisements were displayed (the number of impressions) and how often their advertisements were clicked (the number of transfers).

To track the number of times that an advertisement is displayed, you need to handle the AdRotator control’s AdCreated event. To track the number of times that an advertisement is clicked, you need to create a redirect handler.

Warning

If you create an event handler for the AdCreated event and you cache the page, the content rendered by the AdRotator control will also be cached. When handling the AdCreated event, use partial page caching to cache only part of a page and not the AdRotator control itself.

The page in Listing 4.14 displays a banner advertisement with the AdRotator control. The page includes an event handler for the AdRotator control’s AdCreated event.

Example 4.14. AdRotatorTrack.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Sub AdRotator1_AdCreated(ByVal sender As Object, ByVal e As AdCreatedEventArgs)
        ' Update Impressions
        srcAds.InsertParameters("AdId").DefaultValue = e.AdProperties("Id").ToString()
        srcAds.Insert()

        ' Change NavigateUrl to redirect page
        e.NavigateUrl = "~/AdHandler.ashx?id=" & e.AdProperties("Id").ToString()
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>AdRotator Track</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:AdRotator
        id="AdRotator1"
        DataSourceID="srcAds"
        OnAdCreated="AdRotator1_AdCreated"
        Runat="server" />

    <asp:SqlDataSource
        id="srcAds"

        ConnectionString="Server=.SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|AdListDB.mdf;User Instance=True"
        SelectCommand="SELECT Id, ImageUrl, Width, Height, NavigateUrl, AlternateText, Keyword, Impressions
            FROM AdList"
        InsertCommand="INSERT AdStats (AdId, EntryDate, Type) VALUES (@AdId, GetDate(), 0)"
        Runat="server">
        <InsertParameters>
        <asp:Parameter Name="AdId" Type="int32" />
        </InsertParameters>
     </asp:SqlDataSource>

    </div>
    </form>
</body>
</html>

The AdCreated event handler does two things. First, it inserts a new record into a database table named AdStats, which records an advertisement impression. Second, the handler modifies the NavigateUrl so that the user is redirected to a handler named AdHandler.ashx.

The AdStats database table looks like this:

Column Name

Data Type

Id

Int (IDENTITY)

AdId

Int

EntryDate

DateTime

Type

Int

The Type column is used to record the type of entry. The value 0 represents an advertisement impression, and the value 1 represents an advertisement transfer.

When you click an advertisement, you link to a file named AdHandler.ashx. This file is contained in Listing 4.15.

Example 4.15. AdHandler.ashx

<%@ WebHandler Language="VB" Class="AdHandler" %>

Imports System
Imports System.Web
Imports System.Data
imports System.Data.SqlClient
Public Class AdHandler
    Implements IHttpHandler

    Const conString As String = "Server=.SQLExpress;Integrated Security=True;AttachDbFileName=|DataDirectory|AdListDB.mdf;User Instance=True"

    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        Dim AdId As Integer = Int32.Parse(context.Request("Id"))

        Dim con As New SqlConnection(conString)
        Dim navigateUrl As String = String.Empty
        Using con
            con.Open()
            UpdateTransferStats(AdId, con)
            navigateUrl = GetNavigateUrl(AdId, con)
        End Using

        If Not String.IsNullOrEmpty(navigateUrl) Then
            context.Response.Redirect(navigateUrl)
        End If
    End Sub

    Sub UpdateTransferStats(ByVal advertisementId As Integer, ByVal con As SqlConnection)
        Dim cmdText As String = "INSERT AdStats (AdId, EntryDate, Type) VALUES "& _
            "(@AdId, GetDate(), 1)"
        Dim cmd As New SqlCommand(cmdText, con)
        cmd.Parameters.AddWithValue("@AdId", advertisementId)
        cmd.ExecuteNonQuery()
    End Sub

    Function GetNavigateUrl(ByVal advertisementId As Integer, ByVal con As SqlConnection) As String
        Dim cmdText As String = "SELECT NavigateUrl FROM AdList WHERE Id=@AdId"
        Dim cmd As New SqlCommand(cmdText, con)
        cmd.Parameters.AddWithValue("@AdId", advertisementId)
        Return cmd.ExecuteScalar().ToString()
    End Function


    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable

        Get
            Return False
        End Get
    End Property

 End Class

The handler in Listing 4.15 performs two tasks. First, it inserts a new record into the AdStats database table, recording the fact that a transfer is taking place. Next, it grabs the NavigateUrl from the AdList database table and sends the user to the advertiser’s website.

The final page displays advertiser statistics from the AdStats database table (see Figure 4.9). This page is contained in Listing 4.16.

Displaying advertiser statistics.

Figure 4.9. Displaying advertiser statistics.

Example 4.16. AdRotatorStats.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >

<head id="Head1" runat="server">
    <style type="text/css">
        .grid td,.grid th
        {
            border-bottom:solid 1px black;
            padding:5px;
        }
    </style>
    <title>AdRotator Statistics</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <h1>Advertisement Statistics</h1>
    Impressions represent the number of times an advertisement has been viewed.
    Transfers represent the number of times an advertisement has been clicked.

    <h2>Impressions</h2>

    <asp:GridView
        id="grdImpressions"
        DataSourceID="srcImpressions"
        AutoGenerateColumns="false"
        GridLines="None"
        CssClass="grid"
        Runat="server">
        <Columns>
        <asp:BoundField
            DataField="AdId"
            HeaderText="Advertisement Id" />
        <asp:BoundField
            DataField="Impressions"
            HeaderText="Impressions" />
        </Columns>
    </asp:GridView>

    <asp:SqlDataSource
        id="srcImpressions"
        ConnectionString="Server=.SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|AdListDB.mdf;User Instance=True"
        SelectCommand="SELECT AdId,Count(*) As Impressions
            FROM AdStats

            WHERE Type=0
            GROUP BY AdId
            ORDER BY Impressions DESC"
        Runat="server" />

    <h2>Transfers</h2>

    <asp:GridView
        id="grdTransfers"
        DataSourceID="srcTransfers"
        AutoGenerateColumns="false"
        GridLines="None"
        CssClass="grid"
        Runat="server">
        <Columns>
        <asp:BoundField
            DataField="AdId"
            HeaderText="Advertisement Id" />
        <asp:BoundField
            DataField="Transfers"
            HeaderText="Transfers" />
        </Columns>
    </asp:GridView>

    <asp:SqlDataSource
        id="srcTransfers"
        ConnectionString="Server=.SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|AdListDB.mdf;User Instance=True"
        SelectCommand="SELECT AdId,Count(*) As Transfers
            FROM AdStats
            WHERE Type=1
            GROUP BY AdId
            ORDER BY Transfers DESC"
        Runat="server" />

    </div>
    </form>
</body>
</html>

The page in Listing 4.16 contains two GridView controls bound to two SqlDataSource controls. The first GridView displays statistics on impressions, and the second GridView displays statistics on transfers.

Displaying Different Page Views

The MultiView control enables you to hide and display different areas of a page. This control is useful when you need to create a tabbed page. It is also useful when you need to divide a long form into multiple forms.

The MultiView control contains one or more View controls. You use the MultiView control to select a particular View control to render. (The selected View control is the Active View.) The contents of the remaining View controls are hidden. You can render only one View control at a time.

The MultiView control supports the following properties (this is not a complete list):

  • ActiveViewIndex—Enables you to select the View control to render by index.

  • Views—Enables you to retrieve the collection of View controls contained in the MultiView control

The MultiView control also supports the following methods:

  • GetActiveView—Enables you to retrieve the selected View control.

  • SetActiveView—Enables you to select the active view.

Finally, the MultiView control supports the following event:

  • ActiveViewChanged—Raised when a new View control is selected.

The View control does not support any special properties or methods. Its primary purpose is to act as a container for other controls. However, the View control does support the following two events:

  • Activate—Raised when the view becomes the selected view in the MultiView control.

  • Deactivate—Raised when another view becomes the selected view in the MultiView control.

Displaying a Tabbed Page View

When you use the MultiView control in conjunction with the Menu control, you can create a tabbed page view. (To make it look pretty, you need to use some CSS.)

For example, the page in Listing 4.17 contains a MultiView control with three View controls. The Menu control is used to switch between the View controls (see Figure 4.10).

Example 4.17. MultiViewTabs.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs)
        Dim index As Integer = Int32.Parse(e.Item.Value)
        MultiView1.ActiveViewIndex = index
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        html
        {
            background-color:silver;
        }
        .tabs
        {
            position:relative;
            top:1px;

            left:10px;
        }
        .tab
        {
            border:solid 1px black;
            background-color:#eeeeee;
            padding:2px 10px;
        }
        .selectedTab
        {
            background-color:white;
            border-bottom:solid 1px white;
        }
        .tabContents
        {
            border:solid 1px black;
            padding:10px;
            background-color:white;
        }
    </style>
    <title>MultiView Tabs</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Menu
        id="Menu1"
        Orientation="Horizontal"
        StaticMenuItemStyle-CssClass="tab"
        StaticSelectedStyle-CssClass="selectedTab"
        CssClass="tabs"
        OnMenuItemClick="Menu1_MenuItemClick"
        Runat="server">
        <Items>
        <asp:MenuItem Text="Tab 1" Value="0" Selected="true" />
        <asp:MenuItem Text="Tab 2" Value="1" />
        <asp:MenuItem Text="Tab 3" Value="2" />
        </Items>
    </asp:Menu>

    <div class="tabContents">
    <asp:MultiView
        id="MultiView1"

        ActiveViewIndex="0"
        Runat="server">
        <asp:View ID="View1" runat="server">
            <br />This is the first view
            <br />This is the first view
            <br />This is the first view
            <br />This is the first view
        </asp:View>
        <asp:View ID="View2" runat="server">
            <br />This is the second view
            <br />This is the second view
            <br />This is the second view
            <br />This is the second view
        </asp:View>
        <asp:View ID="View3" runat="server">
            <br />This is the third view
            <br />This is the third view
            <br />This is the third view
            <br />This is the third view
        </asp:View>
    </asp:MultiView>
    </div>

    </div>
    </form>
</body>
</html>
Displaying a tabbed page with the MultiView control.

Figure 4.10. Displaying a tabbed page with the MultiView control.

In Listing 4.17, the Menu control is associated with a CSS class named tabs. This class relatively positions the Menu control down one pixel to merge the bottom border of the Menu control with the top border of the <div> tag that contains the MultiView. Because the selected tab has a white bottom border, the border between the selected tab and the tab contents disappears.

Displaying a Multi-Part Form

You can use the MultiView control to divide a large form into several sub-forms. You can associate particular commands with button controls contained in a MultiView. When the button is clicked, the MultiView changes the active view.

The MultiView control recognizes the following commands:

  • NextView—Causes the MultiView to activate the next View control.

  • PrevView—Causes the MultiView to activate the previous View control.

  • SwitchViewByID—Causes the MultiView to activate the view specified by the button control’s CommandArgument.

  • SwitchViewByIndex—Causes the MultiView to activate the view specified by the button control’s CommandArgument.

You can use these commands with any of the button controls—Button, LinkButton, and ImageButton—by setting the button control’s CommandName property and, in the case of the SwitchViewByID and SwitchViewByIndex, by setting the CommandArgument property.

The page in Listing 4.18 illustrates how you can use the NextView command to create a multiple-part form.

Example 4.18. MultiViewForm.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    Sub View3_Activate(ByVal sender As Object, ByVal e As EventArgs)
        lblFirstNameResult.Text = txtFirstName.Text
        lblColorResult.Text = txtColor.Text
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>MultiView Form</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:MultiView
        id="MultiView1"
        ActiveViewIndex="0"
        Runat="server">
        <asp:View ID="View1" runat="server">
        <h1>Step 1</h1>
        <asp:Label
            id="lblFirstName"
            Text="Enter Your First Name:"
            AssociatedControlID="txtFirstName"
            Runat="server" />
        <br />
        <asp:TextBox
            id="txtFirstName"

            Runat="server" />

        <br /><br />

        <asp:Button
            id="btnNext"
            Text="Next"
            CommandName="NextView"
            Runat="server" />

        </asp:View>
        <asp:View ID="View2" runat="server">
        <h1>Step 2</h1>
        <asp:Label
            id="Label1"
            Text="Enter Your Favorite Color:"
            AssociatedControlID="txtColor"
            Runat="server" />
        <br />
        <asp:TextBox
            id="txtColor"
            Runat="server" />

        <br /><br />

        <asp:Button
            id="Button1"
            Text="Next"
            CommandName="NextView"
            Runat="server" />

        </asp:View>
        <asp:View ID="View3" runat="server" OnActivate="View3_Activate">
        <h1>Summary</h1>
        Your First Name:
        <asp:Label
            id="lblFirstNameResult"
            Runat="server" />
        <br /><br />
        Your Favorite Color:
        <asp:Label
            id="lblColorResult"
            Runat="server" />
        </asp:View>

    </asp:MultiView>

    </div>
    </form>
</body>
</html>

The first two View controls in Listing 4.18 contain a Button control. These Button controls both have a CommandName property set to the value NextView.

Displaying a Wizard

The Wizard control, like the MultiView control, can be used to divide a large form into multiple sub-forms. The Wizard control, however, supports many advanced features that are not supported by the MultiView control.

The Wizard control contains one or more WizardStep child controls. Only one WizardStep is displayed at a time.

The Wizard control supports the following properties (this is not a complete list):

  • ActiveStep—Enables you to retrieve the active WizardStep control.

  • ActiveStepIndex—Enables you to set or get the index of the active WizardStep control.

  • CancelDestinationPageUrl—Enables you to specify the URL where the user is sent when the Cancel button is clicked.

  • DisplayCancelButton—Enables you to hide or display the Cancel button.

  • DisplaySideBar—Enables you to hide or display the Wizard control’s side bar. The side bar displays a list of all the wizard steps.

  • FinishDestinationPageUrl—Enables you to specify the URL where the user is sent when the Finish button is clicked.

  • HeaderText—Enables you to specify the header text that appears at the top of the Wizard control.

  • WizardSteps—Enables you to retrieve the WizardStep controls contained in the Wizard control.

The Wizard control also supports the following templates:

  • FinishNavigationTemplate—Enables you to control the appearance of the navigation area of the finish step.

  • HeaderTemplate—Enables you control the appearance of the header area of the Wizard control.

  • SideBarTemplate—Enables you to control the appearance of the side bar area of the Wizard control.

  • StartNavigationTemplate—Enables you to control the appearance of the navigation area of the start step.

  • StepNavigationTemplate—Enables you to control the appearance of the navigation area of steps that are not start, finish, or complete steps.

The Wizard control also supports the following methods:

  • GetHistory()—Enables you to retrieve the collection of WizardStep controls that have been accessed.

  • GetStepType()—Enables you to return the type of WizardStep at a particular index. Possible values are Auto, Complete, Finish, Start, and Step.

  • MoveTo()—Enables you to move to a particular WizardStep.

The Wizard control also supports the following events:

  • ActiveStepChanged—Raised when a new WizardStep becomes the active step.

  • CancelButtonClick—Raised when the Cancel button is clicked.

  • FinishButtonClick—Raised when the Finish button is clicked.

  • NextButtonClick—Raised when the Next button is clicked.

  • PreviousButtonClick—Raised when the Previous button is clicked.

  • SideBarButtonClick—Raised when a side bar button is clicked.

A Wizard control contains one or more WizardStep controls that represent steps in the wizard. The WizardStep control supports the following properties:

  • AllowReturn—Enables you to prevent or allow a user to return to this step from a future step.

  • Name—Enables you to return the name of the WizardStep control.

  • StepType—Enables you to get or set the type of wizard step. Possible values are Auto, Complete, Finish, Start and Step.

  • Title—Enables you to get or set the title of the WizardStep. The title is displayed in the wizard side bar.

  • Wizard—Enables you to retrieve the Wizard control containing the WizardStep.

The WizardStep also supports the following two events:

  • Activate—Raised when a WizardStep becomes active.

  • Deactivate—Raised when another WizardStep becomes active.

The StepType property is the most important property. This property determines how a WizardStep is rendered. The default value of StepType is Auto. When StepType is set to the value Auto, the position of the WizardStep in the WizardSteps collection determines how the WizardStep is rendered.

You can explicitly set the StepType property to a particular value. If you set StepType to the value Start, then a Previous button is not rendered. If you set the StepType to Step, then both Previous and Next buttons are rendered. If you set StepType to the value Finish, then Previous and Finish buttons are rendered. Finally, when StepType is set to the value Complete, no buttons are rendered.

The page in Listing 4.19 illustrates how you can use a Wizard control to display a multiple part form (see Figure 4.11).

Example 4.19. ShowWizard.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    Sub Wizard1_FinishButtonClick(ByVal sender As Object, ByVal e As WizardNavigationEventArgs)
        lblSSNResult.Text = txtSSN.Text
        lblPhoneResult.Text = txtPhone.Text
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .wizard
        {
            border:solid 1px black;
            font:14px Verdana,Sans-Serif;
            width:400px;
            height:300px;
        }
        .header
        {
            color:gray;
            font:bold 18px Verdana,Sans-Serif;
        }
        .sideBar
        {
            background-color:#eeeeee;
            padding:10px;
            width:100px;
        }
        .sideBar a
        {
            text-decoration:none;
        }
        .step
        {
            padding:10px;
        }
    </style>
    <title>Show Wizard</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Wizard
        id="Wizard1"
        HeaderText="Product Survey"
        OnFinishButtonClick="Wizard1_FinishButtonClick"
        CssClass="wizard"
        HeaderStyle-CssClass="header"
        SideBarStyle-CssClass="sideBar"
        StepStyle-CssClass="step"
        Runat="server">
        <WizardSteps>
        <asp:WizardStep ID="WizardStep1" Title="Introduction">
        Please complete our survey so that we can improve our
        products.
        </asp:WizardStep>
        <asp:WizardStep ID="WizardStep2" Title="Step 1">
        <asp:Label
            id="lblSSN"
            Text="Social Security Number:"
            AssociatedControlID="txtSSN"
            Runat="server" />
        <br />
        <asp:TextBox
            id="txtSSN"
            Runat="server" />
        </asp:WizardStep>
        <asp:WizardStep ID="WizardStep3" Title="Step 2" StepType="Finish">
        <asp:Label
            id="lblPhone"
            Text="Phone Number:"
            AssociatedControlID="txtPhone"
            Runat="server" />
        <br />
        <asp:TextBox
            id="txtPhone"
            Runat="server" />
        </asp:WizardStep>
        <asp:WizardStep ID="WizardStep4" Title="Summary" StepType="Complete">
        <h1>Summary</h1>
        Social Security Number:
        <asp:Label
            id="lblSSNResult"
            Runat="server" />
        <br /><br />
        Phone Number:

        <asp:Label
            id="lblPhoneResult"
            Runat="server" />
        </asp:WizardStep>
        </WizardSteps>
    </asp:Wizard>

    </div>
    </form>
</body>
</html>
Displaying a wizard with the Wizard control.

Figure 4.11. Displaying a wizard with the Wizard control.

The Wizard control in Listing 4.19 contains four WizardStep controls. Notice that the StepType property is explicitly set for the last two WizardStep controls. When the Finish WizardStep is rendered, a Finish button is rendered. When the Complete WizardStep is rendered, no buttons are rendered.

The Wizard control’s FinishButtonClick event is handled with a method named Wizard1_FinishButtonClick(). This method updates the final WizardStep with a summary of the answers entered in the previous WizardStep controls.

Summary

This chapter tackled the rich controls. You learned how to perform file uploads with the FileUpload control. You also saw how to accept and display large file uploads by dividing the file into smaller chunks.

You also learned how to use the Calendar control to display a date picker and render a schedule of events. Using a tiny bit of JavaScript, you learned how to create a fancy pop-up date picker.

This chapter also discussed the AdRotator control. You learned how to store a list of advertisements in both an XML file and a database table. You also learned how to track advertisement impressions and transfers and build a statistics page.

You also learned how to use the MultiView control to display different views of a page. You learned how to create a tabbed page by using the MultiView control with the Menu control. You also learned how to use the MultiView to divide a large form into multiple sub-forms.

Finally, we discussed the Wizard control. You learned how to use the Wizard control to render navigation elements automatically for completing a multiple-step task.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset