Chapter 24

Ajax Control Toolkit

WHAT’S IN THIS CHAPTER?

WROX.COM CODE DOWNLOADS FOR THIS CHAPTER

Please note that all the code examples in this chapter are available as a part of this chapter’s code download on the book’s website at www.wrox.com on the Download Code tab.

ASP.NET AJAX applications were introduced in the previous chapter. You might be wondering why there were so few server controls for ASP.NET AJAX, given that ASP.NET Web Forms heavily rely on this way of modularizing code. The reason is that Microsoft has treated them as an open source project instead of just blending them into Visual Studio 2012.

Developers at Microsoft and in the community have developed a series of Ajax-capable server controls that you can use in your ASP.NET applications. Originally, these controls were collectively called the ASP.NET AJAX Control Toolkit. However, Microsoft eventually rebranded the library a bit, making it sound less like a part of ASP.NET. It is now called the Ajax Control Toolkit and is hosted at CodePlex at http://ajaxcontroltoolkit.codeplex.com/. Figure 24-1 shows the download page for the Ajax Control Toolkit.

FIGURE 24-1

image

As you may remember from the previous chapter, ASP.NET AJAX is the foundation on which to build richer web applications that leverage the browser more fully, but it does not have the rich UI elements that really blur the distinction between web and desktop applications. ASP.NET AJAX includes several powerful ASP.NET controls that make adding Ajax functionality to an existing application or building better user experiences into a new application easy. The Ajax Control Toolkit, however, was developed to provide rich ASP.NET AJAX controls that you can use to make your web applications really come to life. The toolkit makes pushing the user interface of an application beyond what users expect from a web application easy.

The toolkit is a shared source project with code contributions from developers from Microsoft and elsewhere. Most developers who work with ASP.NET AJAX should also download the toolkit for the additional set of controls it contains. The Ajax Control Toolkit download mentioned earlier enables you to download a compiled DLL with the controls and extenders, or you can download the source code and project files and compile it yourself. Either way, make sure you add the DLL to your toolbox in Visual Studio, as described shortly.

The toolkit contains some controls that have Ajax functionality and many control extenders. The control extenders attach to another control to enhance or “extend” the control’s functionality. Because the controls cover such a wide variety of application-development areas, the ones we chose to cover are listed alphabetically and the control names are self-explanatory to make locating the information you need when using this chapter for later reference easy.

Also, note that the toolkit project is ongoing and will continue to evolve as developers contribute to it. This chapter is up-to-date as of the time of this writing, but the expectation is that more will be added to the toolkit regularly. Chapter 25 covers a truly open source project that provides similar functionality, but is completely independent of Microsoft technologies. So whereas the Ajax Control Toolkit is closely tied to ASP.NET and therefore a bit easier to use at first, you should not miss the following chapter to see a well-maintained alternative, jQuery.

DOWNLOADING AND INSTALLING THE AJAX CONTROL TOOLKIT

Because the Ajax Control Toolkit is not part of the default install of Visual Studio 2012, you must set up the controls yourself. Again, the Control Toolkit’s site offers a couple of options.

The CodePlex site offers versions of the Ajax Control Toolkit for .NET 3.5, 4.0, and 4.5. This chapter focuses on using the control toolkit with Visual Studio 2012 and the .NET Framework 4.5. You can also completely omit the project homepage and use NuGet to add the Ajax Control Toolkit to a project:

Install-Package AjaxControlToolkit

If you would like to see prior to the installation what you are actually adding to the project, we recommend the manual installation. To get set up, download the .zip file from the aforementioned site at http://ajaxcontroltoolkit.codeplex.com/ and unzip it where you want it on your machine. Then follow these steps:

1. Install the controls into Visual Studio. Adding the controls to your Visual Studio 2012 toolbox is very easy. Right-click in the toolbox and select Add Tab from the provided menu. Name the tab as you want — for this example, the tab is called Ajax Controls.
2. With the new tab in your toolbox, right-click the tab and select Choose Items from the provided menu, as illustrated in Figure 24-2. The Choose Toolbox Items dialog box appears.
3. Select the AjaxControlToolkit.dll from the download. When you find the DLL and click Open, Visual Studio 2012 first asks you if you really want to install something from the Internet (see Figure 24-3). If you agree, the Choose Toolbox Items dialog box changes to include the controls that are contained within this DLL. The controls are highlighted in the dialog box and are already selected for you (as shown in Figure 24-4).
4. Click OK, and the Ajax Control Toolkit’s controls are added to your Visual Studio toolbox. Figure 24-5 presents the end result.

More than 40 controls and extenders have been added to the toolbox for use in your ASP.NET applications.

THE ASP.NET AJAX CONTROLS

The number of controls and extenders available from the control toolkit is large. As stated, more than 40 controls and extenders are at your disposal. This section looks at these items and how you can use them in your ASP.NET applications.

When you add an ASP.NET AJAX server control to your page, you may notice that a number of DLLs focused on localization into a number of languages have been added to the Bin folder of your solution. All the resource files have been organized into language folders within the folder. Figure 24-6 presents an example of what you will find.

FIGURE 24-6

image

In addition to the localization DLLs added to your project, the ASP.NET AJAX control is added just as any other custom server control in ASP.NET. Listing 24-1 shows what your ASP.NET page should look like after the addition of a single ASP.NET AJAX control to it.

LISTING 24-1: Changes to the ASP.NET page after adding an Ajax Control Toolkit control

<%@ Page Language="C#" AutoEventWireup="true"
    CodeFile="Default.aspx.cs" Inherits="_Default" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
        
<html>
<head runat="server">
    <title>First Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
       <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" />
        
        <asp:AlwaysVisibleControlExtender
         ID="AlwaysVisibleControlExtender1" runat="server"
         TargetControlID="TextBox1">
        </asp:AlwaysVisibleControlExtender>
        
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

In this example, you can see that the ASP.NET AJAX control is registered on the page using the @Register directive. This directive points to the AJAXControlToolkit assembly and gives all controls that use this assembly reference a tag prefix of asp. Visual Studio 2012 by default adds the reference to web.config, but in order to make our code as self-contained as possible, we moved these references to the top using @Register for this chapter.

Another interesting aspect to the controls that are provided through the Ajax Control Toolkit is the ToolkitScriptManager control (which you need to add manually; Visual Studio does not do that for you automatically). This control derives from the base ScriptManager control and extends it to handle script combining for you by default, thus making your pages more expedient than before. The examples provided in this chapter make use of this newer version of the ScriptManager control.

Ajax Control Toolkit Extenders

The first set of items you look at includes the extenders that are part of the Ajax Control Toolkit. Extenders are basically controls that reach out and extend other controls. For example, you can think of the ASP.NET Validation Controls (covered in Chapter 6 of this book) as extender controls themselves. For instance, you can add a RequiredFieldValidator server control to a page and associate it to a TextBox control. This extends the TextBox control and changes its behavior. Normally it would just accept text. Now, if nothing is entered into the control, then the control will trigger an event back to the RequiredFieldValidator control whose client-side behavior is controlled by JavaScript.

The Ajax Control Toolkit’s extenders accomplish the same thing. The controls extend the behavior of the ASP.NET server controls with additional JavaScript on the client as well as some server-side communications.

AlwaysVisibleControlExtender

When presenting information in the browser, you may want to keep a piece of information fixed in the user’s view. Screen space is a limited commodity, and sometimes a screen element should always be available without the user ever having to scroll. The AlwaysVisibleControlExtender lets you designate any ASP.NET control as having this distinction. You specify a position for the control using the AlwaysVisibleControlExtender, and while the user scrolls the page to view other information, the control you designate is always kept in view. It seems to move around as the user scrolls the screen or resizes the window, so that it stays in the same relative position in the viewable portion of the browser window.

The AlwaysVisibleControlExtender has only six properties. Listing 24-2 presents an example of using this control.

LISTING 24-2: Using the AlwaysVisibleControlExtender

VB

<%@ Page Language="VB" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<script runat="server">
    Protected Sub Button1_Click(ByVal sender As Object, _
       ByVal e As System.EventArgs)
        Response.Write("The page has been submitted!")
    End Sub
</script>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>AlwaysVisibleControlExtender</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" />
        <asp:AlwaysVisibleControlExtender
         ID="AlwaysVisibleControlExtender1"
            runat="server" TargetControlID="Panel1"
            HorizontalOffset="10"
            HorizontalSide="Right" VerticalOffset="10">
        </asp:AlwaysVisibleControlExtender>
        Form Element :
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <br />
        Form Element :
        <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
        <br />
        
        <!-- Excessive code removed for clarity -->
        
        Form Element :
        <asp:TextBox ID="TextBox29" runat="server"></asp:TextBox>
        <br />
        Form Element :
        <asp:TextBox ID="TextBox30" runat="server"></asp:TextBox>
        <br />
        <br />
        <asp:Panel ID="Panel1" runat="server">
            <asp:Button ID="Button1" runat="server" Text="Submit"
             OnClick="Button1_Click" />
            <asp:Button ID="Button2" runat="server" Text="Clear" />
        </asp:Panel>
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<script runat="server">
    protected void Button1_Click(object sender, EventArgs e)
    {
        Response.Write("The page has been submitted!");
    }
</script>

This code presents a very long form that requires end users to scroll the page in their browser. The AlwaysVisibleControlExtender control is present, and its presence requires that you also have a ScriptManager control on the page (this is the same requirement for all ASP.NET AJAX controls).

The AlwaysVisibleControlExtender1 control extends the Panel1 control through the use of the TargetControlID attribute. In this case, the value of the TargetControlID attribute points to the Panel1 control. The Panel1 control contains the form’s Submit button. The result of the code from Listing 24-2 is shown in Figure 24-7.

FIGURE 24-7

image

The location of the Submit and Clear buttons on the page is controlled via a combination of several control attributes. The location on the page is determined by the HorizontalSide (possible values include Center, Left, and Right) and VerticalSide properties (possible values include Bottom, Middle, and Top). A padding is also placed around the control using the HorizontalOffset and VerticalOffset properties, both of which are set to 10 pixels in this example.

AnimationExtender

The AnimationExtender server control provides a tremendous amount of capabilities. It enables you to program fluid animations to the controls that you put on the page. You can do a lot with this control — much more than can be shown in this chapter.

This control enables you to program elements that can move around the page based on specific end-user triggers (such as a button click). Specific events are available for you to program your animations against. These events are as follows:

Creating animations is not as straightforward as many would like because it has little Visual Studio support, such as wizards or even IntelliSense. For an example of creating your first animation, Listing 24-3 shows how you can fade an element in and out of the page based on an end-user action.

LISTING 24-3: Using the AnimationExtender to fade a background color

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>AnimationExtender</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" />
        <asp:AnimationExtender ID="AnimationExtender1" runat="server"
            TargetControlID="Panel1">
            <Animations>
                <OnClick>
                    <Sequence>
                        <Color PropertyKey="background"
                         StartValue="#999966"
                         EndValue="#FFFFFF" Duration="5.0" />
                    </Sequence>
                </OnClick>
            </Animations>
        </asp:AnimationExtender>
        <asp:Panel ID="Panel1" runat="server" BorderColor="Black"
            BorderWidth="3px" Font-Bold="True" Width="600px">
            Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
            Donec accumsan lorem. Ut consectetuer tempus metus.
            Aenean tincidunt venenatis tellus. Suspendisse molestie
            cursus ipsum. Curabitur ut lectus. Nulla ac dolor nec elit
            convallis vulputate. Nullam pharetra pulvinar nunc. Duis
            orci. Phasellus a tortor at nunc mattis congue.
            Vestibulum porta tellus eu orci. Suspendisse quis massa.
            Maecenas varius, erat non ullamcorper nonummy, mauris erat
            eleifend odio, ut gravida nisl neque a ipsum. Vivamus
            facilisis. Cras viverra. Curabitur ut augue eget dolor
            semper posuere. Aenean at magna eu eros tempor
            pharetra. Aenean mauris.
        </asp:Panel>
    </div>
    </form>
</body>
</html>

In this case, when you open the page from Listing 24-3, you will see that it uses a single AnimationExtender control that is working off the Panel1 control. This connection is made using the TargetControlID property.

As stated, IntelliSense is not enabled when you are typing the code that is contained within the AnimationExtender control, so you need to look in the documentation for the animations that you want to create. In the case of the previous example, the <OnClick> element is utilized to define a sequence of events that needs to occur when the control is clicked. For this example, only one animation is defined within the <Sequence> element — a color change to the background of the element. Here, the <Color> element states that the background CSS property will need to start at the color #999966 and change completely to color #FFFFFF within 5 seconds (defined using the Duration property).

When you open this page and click the Panel element, you will see the color change in a 5-second duration from the described start color to the end color.

AutoCompleteExtender

The AutoCompleteExtender control enables you to help end users find what they might be looking for when they need to type in search terms within a textbox. This feature, used on a lot of search sites today, helps in that when you start typing characters in the textbox, you get results from a datastore as a drop-down list directly below the textbox you are working with that match what you have typed so far.

To establish something similar for yourself, create a new page that contains only a ScriptManager control, an AutoCompleteExtender control, and a TextBox control. The ASP.NET portion of the page should appear as presented in Listing 24-4 (AutoCompleteExtender.aspx in the code download for this chapter).

LISTING 24-4: The ASP.NET page

<%@ Page Language="C#" AutoEventWireup="true"
    CodeFile="AutoComplete.aspx.cs" Inherits="AutoComplete" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>AutoComplete</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:AutoCompleteExtender ID="AutoCompleteExtender1"
         runat="server" TargetControlID="TextBox1"
         ServiceMethod="GetCompletionList" UseContextKey="True">
        </asp:AutoCompleteExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

Again, like the other ASP.NET AJAX controls, you extend the TextBox control using the TargetControlID property. When you first add these controls to the page, you will not have the ServiceMethod property defined in the AutoCompleteExtender control. Using Visual Studio 2012, you can make the framework for a service method and tie the extender control to this method all from the design surface. After expanding the TextBox control’s smart tag, select the Add AutoComplete page method option from the provided menu, shown in Figure 24-8.

FIGURE 24-8

image

This action creates a service method in the code-behind for your page. Listing 24-5 (AutoCompleteExtender.aspx.vb and AutoCompleteExtender.aspx.cs in the code download for this chapter) shows the steps necessary to complete this method to call the company names from Microsoft’s classic Northwind database.


NOTE You can find instructions on downloading and using the Northwind database with Visual Studio 2012 at http://msdn.microsoft.com/en-us/library/8b6y4c7s.aspx. The version of the Northwind database that we used for this book is available for download at www.wrox.com/go/SQLServer2012DataSets.

LISTING 24-5: The code-behind that sets up the service method for auto-complete

VB

Imports System.Data
Imports System.Data.SqlClient
        
Partial Class AutoComplete
    Inherits System.Web.UI.Page
        
    <System.Web.Services.WebMethodAttribute(),
     System.Web.Script.Services.ScriptMethodAttribute()>
    Public Shared Function GetCompletionList(ByVal _
      prefixText As String, ByVal count As Integer) As String()
        Dim conn As SqlConnection
        Dim cmd As SqlCommand
        Dim cmdString As String =
      "Select CompanyName from Customers WHERE CompanyName LIKE " & _
           "@prefixText"
        conn = New SqlConnection("Data Source=.\SQLEXPRESS;
           AttachDbFilename=|DataDirectory|\NORTHWND.MDF;
           Integrated Security=True;User Instance=True")
        ' Put this string on one line in your code
        cmd = New SqlCommand(cmdString, conn)
        cmd.Parameters.AddWithValue("@prefixText", prefixText & "%")
        conn.Open()
        
        Dim myReader As SqlDataReader
        Dim returnData As List(Of String) = New List(Of String)
        myReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
        
        While myReader.Read()
            returnData.Add(myReader("CompanyName").ToString())
        End While
        
        Return returnData.ToArray()
    End Function
End Class

C#

using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
public partial class AutoComplete : System.Web.UI.Page
{
    [System.Web.Services.WebMethodAttribute(),
     System.Web.Script.Services.ScriptMethodAttribute()]
    public static string[] GetCompletionList(string prefixText,
       int count, string contextKey)
    {
        SqlConnection conn;
        SqlCommand cmd;
        string cmdString =
         "Select CompanyName from Customers WHERE CompanyName LIKE " +
           "@prefixText";
        conn = new
            SqlConnection(@"Data Source=.\SQLEXPRESS;
            AttachDbFilename=|DataDirectory|\NORTHWND.MDF;
            Integrated Security=True;User Instance=True");
        // Put this string on one line in your code
        cmd = new SqlCommand(cmdString, conn);
        cmd.Parameters.AddWithValue("@prefixText", prefixText + "%");
        conn.Open();
        
        SqlDataReader myReader;
        List<string> returnData = new List<string>();
        
        myReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        
        while (myReader.Read())
        {
            returnData.Add(myReader["CompanyName"].ToString());
        }
        
        return returnData.ToArray();
    }
}

When you run this page and type the characters ant into the textbox, the GetCompletionList() method is called, passing in these characters. These characters are retrievable through the prefixText parameter (you can also use the count parameter, which is defaulted at 10). The Northwind database is called using the prefixText value and this is what is returned back to the TextBox1 control. In the end, you get a drop-down list of the items that match the first three characters that were entered into the textbox. This is illustrated in Figure 24-9.

FIGURE 24-9

image

It is good to know that the results, once called the first time, are cached. This caching is controlled via the EnableCaching property (it is defaulted to true). You can also change the style of the drop-down auto-complete list, configure how many elements appear, and much more with this feature. One more important point is that you are not required to call out a method that is exposed on the same page as the control, as the example in this book demonstrates, but you can also call out another server-side method on another page, or a web method.

BalloonPopupExtender

One of the most requested additions to the Ajax Control Toolkit has always been a control that provides a balloon-like UI added to an element. Finally, starting with the November 2011 edition of the Ajax Control Toolkit, the team gave in and added such a control.

The BalloonPopupExtender adds a “balloon” to the element referenced in the TargetControlID. The actual content of the balloon resides in an arbitrary control on the page; the extender's BalloonPopupControlID property contains the ID of that control.

The extender supports several built-in styles (BalloonStyle property) and sizes (BalloonSize property), and also custom styling. Listing 24-6 shows an example of providing a cloud-like balloon for a TextBox control.

LISTING 24-6: Adding a balloon to a TextBox control

<%@ Page Language="C#" %>
 
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
 
<!DOCTYPE html>
 
<script runat="server">
 
</script>
 
<!DOCTYPE html>
<html>
<head runat="server">
    <title>BalloonPopupExtender</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
 
        <asp:TextBox ID="TextBox1" runat="server" />
        <asp:Panel ID="Panel1" runat="server">
            Please enter your country.
        </asp:Panel>
 
        <asp:BalloonPopupExtender ID="BalloonPopupExtender1" runat="server"
            TargetControlID="TextBox1"
            BalloonPopupControlID="Panel1"
            BalloonStyle="Cloud" BalloonSize="Small" />
    
    </div>
    </form>
</body>
</html>

When you click in the textbox, the balloon appears, as shown in Figure 24-10.

FIGURE 24-10

image

CalendarExtender

Selecting a date is a common requirement of many applications. It is also one of the most common points in a form that can hinder form submission. End users are often slowed down by trying to figure out the format of the date that the form requires. The CalendarExtender control enables you to make it simple for your end users to select a date within a form. The CalendarExtender attaches to a textbox and pops up a calendar for selecting a date. By default, the calendar is shown when the textbox gets focus, but if you set the PopupButtonID to the ID of another control, the calendar becomes visible when that control is clicked.

The best way to set up fast date selection in a form is to provide a calendar that can be navigated and allow a date to quickly be selected, which will then be translated to a textual date format in the textbox. The CalendarExtender is very easy to use with just a few key properties. The TargetControlID points to the textbox that receives the selected date. The Format property specifies the string format for the date input of the textbox. The CalendarExtender control gives you all the client-side code required for this kind of action. Listing 24-7 shows you an example of providing a calendar control off your textbox controls.

LISTING 24-7: Using a calendar control from a TextBox control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>CalendarExtender</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:CalendarExtender ID="CalendarExtender1" runat="server"
         TargetControlID="TextBox1">
        </asp:CalendarExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

When you run this page, the result is a single textbox on the page, appearing no different from any other textbox. However, when the end user clicks inside the textbox, a calendar appears directly below it, as shown in Figure 24-11.

FIGURE 24-11

image

Then, when the end user selects a date from the calendar, the date is placed as text within the textbox.

Some of the properties exposed from this control are FirstDayOfWeek and PopupPosition (which has the options BottomLeft, BottomRight, TopLeft, and TopRight). You can also change how the calendar is initiated on the client. Some sites offer a calendar button next to the textbox and only pop up the calendar option when the end user clicks the button. If this is something that you want to do on your pages, use the PopupButtonID property, which you must point to the ID of the image or button that you are using.

CollapsiblePanelExtender

The CollapsiblePanelExtender server control enables you to collapse one control into another. When working with two Panel server controls, you can provide a nice way to control any real estate issues that you might be experiencing on your ASP.NET page.

The CollapsiblePanelExtender is similar to the Accordion control (presented later in this chapter), but it does not target multiple content areas. An ASP.NET panel control is shown or hidden from view based on the user’s interaction with a given control. This enables you to hide something the user does not always need to see. The TargetControlID is shown when the ExpandControlID is clicked or hidden when the CollapseControlID is clicked. Alternatively, it can be shown or hidden based on a mouse hover if the AutoCollapse and AutoExpand properties are set to True.

Listing 24-8 demonstrates the use of a CollapsiblePanelExtender to set the panel size to 0 when it is collapsed and to 300 pixels when it is expanded. Another panel is used as the selector for expanding and collapsing the panel. In addition, a label is included that is designated as the TextLabelID. The value of the Label control is changed between the ExpandedText and CollapsedText values based on the current state.

LISTING 24-8: Using CollapsiblePanelExtender with two Panel controls

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
    <title>CollapsiblePanelExtender</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:Panel ID="Panel1" runat="server" BackColor="#000066"
         ForeColor="White">
            <asp:Label ID="Label2" runat="server"
             Text="This is my title"></asp:Label>
            <asp:Label ID="Label1" runat="server"></asp:Label>
        </asp:Panel>
        <asp:Panel ID="Panel2" runat="server" Style="overflow: hidden;"
         Height="0">
            Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
            Donec accumsan lorem. Ut consectetuer tempus metus.
            Aenean tincidunt venenatis tellus. Suspendisse molestie
            cursus ipsum. Curabitur ut lectus. Nulla ac dolor nec elit
            convallis vulputate. Nullam pharetra pulvinar nunc. Duis
            orci. Phasellus a tortor at nunc mattis congue. Vestibulum
            porta tellus eu orci. Suspendisse quis massa.
            Maecenas varius, erat non ullamcorper nonummy, mauris erat
            eleifend odio, ut gravida nisl neque a ipsum. Vivamus
            facilisis. Cras viverra. Curabitur ut augue eget dolor
            semper posuere. Aenean at magna eu eros tempor pharetra.
            Aenean mauris.
        </asp:Panel>
        <asp:CollapsiblePanelExtender ID="CollapsiblePanelExtender1"
         runat="server"
         TargetControlID="Panel2" Collapsed="true"
         ExpandControlID="Panel1"
         CollapseControlID="Panel1"
         CollapsedSize="1"
         ExpandedSize="300" CollapsedText="[Click to expand]"
         ExpandedText="[Click to collapse]" TextLabelID="Label1"
         SuppressPostBack="true">
        </asp:CollapsiblePanelExtender>
    </div>
    </form>
</body>
        
</html>

In this case, when the page opens for the first time you will see only the contents of Panel1 — the title panel. By default, you would usually see both controls, but because the Collapsed property is set to True in the control, you will see only Panel1. Clicking the Panel control will then expose the contents of Panel2. In fact, the contents will slide out from the Panel1 control. Tying these two controls together to perform this action is accomplished through the use of the CollapsiblePanelExtender control. This control’s TargetControlID is assigned to the second Panel control — Panel2, because this is the control that needs to expand onto the page. The ExpandControlID property is the control that initiates the expansion.

Once expanded, it is when the end user clicks Panel2 that the contents will disappear by sliding back into Panel1. This is accomplished through the use of the CollapseControlID property being assigned to Panel2.

The CollapsiblePanelExtender control has a number of properties that enable you to fine-tune how the expanding and collapsing occur. For instance, you could have also set the Label1 control to be the initiator of this process and even change the text of the Label control depending on the whether Panel2 is collapsed or expanded.

ColorPickerExtender

One of the difficult data points to retrieve from an end user is color. This particular data point is tough to define if you are using just text. If you have an open selection of colors, how does the end user define a darker shade of blue? For this reason, you have the ColorPickerExtender to quickly and easily extend something like a TextBox control to a tool that makes this selection process a breeze. Listing 24-9 shows a quick and easy way to do this task.

LISTING 24-9: Using the ColorPickerExtender control to allow for color selection

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>ColorPickerExtender</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <br />
        Pick your favorite color:<br />
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:ColorPickerExtender ID="ColorPickerExtender1"
         runat="server" TargetControlID="TextBox1">
        </asp:ColorPickerExtender>
    </div>
    </form>
</body>
</html>

When this page opens, you simply have a single TextBox server control on the page. Applying focus to this TextBox control pops up the color selector, as illustrated here in black and white in Figure 24-12.

FIGURE 24-12

image

The end user then can scroll across the color options and after the user selects one of these colors, the pop-up disappears and the hexadecimal color code is shown in the TextBox. This end result is presented here in Figure 24-13.

FIGURE 24-13

image

ConfirmButtonExtender and ModalPopupExtender

Usually before allowing your end users to make deletions of data via a browser application, you want to confirm such actions with the end user. ConfirmButtonExtender enables you to question the end user’s action and reconfirm that he wants the action to occur. Listing 24-10 shows how to use this control.

LISTING 24-10: Using the ConfirmButtonExtender control to reconfirm a user action

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>ConfirmButtonExtender</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:ConfirmButtonExtender ID="ConfirmButtonExtender1"
         runat="server" TargetControlID="Button1"
         ConfirmText="Are you sure you wanted to click this button?">
        </asp:ConfirmButtonExtender>
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </div>
    </form>
</body>
</html>

In this case, the ConfirmButtonExtender extends the Button1 server control and adds a confirmation dialog box using the text defined with the ConfirmText property. Figure 24-14 shows this page.

FIGURE 24-14

image

If the end user clicks OK in this instance, the page functions normally as if the dialog box never occurred. However, if Cancel is clicked, the dialog box, by default, disappears and the form will not be submitted (it will be as if the button were not clicked at all). In this case, you can also capture the Cancel button being clicked and perform a client-side operation by using the OnClientClick event and giving it a value of a client-side JavaScript function.

Instead of using the browser’s modal dialog boxes, you can even go as far as creating your own to use as the confirmation form. To accomplish this task, you need to use the ModalPopupExtender server control. The ModalPopupExtender control points to another control to use for the confirmation.

The ModalPopupExtender prevents the user from interacting with the underlying page until a modal dialog box has been addressed by the user. It is very similar to the HoverMenuExtender, except that the user must work with the control designated by the PopupControlID before he can proceed. It has properties for specifying the OkControlID and the CancelControlID, along with OnOkScript and OnCancelScript properties that will run based on the user’s selection. Listing 24-11 shows how to use this control.

LISTING 24-11: Using the ModalPopupExtender control to create your own confirmation form

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>ConfirmButtonExtender</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:ConfirmButtonExtender ID="ConfirmButtonExtender1"
         runat="server" TargetControlID="Button1"
         DisplayModalPopupID="ModalPopupExtender1">
        </asp:ConfirmButtonExtender>
        <asp:ModalPopupExtender ID="ModalPopupExtender1" runat="server"
            CancelControlID="ButtonNo" OkControlID="ButtonYes"
            PopupControlID="Panel1"
            TargetControlID="Button1">
        </asp:ModalPopupExtender>
        <asp:Button ID="Button1" runat="server" Text="Button" />
        <asp:Panel ID="Panel1" runat="server"
         style="display:none; background-color:White; width:200;
         border-width:2px; border-color:Black; border-style:solid;
         padding:20px;">
         Are you sure you wanted to click this button?<br />
         <asp:Button ID="ButtonYes" runat="server" Text="Yes" />
         <asp:Button ID="ButtonNo" runat="server" Text="No" />
        </asp:Panel>
    </div>
    </form>
</body>
</html>

In this example, the ConfirmButtonExtender still points to the Button1 control on the page, meaning that when the button is clicked, the ConfirmButtonExtender takes action. Instead of using the ConfirmText property, the DisplayModalPopupID property is used. In this case, it points to the ModalPopupExtender1 control — another extender control.

The ModalPopupExtender control, in turn, references the Panel1 control on the page through the use of the PopupControlID property. The contents of this Panel control are used for the confirmation on the button click. For this to work, the ModalPopupExtender control must have a value for the OkControlID and the CancelControlID properties. In this case, these two properties point to the two Button controls that are contained within the Panel control. When you run this page, you get the results shown in Figure 24-15.

FIGURE 24-15

image

DragPanelExtender

The DragPanelExtender enables you to define areas where end users can move elements around the page as they want. The end user actually has the ability to drag and drop the element anywhere on the browser page.

To enable this feature, you must do a few things. The first suggestion is to create a <div> area on the page that is large enough to drag the item around in. From here, you need to specify what will be used as the drag handle and another control that will follow the drag handle around. In the example in Listing 24-12, the Label control is used as the drag handle, and the Panel2 control is the content that is dragged around the screen.

LISTING 24-12: Dragging a Panel control around the page

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>DragPanel control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <div style="height: 600px;">
            <asp:DragPanelExtender ID="DragPanelExtender1"
             runat="server"
             DragHandleID="Label1" TargetControlID="Panel1">
            </asp:DragPanelExtender>
            <asp:Panel ID="Panel1" runat="server" Width="450px">
                <asp:Label ID="Label1" runat="server"
                 Text="Drag this Label control to move the control"
                 BackColor="DarkBlue" ForeColor="White"></asp:Label>
                <asp:Panel ID="Panel2" runat="server" Width="450px">
            Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
            Donec accumsan lorem. Ut consectetuer tempus metus.
            Aenean tincidunt venenatis tellus. Suspendisse molestie
            cursus ipsum. Curabitur ut lectus. Nulla ac dolor nec elit
            convallis vulputate. Nullam pharetra pulvinar nunc. Duis
            orci. Phasellus a tortor at nunc mattis congue.
            Vestibulum porta tellus eu orci. Suspendisse quis massa.
            Maecenas varius, erat non ullamcorper nonummy, mauris erat
            eleifend odio, ut gravida nisl neque a ipsum. Vivamus
            facilisis. Cras viverra. Curabitur
            ut augue eget dolor semper posuere. Aenean at magna eu eros
            tempor pharetra. Aenean mauris.
                </asp:Panel>
            </asp:Panel>
        </div>
    </div>
    </form>
</body>
</html>

This example creates a <div> element that has a height of 600 pixels. Within this defined area, the example uses a DragPanelExtender control and targets the Panel1 control through the use of the TargetControlID property being assigned to this control.

Within the Panel1 control are two other server controls — a Label and another Panel control. The Label control is assigned to be the drag handle using the DragHandleID property of the DragPanelExtender control. With this little bit of code in place, you are now able to drag the Panel1 control around on your browser window. Figure 24-16 shows the Label control being used as a handle to drag around the Panel control.

FIGURE 24-16

image

DropDownExtender

The DropDownExtender control enables you to take any control and provide a drop-down list of options below it for selection. It provides a different framework from a typical drop-down list control because it allows for an extreme level of customization. Listing 24-13 shows how you can even use an image as the initiator of a drop-down list of options.

LISTING 24-13: Using an Image control as an initiator of a drop-down list

VB

<%@ Page Language="VB" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<script runat="server">
    Protected Sub Page_Load(ByVal sender As Object, _
      ByVal e As System.EventArgs)
       Image1.ImageUrl = "Images/Creek.jpg"
    End Sub
        
    Protected Sub Option_Click(ByVal sender As Object, _
      ByVal e As System.EventArgs)
       Image1.ImageUrl = "Images/" & DirectCast(sender, _
         LinkButton).Text & ".jpg"
    End Sub
</script>
        
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>DropDownExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:DropDownExtender ID="DropDownExtender1"
                 runat="server"
                 DropDownControlID="Panel1" TargetControlID="Image1">
                </asp:DropDownExtender>
                <asp:Image ID="Image1" runat="server">
                </asp:Image>
            <asp:Panel ID="Panel1" runat="server" Height="50px"
             Width="125px">
                <asp:LinkButton ID="Option1" runat="server"
                 OnClick="Option_Click">ToolkitLogo</asp:LinkButton>
                <asp:LinkButton ID="Option2" runat="server"
                 OnClick="Option_Click">ToolkitLogo1</asp:LinkButton>
                <asp:LinkButton ID="Option3" runat="server"
                 OnClick="Option_Click">ToolkitLogo2</asp:LinkButton>
            </asp:Panel>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        Image1.ImageUrl = "Images/ToolkitLogo.jpg";
    }
        
    protected void Option_Click(object sender, EventArgs e)
    {
        Image1.ImageUrl = "Images/" + ((LinkButton)sender).Text
          + ".jpg";
    }
</script>

In this case, a DropDownExtender control is tied to an Image control that displays a specific image on the Page_Load() event. The DropDownExtender control has two specific properties that need to be filled. The first is the TargetControlID property that defines the control that becomes the initiator of the drop-down list. The second property is the DropDownControlID property, which defines the element on the page that will be used for the drop-down items that appear below the control. In this case, it is a Panel control with three LinkButton controls.

Each of the LinkButton controls designates a specific image that should appear on the page. Selecting one of the options changes the image through the Option_Click() method. Running this page gives you the results illustrated in Figure 24-17.

FIGURE 24-17

image

DropShadowExtender

The DropShadowExtender enables you to add a DropShadow effect to an ASP.NET panel or image on the page. You set the TargetControlID, and you can then control the Width and Opacity, and whether the corners should be Rounded. If the panel can be moved or resized, you can also set the TrackPosition property to True to indicate that JavaScript should run to track the panel and update the DropShadow as needed.

Your first thought for where to use this might be an image (as shown in Listing 24-14), but you can use it for any control that you want.

LISTING 24-14: Using DropShadowExtender with an Image control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>DropShadowExtender Control</title>
</head>
<body>
    <form id="form1" runat="server"> <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:DropShadowExtender ID="DropShadowExtender1" runat="server"
         TargetControlID="Image1">
        </asp:DropShadowExtender>
        <asp:Image ID="Image1" runat="server"
         ImageUrl="Images/ToolkitLogo.jpg" />
    </div>
    </form>
</body>
</html>

In this example, accomplishing this is as simple as using the DropShadowExtender control with a TargetControlID of Image1. With this in place, the image appears in the browser, as shown in Figure 24-18.

FIGURE 24-18

image

As stated, in addition to images, you can use DropShadowExtender for almost anything. Listing 24-15 shows how to use it with a Panel control.

LISTING 24-15: Using the DropShadowExtender with a Panel control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>DropShadowExtender Control</title>
</head>
<body>
    <form id="form1" runat="server"> <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:DropShadowExtender ID="DropShadowExtender1" runat="server"
         TargetControlID="Panel1" Rounded="True">
        </asp:DropShadowExtender>
        <asp:Panel ID="Panel1" runat="server" BackColor="Orange"
         Width="300" HorizontalAlign="Center">
            <asp:Login ID="Login1" runat="server">
            </asp:Login>
        </asp:Panel>
    </div>
    </form>
</body>
</html>

NOTE If you get an error stating that “WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping for ‘jquery’,“ just use the following setting in web.config:
<appSettings>
  <add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
    </appSettings>

In this case, a Panel control with a Login control is extended with the DropShadowExtender control. The result is quite similar to that of the Image control’s result. However, one addition to the DropShadowExtender control here is that the Rounded property is set to True (by default, it is set to False). This produces the look shown in Figure 24-19.

FIGURE 24-19

image

As you can see from Figure 24-19, not only are the edges of the drop shadow rounded, but also the entire Panel control has rounded edges. Other style properties that you can work with include the Opacity property, which controls the opacity of the drop shadow only, and the Radius property, which controls the radius used in rounding the edges and obviously works only if the Rounded property is set to True. By default, the Opacity setting is set at 1, which means 100 percent visible. To set it at, say, 50 percent opacity, you need to set the Opacity value to .5.

DynamicPopulateExtender

The DynamicPopulateExtender control enables you to send dynamic HTML output to a Panel control. For this to work, you need one control or event that triggers a callback to the server to get the HTML that, in turn, gets pushed into the Panel control, thereby making a dynamic change on the client.

As with the AutoCompleteExtender control, you need a server-side event that returns something to the client asynchronously. Listing 24-16 shows the code required to use this control on the .aspx page (DynamicPopulateExtender.aspx in the code download for the chapter).

LISTING 24-16: Using the DynamicPopulateExtender control to populate a Panel control

.ASPX

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DynamicPopulateExtender.aspx.cs" 
         Inherits="DynamicPopulateExtender" %>
 
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
 
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
    <title>DynamicPopulateExtender Control</title>
    <script type="text/javascript">    
      function updateGrid(value) {
        var behavior = $find('DynamicPopulateExtender1');
        if (behavior) {
            behavior.populate(value);
        }        
      }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" />
        <asp:DynamicPopulateExtender ID="DynamicPopulateExtender1" runat="server" 
            TargetControlID="Panel1" ServiceMethod="GetDynamicContent">
        </asp:DynamicPopulateExtender>
        <div onclick="updateGrid(0);">
        <asp:LinkButton ID="LinkButton1" runat="server" 
         OnClientClick="return false;">Customers</asp:LinkButton></div>
        <div onclick="updateGrid(1);">
        <asp:LinkButton ID="LinkButton2" runat="server" 
         OnClientClick="return false;">Employees</asp:LinkButton></div>
        <div onclick="updateGrid(2);">
        <asp:LinkButton ID="LinkButton3" runat="server" 
         OnClientClick="return false;">Products</asp:LinkButton></div>
        <asp:Panel ID="Panel1" runat="server">
        </asp:Panel>
    </div>
    </form>
</body>
</html>

This .aspx page is doing a lot, one thing being that a client-side JavaScript function called updateGrid() calls the DynamicPopulateExtender control that is on the page. You will also find three LinkButton server controls, each of which is encased within a <div> element that calls the updateGrid() function and provides a value that is passed into the function. Because you want the <div> element’s onclick event to be triggered with a click and not the LinkButton control’s click event, each LinkButton contains an OnClientClick attribute that simply does nothing. This is accomplished using return false;.

The DynamicPopulateExtender control on the page targets the Panel1 control as the container that will take the HTML that comes from the server on an asynchronous request. The DynamicPopulateExtender control knows where to go to get the HTML using the ServiceMethod attribute. The value of this attribute calls the GetDynamicContent() method, which is in the page’s code-behind file.

After the .aspx page is in place, the next step is to create the code-behind page. This page will contain the server-side method that is called by the DynamicPopulateExtender control. This is presented in Listing 24-17 (DynamicPopulateExtender.aspx.cs and DynamicPopulateExtender.aspx.vb in the code download for the chapter).

LISTING 24-17: The code-behind page of the DynamicPopulateExtender.aspx page

VB

Imports System.Data
Imports System.Data.SqlClient
Imports System.IO
        
Partial Class DynamicPopulateExtender
    Inherits System.Web.UI.Page
        
    <System.Web.Services.WebMethodAttribute()>
    <System.Web.Script.Services.ScriptMethodAttribute()>
    Public Shared Function GetDynamicContent(ByVal contextKey As _
      System.String) As System.String
        Dim conn As SqlConnection
        Dim cmd As SqlCommand
        Dim cmdString As String = "Select * from Customers"
        
        Select Case contextKey
            Case "1"
                cmdString = "Select * from Employees"
            Case "2"
                cmdString = "Select * from Products"
        End Select
        
        conn = New SqlConnection("Data Source=.\SQLEXPRESS;
            AttachDbFilename=|DataDirectory|\NORTHWND.MDF;
            Integrated Security=True;User Instance=True")
            ' Put this string on one line in your code
        cmd = New SqlCommand(cmdString, conn)
        conn.Open()
        
        Dim myReader As SqlDataReader
        myReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
        
        Dim dt As New DataTable
        dt.Load(myReader)
        myReader.Close()
        
        Dim myGrid As New GridView
        myGrid.ID = "GridView1"
        myGrid.DataSource = dt
        myGrid.DataBind()
        
        Dim sw As New StringWriter
        Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
        
        myGrid.RenderControl(htw)
        htw.Close()
        
        Return sw.ToString()
    End Function
End Class

C#

using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
        
public partial class DynamicPopulateExtender : System.Web.UI.Page
{
    [System.Web.Services.WebMethodAttribute(),
     System.Web.Script.Services.ScriptMethodAttribute()]
    public static string GetDynamicContent(string contextKey)
    {
        SqlConnection conn;
        SqlCommand cmd;
        string cmdString = "Select * from Customers";
        
        switch (contextKey)
        {
            case ("1"):
                cmdString = "Select * from Employees";
                break;
            case ("2"):
                cmdString = "Select * from Products";
                break;
        }
        
        conn = new
            SqlConnection(@"Data Source=.\SQLEXPRESS;
               AttachDbFilename=|DataDirectory|\NORTHWND.MDF;
               Integrated Security=True;User Instance=True");
               // Put this string on one line in your code
        cmd = new SqlCommand(cmdString, conn);
        conn.Open();
        
        SqlDataReader myReader;
        myReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        
        DataTable dt = new DataTable();
        dt.Load(myReader);
        myReader.Close();
        
        GridView myGrid = new GridView();
        myGrid.ID = "GridView1";
        myGrid.DataSource = dt;
        myGrid.DataBind();
        
        StringWriter sw = new StringWriter();
        HtmlTextWriter htw = new HtmlTextWriter(sw);
        
        myGrid.RenderControl(htw);
        htw.Close();
        
        return sw.ToString();
    }
}

This code is the code-behind page for the DynamicPopulateExtender.aspx page and contains a single method that is callable asynchronously. The GetDynamicContent() method takes a single parameter, contextKey, a string value that can be used to determine what link the end user clicked.

Based on the selection, a specific command string is used to populate a DataTable object. From here, the DataTable object is used as the data source for a programmatic GridView control that is rendered and returned as a string to the client. The client will take the large string and use the text to populate the Panel1 control that is on the page. Figure 24-20 shows the result of clicking one of the links.

FIGURE 24-20

image

FilteredTextBoxExtender

The FilteredTextBoxExtender control, actually originally contributed by the author of this chapter, works off a TextBox control to specify the types of characters the end user can input into the control. For instance, if you want the end user to be able to enter only numbers into the textbox, you can associate a FilteredTextBoxExtender to the TextBox control and specify such behavior. Listing 24-18 presents an example of this.

LISTING 24-18: Filtering a textbox to use only numbers

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>FilteredTextBoxExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:FilteredTextBoxExtender ID="FilteredTextBoxExtender1"
         runat="server"
         TargetControlID="TextBox1" FilterType="Numbers">
        </asp:FilteredTextBoxExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

In this case, a FilteredTextBoxExtender control is attached to the TextBox1 control through the use of the TargetControlID property. The FilteredTextBoxExtender control has a property called FilterType that has the possible values of Custom, LowercaseLetters, Numbers, and UppercaseLetters.

This example uses a FilterType value of Numbers, meaning that only numbers can be entered into the textbox. If the end user tries to enter any other type of information, nothing happens — it will seem to the end user as if the key doesn’t even function.

The FilteredTextBoxExtender control also exposes the FilterMode and the InvalidChars properties. Here is an example of using these two properties:

<asp:FilteredTextBoxExtender ID="FilteredTextBoxExtender1" runat="server"
  TargetControlID="TextBox1" InvalidChars="*" FilterMode="InvalidChars">
</asp:FilteredTextBoxExtender>

The default value of the FilterMode property is ValidChars. When set to ValidChars, the control works from the FilterType property and allows only what this property defines. When set to InvalidChars, you then use the InvalidChars property and put the characters here (multiple characters all go together with no space or item between them).

HoverMenuExtender

The HoverMenuExtender control enables you to make a hidden control appear on the screen when the end user hovers on another control. This means that you can either build elaborate tooltips or provide extra functionality when an end user hovers somewhere in your application.

One example is to change a ListView control so that when the end user hovers over a product name, the Edit button for that row of data appears on the screen. The complete code, which adds the extender to the <ItemTemplate> in the ListView control, is shown in Listing 24-19.

LISTING 24-19: Adding a hover button to the ListView control’s ItemTemplate

<%@ Page Language="C#" %>
 
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
 
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
    <title>HoverMenuExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
            </asp:ToolkitScriptManager>
            <asp:ListView ID="ListView1" runat="server" DataSourceID="SqlDataSource1">
                <LayoutTemplate>
                    <table>
                        <tr>
                            <th></th>
                            <th>ProductID</th>
                            <th>ProductName</th>
                            <th>SupplierID</th>
                            <th>CategoryID</th>
                            <th>QuantityPerUnit</th>
                        </tr>
                        <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
                    </table>
                </LayoutTemplate>
                <ItemTemplate>
                    <tr style="background-color: #DCDCDC; color: #000000;">
                        <td>
                            <asp:HoverMenuExtender ID="HoverMenuExtender1" runat="server"
                                TargetControlID="ProductNameLabel" PopupControlID="Panel1"
                                PopDelay="25" OffsetX="-50">
                            </asp:HoverMenuExtender>
                            <asp:Panel ID="Panel1" runat="server" Height="50px"
                                Width="125px">
                                <asp:Button ID="EditButton" runat="server"
                                    CommandName="Edit" Text="Edit" />
                            </asp:Panel>
                        </td>
                        <td>
                            <asp:Label ID="ProductIDLabel" runat="server"
                                Text='<%# Eval("ProductID") %>' />
                        </td>
                        <td>
                            <asp:Label ID="ProductNameLabel" runat="server"
                                Text='<%# Eval("ProductName") %>' />
                        </td>
                        <td>
                            <asp:Label ID="SuppliedIDLabel" runat="server"
                                Text='<%# Eval("SupplierID") %>' />
                        </td>
                        <td>
                            <asp:Label ID="CategoryIDLabel" runat="server"
                                Text='<%# Eval("CategoryID") %>' />
                        </td>
                        <td>
                            <asp:Label ID="QuantityPerUnitLabel" runat="server"
                                Text='<%# Eval("QuantityPerUnit") %>' />
                        </td>
 
                    </tr>
                </ItemTemplate>
            </asp:ListView>
            <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\NORTHWND.MDF;Integrated Security=True;User Instance=True" ProviderName="System.Data.SqlClient" SelectCommand="SELECT * FROM [Products]"></asp:SqlDataSource>
        </div>
    </form>
</body>
</html>

Here, a HoverMenuExtender control is attached to the Label control with the ID of ProductNameLabel, which appears in each row of the ListView control. This is done using the TargetControlID property, whereas the PopupControlID property is used to assign the control that appears dynamically when a user hovers the mouse over the targeted control.

The HoverMenuExtender control exposes several properties that control the style and behaviors of the pop-up. The PopDelay property is used in this example and provides a means to delay the pop-up from occurring (in milliseconds). The OffsetX and OffsetY properties specify the location of the pop-up based on the targeted control. In this case, the offset is set to -50 (pixels). Figure 24-21 shows the results of the operation.

FIGURE 24-21

image

ListSearchExtender

The ListSearchExtender control extends either a ListBox or a DropDownList control, although not always with the best results in browsers such as Opera and Safari. This extender enables you to provide search capabilities through large collections that are located in either of these controls. This alleviates the need for the end users to search through the collection to find the item they are looking for.

When utilized, the extender adds a search text that shows the characters the end user types for the search in the area above the control. Listing 24-20 shows the use of this extender.

LISTING 24-20: Extending a ListBox control with the ListSearchExtender control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>ListSearchExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:ListSearchExtender ID="ListSearchExtender1" runat="server"
         TargetControlID="ListBox1">
        </asp:ListSearchExtender>
        <asp:ListBox ID="ListBox1" runat="server" Width="150">
            <asp:ListItem>Aardvark</asp:ListItem>
            <asp:ListItem>Bee</asp:ListItem>
            <asp:ListItem>Camel</asp:ListItem>
            <asp:ListItem>Dog</asp:ListItem>
            <asp:ListItem>Elephant</asp:ListItem>
        </asp:ListBox>
    </div>
    </form>
</body>
</html>

In this case, the only property used in the ListSearchExtender control is the TargetControlID property to associate which control it extends. Running this page produces the results shown in Figure 24-22.

FIGURE 24-22

image

Then, as an end user, when you start typing, you will see what you are typing in the text below the control (as shown in Figure 24-23).

FIGURE 24-23

image

You can customize the text that appears at the top of the control with the PromptCssClass, PromptPosition, and PromptText properties. By default, the PromptPosition property is set to Top (the other possible value is Bottom) and the PromptText value is Type to search.

MaskedEditExtender and MaskedEditValidator

The MaskedEditExtender control is similar to the FilteredTextBoxExtender control in that it restricts the end user from entering specific text within a TextBox control. This control takes the process one step further by providing end users with a template within the textbox for them to follow. If the end users do not follow the template, then they will be unable to proceed and might receive a validation warning from the control using the MaskedEditValidator control.

Listing 24-21 provides an example of using both of these controls.

LISTING 24-21: Using both the MaskedEditExtender and the MaskedEditValidator controls

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>MaskedEditExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:MaskedEditExtender ID="MaskedEditExtender1" runat="server"
         TargetControlID="TextBox1" MaskType="Number" Mask="999">
        </asp:MaskedEditExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:MaskedEditValidator ID="MaskedEditValidator1"
         runat="server" ControlExtender="MaskedEditExtender1"
         ControlToValidate="TextBox1" IsValidEmpty="False"
         EmptyValueMessage="A three digit number is required!"
         Display="Dynamic"></asp:MaskedEditValidator>
    </div>
    </form>
</body>
</html>

In this case, the MaskedEditExtender control uses the TargetControlID to associate itself with the TextBox1 control. The MaskType property supplies the type of mask or filter to place on the textbox. The possible values include:

Listing 24-21 uses Number and then specifies the mask or template the numbers need to take. This is done through the use of the Mask property. In this case, the Mask property is set to 999. This means that all numbers can be only three digits in length.

Using 999 as a value to the Mask property means that when an end user enters a value in the textbox, he will be presented with three underscores inside the textbox. Figure 24-24 shows the template for entering items.

FIGURE 24-24

image

If the Mask property is changed to 99,999.99 as follows:

<asp:MaskedEditExtender ID="MaskedEditExtender1" runat="server"
 TargetControlID="TextBox1" MaskType="Number" Mask="99,999.99">
</asp:MaskedEditExtender>

the textbox template appears, as illustrated in Figure 24-25.

FIGURE 24-25

image

From Figure 24-25, you can see that the comma and the period are present in the template. As the end users type, they do not need to retype these values. The cursor simply moves to the next section of numbers required.

As you can see from the Mask property value, numbers are represented by the number 9. When working with other MaskType values, you also need to be aware of the other mask characters:

In addition to the character specifications, the template uses delimiters, which are detailed in the following list:

Using some of these items, you can easily change MaskedEditExtender to deal with a DateTime value:

<asp:MaskedEditExtender ID="MaskedEditExtender1" runat="server"
 TargetControlID="TextBox1" MaskType="DateTime" Mask="99/99/9999 99:99:99">
</asp:MaskedEditExtender>

The template created in the textbox for this is shown in Figure 24-26.

FIGURE 24-26

image

The MaskedEditExtender control has many properties that are exposed to control and manipulate the behavior and style of the textbox. The MaskedEditExtender control can work in conjunction with the MaskedEditValidator control, which provides validation against the textbox controls.

In the earlier example, the validation was accomplished through an instance of the MaskedEditValidator control:

<asp:MaskedEditValidator ID="MaskedEditValidator1" runat="server"
 ControlExtender="MaskedEditExtender1" ControlToValidate="TextBox1"
 IsValidEmpty="False" EmptyValueMessage="A three digit number is required!"
 Display="Dynamic"></asp:MaskedEditValidator>

This control uses the ControlExtender property to associate itself with the MaskedEditExtender control and uses the ControlToValidate property to watch a specific control on the form. By default, the IsValidEmpty property is set to True. Changing it to False means that the end user will be required to enter some value in the textbox to pass validation and not receive the error message that is presented in the EmptyValueMessage property.

Triggering the MaskedEditValidator control gives you something like the message shown in Figure 24-27. It is important to remember that you can style the control in many ways to produce the validation message appearance that you are looking for.

FIGURE 24-27

image

MutuallyExclusiveCheckBoxExtender

Often, you want to offer a list of check boxes that behave as if they are radio buttons. That is, when you have a collection of check boxes, you want the end user to make only a single selection from the provided list of items.

Using the MutuallyExclusiveCheckBoxExtender control, you can perform such an action. Listing 24-22 shows you how to accomplish this task.

LISTING 24-22: Using the MutuallyExclusiveCheckBoxExtender control with check boxes

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>MutuallyExclusiveCheckBoxExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:MutuallyExclusiveCheckBoxExtender
         ID="MutuallyExclusiveCheckBoxExtender1" runat="server"
         TargetControlID="CheckBox1" Key="MyCheckboxes" />
        <asp:CheckBox ID="CheckBox1" runat="server" Text="Blue" />
        <br />
        <asp:MutuallyExclusiveCheckBoxExtender
         ID="MutuallyExclusiveCheckBoxExtender2" runat="server"
         TargetControlID="CheckBox2" Key="MyCheckboxes" />
        <asp:CheckBox ID="CheckBox2" runat="server" Text="Brown" />
        <br />
        <asp:MutuallyExclusiveCheckBoxExtender
         ID="MutuallyExclusiveCheckBoxExtender3" runat="server"
         TargetControlID="CheckBox3" Key="MyCheckboxes" />
        <asp:CheckBox ID="CheckBox3" runat="server" Text="Green" />
        <br />
        <asp:MutuallyExclusiveCheckBoxExtender
         ID="MutuallyExclusiveCheckBoxExtender4" runat="server"
         TargetControlID="CheckBox4" Key="MyCheckboxes" />
        <asp:CheckBox ID="CheckBox4" runat="server" Text="Orange" />
        <br />
    </div>
    </form>
</body>
</html>

Associating a MutuallyExclusiveCheckBoxExtender control with a CheckBoxList control is impossible; therefore, each of the check boxes needs to be laid out with CheckBox controls as the previous code demonstrates. You need to have one MutuallyExclusiveCheckBoxExtender control for each CheckBox control on the page.

You form a group of CheckBox controls by using the Key property. All the check boxes that you want in one group need to have the same Key value. In the example in Listing 24-22, all the check boxes share a Key value of MyCheckboxes.

Running this page results in a list of four check boxes. When you select one of the check boxes, a check mark appears. Then, when you select another check box, the first check box you selected gets deselected. The best part is that you can even deselect what you have selected in the group, thereby selecting nothing in the check box group.

NumericUpDownExtender

The NumericUpDownExtender control enables you to put some up/down indicators next to a TextBox control that allow the end user to more easily control a selection (which is similar to HTML5’s <input type="number"> element).

A simple example of this is illustrated in Listing 24-23.

LISTING 24-23: Using the NumericUpDownExtender control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>NumericUpDownExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:NumericUpDownExtender ID="NumericUpDownExtender1"
         runat="server" TargetControlID="TextBox1" Width="150"
         Maximum="10" Minimum="1">
        </asp:NumericUpDownExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

The NumericUpDownExtender control here extends the TextBox control on the page. When using the NumericUpDownExtender control, you must specify the width of the control with the Width property. Otherwise, you will see only the up and down arrow keys and not the textbox area. In this case, the Width property is set to 150 (pixels). The Maximum and Minimum properties provide the range used by the up and down indicators.

With a Maximum value setting of 10 and a Minimum value of 1, the only range in the control will be 1 through 10. Running this page produces the results shown in Figure 24-28.

FIGURE 24-28

image

In addition to numbers, as shown in Listing 24-23, you can use text, as illustrated in Listing 24-24.

LISTING 24-24: Using characters instead of numbers with NumericUpDownExtender

<asp:NumericUpDownExtender ID="NumericUpDownExtender1" runat="server"
 TargetControlID="TextBox1" Width="150"
 RefValues="Blue;Brown;Green;Orange;Black;White">
</asp:NumericUpDownExtender>

In this case, the words are defined within the RefValues property (all separated with a semicolon). This gives you the results presented in Figure 24-29.

FIGURE 24-29

image

PagingBulletedListExtender

The PagingBulletedListExtender control enables you to take long bulleted lists and easily apply alphabetic paging to the list. For an example of this, Listing 24-25 works off the Customers table within the Northwind database.

LISTING 24-25: Paging a bulleted list from the Northwind database

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>PagingBulletedListExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <ajaxToolkit:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </ajaxToolkit:ToolkitScriptManager>
        <ajaxToolkit:PagingBulletedListExtender
         ID="PagingBulletedListExtender1"
         runat="server" TargetControlID="BulletedList1">
        </ajaxToolkit:PagingBulletedListExtender>
        <asp:SqlDataSource ID="SqlDataSource1" runat="server"
            ConnectionString="Data Source=.\SQLEXPRESS;
               AttachDbFilename=|DataDirectory|\NORTHWND.MDF;
               Integrated Security=True;User Instance=True"
            ProviderName="System.Data.SqlClient"
            SelectCommand="SELECT [CompanyName] FROM [Customers]">
        </asp:SqlDataSource>
        <asp:BulletedList ID="BulletedList1" runat="server"
            DataSourceID="SqlDataSource1" DataTextField="CompanyName"
            DataValueField="CompanyName">
        </asp:BulletedList>
    </div>
    </form>
</body>
</html>

This code pulls all the CompanyName values from the Customers table of the Northwind database and binds those values to the BulletList control on the page. Running this page gives you the results illustrated in Figure 24-30.

FIGURE 24-30

image

From this figure, you can see that the paging is organized alphabetically on the client side. Only the letters for which there are values appear in the linked list of letters. Clicking any of the letters gives you the items from the bulleted list that start with that character.

PopupControlExtender

The PopupControlExtender control enables you to create a pop-up for any control on your page. For instance, you can completely mimic the CalendarExtender control that was presented earlier by creating a pop-up containing a Calendar control off a TextBox control. Listing 24-26 mimics this behavior.

LISTING 24-26: Creating a CalendarExtender control with PopupControlExtender

VB

<%@ Page Language="VB" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<script runat="server">
    Protected Sub Calendar1_SelectionChanged(ByVal sender As Object, _
      ByVal e As System.EventArgs)
        PopupControlExtender1.Commit( _
           Calendar1.SelectedDate.ToShortDateString())
    End Sub
</script>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>PopupControlExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:PopupControlExtender ID="PopupControlExtender1"
         runat="server" TargetControlID="TextBox1"
         PopupControlID="UpdatePanel1" OffsetY="25">
        </asp:PopupControlExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Calendar ID="Calendar1" runat="server"
                 BackColor="White" BorderColor="White"
                 BorderWidth="1px" Font-Names="Verdana"
                 Font-Size="9pt" ForeColor="Black" Height="190px"
                 NextPrevFormat="FullMonth" Width="350px"
                 OnSelectionChanged="Calendar1_SelectionChanged">
                    <SelectedDayStyle BackColor="#333399"
                     ForeColor="White" />
                    <TodayDayStyle BackColor="#CCCCCC" />
                    <OtherMonthDayStyle ForeColor="#999999" />
                    <NextPrevStyle Font-Bold="True" Font-Size="8pt"
                     ForeColor="#333333" VerticalAlign="Bottom" />
                    <DayHeaderStyle Font-Bold="True" Font-Size="8pt" />
                    <TitleStyle BackColor="White" BorderColor="Black"
                     BorderWidth="4px" Font-Bold="True"
                     Font-Size="12pt" ForeColor="#333399" />
                </asp:Calendar>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
Namespace="AjaxControlToolkit"
    TagPrefix="asp" %>
        
<script runat="server">
    protected void Calendar1_SelectionChanged(object sender,
       EventArgs e)
    {
        PopupControlExtender1.Commit(
           Calendar1.SelectedDate.ToShortDateString());
    }
</script>

When you run this page, you get a single textbox on the page. Click within the textbox and a pop-up calendar appears so you can select a date that will be populated back into the textbox (as illustrated in Figure 24-31).

FIGURE 24-31

image

You will want to place your pop-up control within an ASP.NET AJAX UpdatePanel control and to pass the value from the pop-up control back to the target control (the TextBox1 control), so you use the Commit() method:

PopupControlExtender1.Commit(Calendar1.SelectedDate.ToShortDateString())

ResizableControlExtender

In many situations, you may want to limit the size of an element when it is initially displayed but allow users to grow or shrink the element as they see fit. The ResizableControlExtender makes this easy. Place the ResizableControl on the page and point it to an ASP.NET Panel control using the TargetControlID property.

The ResizableControlExtender control enables you to take a Panel control and give end users the ability to grab a handle and change the size of the element. Anything you put inside the Panel control will then change in size depending on how the end user extends the item. For this to work, you also need to create a handle for the end user to work from in pulling or contracting the item.

Use the HandleCssClass property to specify the style information about the appearance of the handle the user selects to begin resizing the panel. The ResizableCssClass property refers to style information shown while the panel is being altered.

The control also exposes events that are raised that you can attach code to react to the panel being resized: OnClientResizeBegin, OnClientResizing, and finally OnClientResize. These are very useful for actions such as altering text size or retrieving additional data if the panel is enlarged or hiding elements if the panel is shrunk. Listing 24-27 is an example of using the ResizableControlExtender with the CSS information inline in the page. The example shows you how to use the ResizableControlExtender with an image.

LISTING 24-27: Using the ResizableControlExtender control with an image

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>ResizableControlExtender Control</title>
    <style type="text/css">
        .handle
        {
            width:10px;
            height:10px;
            background-color:Black;
            cursor: se-resize;
        }
        .resizable
        {
            border-style:solid;
            border-width:2px;
            border-color:Black;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:ResizableControlExtender ID="ResizableControlExtender1"
         runat="server"
         TargetControlID="Panel1" HandleCssClass="handle"
         ResizableCssClass="resizable">
        </asp:ResizableControlExtender>
        <asp:Panel ID="Panel1" runat="server" Width="300" Height="225">
            <asp:Image ID="Image1" runat="server"
             ImageUrl="Images/ToolkitLogo.jpg"
             style="width:100%; height:100%"/>
        </asp:Panel>
    </div>
    </form>
</body>
</html>

In this example, the ResizableControlExtender control depends on CSS to create the handle for the end user to grab to resize the Panel control. The TargetControlID property points to the control to be resized.

Two CSS references are in the ResizableControlExtender control. One deals with the control as it sits on the screen with no end user interaction. This is really to show the end user that there is an ability to resize the element. This is done through the HandleCssClass property. The value of this property points to the CSS class handle contained within the same file. The second CSS reference deals with the control as it is clicked and held (when the end user does not let up with the mouse click performed). This one is done with the ResizableCssClass property. The value of this property points to the CSS class resizable.

When compiled and run, the code should generate the same page presented in Figure 24-32.

FIGURE 24-32

image

You can see in the top screenshot how the image looks when there is no end user interaction. In this case, there is a black square (as defined by the CSS) in the lower-right corner of the image. The screenshot on the bottom shows what happens when the end user grabs the handle and starts changing the shape of the image.

RoundedCornersExtender

The RoundedCornersExtender control enables you to put rounded corners on the elements on your page. As with the ResizableControlExtender control, you put the element you are interested in working with inside a Panel control. Listing 24-28 shows this done with a Login server control.

LISTING 24-28: Rounding the corners of the Panel control containing a Login server control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>RoundedCornersExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:RoundedCornersExtender ID="RoundedCornersExtender1"
         runat="server" TargetControlID="Panel1">
        </asp:RoundedCornersExtender>
        <asp:Panel ID="Panel1" runat="server" Width="250px"
         HorizontalAlign="Center" BackColor="Orange">
            <asp:Login ID="Login1" runat="server">
            </asp:Login>
        </asp:Panel>
    </div>
    </form>
</body>
</html>

Here, the RoundedCornersExtender control simply points to the Panel control with the TargetControlID property. This Panel control has a background color of orange to show that the corners are indeed rounded. The result of this bit of code is illustrated in Figure 24-33.

FIGURE 24-33

image

You can control the degree of the rounded corners using the Radius property of the RoundedCornersExtender control. By default, this property is set to a value of 5. You can even choose the corners that you want to round using the Corners property. The possible values of the Corners property include All, Bottom, BottomLeft, BottomRight, Left, None, Right, Top, TopLeft, and TopRight.

SliderExtender and MultiHandleSliderExtender

The SliderExtender control actually extends a TextBox control to make it look nothing like it normally does. This Ajax Control Toolkit control enables you to create a true slider control that allows the end user to select a range of numbers using a mouse instead of typing in the number. Listing 24-29 shows a simple example of using the slider.

LISTING 24-29: Using the SliderExtender control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>SliderExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:SliderExtender ID="SliderExtender1" runat="server"
         TargetControlID="TextBox1">
        </asp:SliderExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

This little bit of code to tie a SliderExtender control to a typical TextBox control is simple and produces the result presented in Figure 24-34.

FIGURE 24-34

image

This is fine, but it is hard for the end users to tell what number they are selecting. Therefore, you might find it better to give a signifier to the end user. Adding a Label control to the page (called Label1) and changing the SliderExtender control to include a BoundControlID property gives you the signifier that you are looking for. Here is the code for this change:

<asp:SliderExtender ID="SliderExtender1" runat="server" TargetControlID="TextBox1"
 BoundControlID="Label1">
</asp:SliderExtender>

This small change produces the result (with the appropriate Label control on the page) shown in Figure 24-35.

FIGURE 24-35

image

Now when the end users slide the handle on the slider, they see the number that they are working with quite easily. Some of the following properties are available to the SliderExtender control:

The MultiHandleSliderExtender is basically the same thing, but this particular extender enables you to have more than one handle for the end user to work with. This works great if you need a slider that needs to do things like allow the end user to select a range or a minimum/maximum value.

SlideShowExtender

The SlideShowExtender control enables you to put an image slideshow in the browser. The slideshow controls enable the end user to move to the next or previous images as well as to simply play the images as a slideshow with a defined wait between each image. Listing 24-30 (SlideShowExtender.aspx in the code download for this chapter) shows an example of creating a slideshow.

LISTING 24-30: Creating a slideshow with three images

.ASPX

<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="SlideShowExtender.aspx.cs" Inherits="SlideShowExtender" %>
 
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
 
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
    <title>SlideShowExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:Panel ID="Panel1" runat="server" Width="300px" 
         HorizontalAlign="Center">
            <asp:SlideShowExtender ID="SlideShowExtender1" runat="server" 
                ImageTitleLabelID="LabelTitle" TargetControlID="Image1" 
                UseContextKey="True" NextButtonID="ButtonNext" 
                PlayButtonID="ButtonPlay" 
                PreviousButtonID="ButtonPrevious" 
                SlideShowServiceMethod="GetSlides" 
                ImageDescriptionLabelID="LabelDescription">
            </asp:SlideShowExtender>
            <asp:Label ID="LabelTitle" runat="server" Text="Label" 
             Font-Bold="True"></asp:Label><br /><br />
            <asp:Image ID="Image1" runat="server" 
             ImageUrl="Images/ToolkitLogo.jpg" /><br />
            <asp:Label ID="LabelDescription" runat="server" 
             Text="Label"></asp:Label><br /><br />
            <asp:Button ID="ButtonPrevious" runat="server" Text="Previous" />
            <asp:Button ID="ButtonNext" runat="server" Text="Next" />
            <asp:Button ID="ButtonPlay" runat="server" />
        </asp:Panel>
    </div>
    </form>
</body>
</html>

The SlideShowExtender control has a lot of properties available. You can specify the location where you are defining the image title and description using the ImageTitleLabelID and the ImageDescriptionLabelID properties. In addition, this page contains three Button controls: one to act as the Previous button, another for the Next button, and the final one as the Play button. However, it is important to note that when the Play button is clicked (to start the slideshow), it turns into the Stop button.

The SlideShowServiceMethod property is important because it points to the server-side method that returns the images that are part of the slideshow. In this case, it is referring to a method called GetSlides, which is represented in Listing 24-31 (SlideShowExtender.aspx.cs and SlideShowExtender.aspx.vb in the code download for this chapter).

LISTING 24-31: The GetSlides method implementation

VB

Partial Class SlideShowExtender
    Inherits System.Web.UI.Page
        
    <System.Web.Services.WebMethodAttribute()>
    <System.Web.Script.Services.ScriptMethodAttribute()>
    Public Shared Function GetSlides(ByVal _
     contextKey As System.String) As AjaxControlToolkit.Slide()
        
          Return New AjaxControlToolkit.Slide() {
            New AjaxControlToolkit.Slide("Images/ToolkitLogo.jpg", _
              "The Logo", "This is the Ajax Control Toolkit Logo."),
            New AjaxControlToolkit.Slide("Images/ToolkitLogo1.jpg", _
              "The 2nd Logo", "This is the modified Ajax Control Toolkit Logo."),
            New AjaxControlToolkit.Slide("Images/ToolkitLogo2.jpg", _
              "The 3rd Logo", "This is another modified Ajax Control Toolkit Logo.")}
    End Function
End Class

C#

public partial class SlideShowExtender : System.Web.UI.Page
{
    [System.Web.Services.WebMethodAttribute(),
     System.Web.Script.Services.ScriptMethodAttribute()]
    public static AjaxControlToolkit.Slide[]
      GetSlides(string contextKey)
    {
        return new AjaxControlToolkit.Slide[] {
            new AjaxControlToolkit.Slide("Images/ToolkitLogo.jpg", 
              "The Logo", "This is the Ajax Control Toolkit Logo."),
            new AjaxControlToolkit.Slide("Images/ToolkitLogo1.jpg", 
              "The 2nd Logo", "This is the modified Ajax Control Toolkit Logo."),
            new AjaxControlToolkit.Slide("Images/ToolkitLogo2.jpg", 
              "The 3rd Logo", "This is another modified Ajax Control Toolkit Logo.") };
    }
}

With the code-behind in place, the SlideShowExtender has a server-side method to call for the photos. This method, called GetSlides(), returns an array of Slide objects that require the location of the object (the path), the title, and the description. When running this page, you get something similar to the results shown in Figure 24-36.

FIGURE 24-36

image

Clicking the Play button on the page rotates the images until they are done. They will not repeat in a loop unless you have the SlideShowExtender control’s Loop property set to True. (It is set to False by default.)

The other important property to pay attention to is the PlayInterval property. The value of this property is an integer that represents the number of milliseconds that the browser will take to change to the next photo in the series of images. By default, this is set to 3000 milliseconds.

TextBoxWatermarkExtender

The TextBoxWatermarkExtender control enables you to put instructions within controls for the end users, which gives them a better understanding of what to use the control for. This can be text or even images (when using CSS). Listing 24-32 shows an example of using this control with a TextBox server control.

LISTING 24-32: Using the TextBoxWatermarkExtender control with a TextBox control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>TextBoxWatermarkExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:TextBoxWatermarkExtender ID="TextBoxWatermarkExtender1"
         runat="server" WatermarkText="Enter in something here!"
         TargetControlID="TextBox1">
        </asp:TextBoxWatermarkExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

In this case, the TextBoxWatermarkExtender control is associated with a simple TextBox control and uses the WatermarkText property to provide the text that will appear inside the actual TextBox control. Figure 24-37 shows the results of the code from this listing.

FIGURE 24-37

image

The text in the image from Figure 24-37 is straight text with no style inside the TextBox control. When the end user clicks inside the TextBox control, the text will disappear and the cursor will be properly placed at the beginning of the textbox.

To apply some style to the content that you use as a watermark, you can use the WatermarkCssClass property. You can change the code to include a bit of style, as shown in Listing 24-33.

LISTING 24-33: Applying style to the watermark

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>TextBoxWatermarkExtender Control</title>
    <style type="text/css">
        .watermark
        {
         width:150px;
         font:Verdana;
         font-style:italic;
         color:GrayText;
        }
        
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:TextBoxWatermarkExtender ID="TextBoxWatermarkExtender1"
         runat="server" WatermarkText="Enter in something here!"
         TargetControlID="TextBox1"
         WatermarkCssClass="watermark">
        </asp:TextBoxWatermarkExtender>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

This time, the WatermarkCssClass property is used and points to the inline CSS class, watermark, which is on the page. When you run this page, you will see the style applied as shown in Figure 24-38.

FIGURE 24-38

image

ToggleButtonExtender

The ToggleButtonExtender control works with CheckBox controls and enables you to use an image of your own instead of the standard check box images that the CheckBox controls typically use. Using the ToggleButtonExtender control, you are able to specify images for checked, unchecked, and disabled statuses. Listing 24-34 shows an example of using this control.

LISTING 24-34: Using the ToggleButtonExtender control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>ToggleButtonExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:MutuallyExclusiveCheckBoxExtender
         ID="MutuallyExclusiveCheckBoxExtender1" runat="server"
         Key="MyCheckBoxes" TargetControlID="CheckBox1">
        </asp:MutuallyExclusiveCheckBoxExtender>
        <asp:MutuallyExclusiveCheckBoxExtender
         ID="MutuallyExclusiveCheckBoxExtender2" runat="server"
         Key="MyCheckBoxes" TargetControlID="CheckBox2">
        </asp:MutuallyExclusiveCheckBoxExtender>
        <asp:ToggleButtonExtender ID="ToggleButtonExtender1"
         runat="server" TargetControlID="CheckBox1"
         UncheckedImageUrl="Images/Unchecked.gif"
         CheckedImageUrl="Images/Checked.gif"
         CheckedImageAlternateText="Checked"
         UncheckedImageAlternateText="Not Checked" ImageWidth="25"
         ImageHeight="25">
        </asp:ToggleButtonExtender>
        <asp:CheckBox ID="CheckBox1" runat="server"
         Text="&nbsp;Option One" />
        <asp:ToggleButtonExtender ID="ToggleButtonExtender2"
         runat="server" TargetControlID="CheckBox2"
         UncheckedImageUrl="Images/Unchecked.gif"
         CheckedImageUrl="Images/Checked.gif"
         CheckedImageAlternateText="Checked"
         UncheckedImageAlternateText="Not Checked" ImageWidth="25"
         ImageHeight="25">
        </asp:ToggleButtonExtender>
        <asp:CheckBox ID="CheckBox2" runat="server"
         Text="&nbsp;Option Two" />
    </div>
    </form>
</body>
</html>

This page has two CheckBox controls. Each check box has an associated ToggleButtonExtender control along with a MutuallyExclusiveCheckBoxExtender control to tie the two check boxes together. The ToggleButtonExtender control uses the CheckedImageUrl and the UncheckedImageUrl properties to specify the appropriate images to use. Then, if images are disabled by the end user’s browser instance, the text that is provided in the CheckedImageAlternateText and UncheckedImageAlternateText properties is used instead. You will also need to specify values for the ImageWidth and ImageHeight properties for the page to run.

Running this page gives you results similar to those presented in Figure 24-39.

FIGURE 24-39

image

UpdatePanelAnimationExtender

Animating an UpdatePanel as its content is being refreshed is a common scenario. The UpdatePanelAnimationExtender enables you to use the broad set of animations available in the toolkit and automatically coordinates playing them when the specified UpdatePanel is being updated or when the update has completed.

The UpdatePanelAnimationExtender control enables you to apply an animation to a Panel control for two specific events. The first is the OnUpdating event and the second is the OnUpdated event. You can then use the animation framework provided by the Ajax Control Toolkit to change the page’s style based on these two events. Listing 24-35 shows an example of using the OnUpdated event when the end user clicks a specific date within a Calendar control contained within the UpdatePanel control on the page.

LISTING 24-35: Using animations on the OnUpdated event

VB

<%@ Page Language="VB" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<script runat="server">
    Protected  Sub Calendar1_SelectionChanged(ByVal sender As Object, _
      ByVal e As EventArgs)
        Label1.Text = "The date selected is " & _
           Calendar1.SelectedDate.ToLongDateString()
    End Sub
</script>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>UpdatePanelAnimationExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:UpdatePanelAnimationExtender
         ID="UpdatePanelAnimationExtender1"
         runat="server" TargetControlID="UpdatePanel1">
            <Animations>
                <OnUpdated>
                    <Sequence>
                        <Color PropertyKey="background"
                         StartValue="#999966"
                         EndValue="#FFFFFF" Duration="5.0" />
                    </Sequence>
                </OnUpdated>
            </Animations>
        </asp:UpdatePanelAnimationExtender>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Label ID="Label1" runat="server"></asp:Label>
                <br />
                <asp:Calendar ID="Calendar1" runat="server"
                    onselectionchanged="Calendar1_SelectionChanged">
                </asp:Calendar>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>

C#

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
Namespace="AjaxControlToolkit"
    TagPrefix="asp" %>
        
<script runat="server">
    protected void Calendar1_SelectionChanged(object sender,
      EventArgs e)
    {
        Label1.Text = "The date selected is " +
           Calendar1.SelectedDate.ToLongDateString();
    }
</script>

With this bit of code, when you click a date within the Calendar control, the entire background of the UpdatePanel holding the calendar changes from one color to another for a 5-second duration as specified in the animation you built. The animations you define can get complex, and building deluxe animations is beyond the scope of this chapter.

ValidatorCalloutExtender

The last extender control covered is the ValidatorCalloutExtender control. This control enables you to add a more noticeable validation message to end users working with a form. You associate this control not with the control that is being validated, but instead with the validation control itself. An example of associating the ValidatorCalloutExtender control with a RegularExpressionValidator control is presented in Listing 24-36.

LISTING 24-36: Creating validation callouts with the ValidatorCalloutExtender

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>ValidatorCalloutExtender Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:ValidatorCalloutExtender ID="ValidatorCalloutExtender1"
         runat="server" TargetControlID="RegularExpressionValidator1">
        </asp:ValidatorCalloutExtender>
        Email Address:&nbsp;
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:RegularExpressionValidator
         ID="RegularExpressionValidator1" runat="server"
         ErrorMessage="You must enter an email address" Display="None"
         ControlToValidate="TextBox1"
         ValidationExpression=
           "\w+([-+.']\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*">
        </asp:RegularExpressionValidator><br />
        <asp:Button ID="Button1" runat="server" Text="Submit" />
    </div>
    </form>
</body>
</html>

This page has a single textbox for the form, a Submit button, and a RegularExpressionValidator control. You build the RegularExpressionValidator control as you would normally, except you make use of the Display property and set it to None. You do not want the normal ASP.NET validation control to also display its message, because it will collide with the one displayed with the ValidatorCalloutExtender control. Although the Display property is set to None, you still use the ErrorMessage property to provide the error message. Running this page produces the results presented in Figure 24-40.

FIGURE 24-40

image

AJAX CONTROL TOOLKIT SERVER CONTROLS

The following ASP.NET AJAX controls actually do not always extend other ASP.NET controls, but instead, are controls themselves. The following sections detail some of these controls.

Accordion Control

The Accordion control is used to specify a set of panes, similar to the famous navigation menu in Microsoft Outlook. Each pane is made up of a header template and a content template. The header templates of all panes are always visible, whereas only one content template is visible. The user selects which pane to view by clicking the header. The content from the previously active pane is hidden from view, and the content of the newly selected pane is displayed instead.

The Accordion control can provide a fade transition when switching among active panes. Set the FadeTransitions property to True and then you can set the TransitionDuration and FramesPerSecond values. The default values are 250 milliseconds and 40 frames per second, respectively.

The SelectedIndex property lets you declaratively and programmatically control which pane to show. Other important properties are the AutoSize and Height properties. The AutoSize property is None by default, meaning that the size of the Accordion control changes based on the active pane. Other content on the screen may be shifted to accommodate the changing size. However, when the AutoSize property is set to Limit, the size is restricted to the Height value. The active pane displays scrollbars if the content is larger than the space available. The other possible value is Fill, which results in expanding a pane if the content is not large enough to satisfy the Height value provided. Listing 24-37 shows the Accordion control in action. The Accordion control is used with two panes.

LISTING 24-37: An Accordion control with two AccordionPane controls

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>Accordion Control</title>
    <style type="text/css">
        .titlebar
        {
            background-color:Blue;
            color:White;
            font-size:large;
            font-family:Verdana;
            border:solid 3px Black;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:Accordion ID="Accordion1" runat="server" HeaderCssClass="titlebar"
         HeaderSelectedCssClass="titlebar"
         FadeTransitions="true"
         TransitionDuration="333"
         FramesPerSecond="30">
            <Panes>
            <asp:AccordionPane runat="server" ID="AccordionPane1">
                <Header>
                    This is the first pane
                </Header>
                <Content>
            Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
            Donec accumsan lorem. Ut consectetuer tempus metus.
            Aenean tincidunt venenatis tellus. Suspendisse molestie
            cursus ipsum. Curabitur ut lectus. Nulla ac dolor nec elit
            convallis vulputate. Nullam pharetra pulvinar nunc. Duis
            orci. Phasellus a tortor at nunc mattis congue.
            Vestibulum porta tellus eu orci. Suspendisse quis massa.
            Maecenas varius, erat non ullamcorper nonummy, mauris erat
            eleifend odio, ut gravida nisl neque a ipsum. Vivamus
            facilisis. Cras viverra. Curabitur
            ut augue eget dolor semper posuere. Aenean at magna eu eros
            tempor pharetra. Aenean mauris.
                </Content>
            </asp:AccordionPane>
            <asp:AccordionPane runat="server" ID="AccordionPane2">
                <Header>
                    This is the second pane
                </Header>
                <Content>
            Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
            Donec accumsan lorem. Ut consectetuer tempus metus.
            Aenean tincidunt venenatis tellus. Suspendisse molestie
            cursus ipsum. Curabitur ut lectus. Nulla ac dolor nec elit
            convallis vulputate. Nullam pharetra pulvinar nunc. Duis
            orci. Phasellus a tortor at nunc mattis congue.
            Vestibulum porta tellus eu orci. Suspendisse quis massa.
            Maecenas varius, erat non ullamcorper nonummy, mauris erat
            eleifend odio, ut gravida nisl neque a ipsum. Vivamus
            facilisis. Cras viverra. Curabitur
            ut augue eget dolor semper posuere. Aenean at magna eu eros
            tempor pharetra. Aenean mauris.
                </Content>
            </asp:AccordionPane>
            </Panes>
        </asp:Accordion>
    </div>
    </form>
</body>
</html>

A single CSS class is defined in the document, and this class, titlebar, is used as the value of the HeaderCssClass and the HeaderSelectedCssClass properties. The Accordion control here contains two AccordionPane controls. The sub-elements of the AccordionPane control are the <Header> and the <Content> elements. The items placed in the <Header> section will be in the clickable pane title, whereas the items contained within the <Content> section will slide out and appear when the associated header is selected.

You will notice that there is also a transition effect in place when the panes are switched. Running this page produces the results illustrated in Figure 24-41.

FIGURE 24-41

image

This figure shows a screenshot of each of the panes selected. Some of the more important properties are described in the following list:

Finally, the properties of DataSource, DataSourceID, and DataMember enable you to bind to this control from your code.

CascadingDropDown

The available options for one DropDownList can be a function of the selection made in another DropDownList. The CascadingDropDown control makes enabling this in your application easy. You set the TargetControlID to the DropDownList that should be populated by a callback to the server. You also assign a category to classify the DropDownList.

Before the DropDownList is populated, the value of the PromptText property is presented. Moreover, while the call to the server is underway, the value of the LoadingText property is displayed. You can set the ServicePath property to call a ServiceMethod on a separate web service, or you can just set the ServiceMethod name to a static ScriptMethod located directly in the page, as illustrated in Listing 24-38.

The first DropDownList in this example lets the user pick a state. This example includes only Missouri and Oregon. When a state is selected, a second DropDownList is populated based on the value selected by the user in the first DropDownList. The way to specify that one DropDownList is dependent on the value of another is to set the ParentControlID of the CascadingDropDown control.

LISTING 24-38: Using the CascadingDropDown control

VB

<%@ Import Namespace="System.Web.Services" %>
<%@ Import Namespace="AjaxControlToolkit" %>
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
        
   <script runat="server" language="vb">
        
      <WebMethod, System.Web.Script.Services.ScriptMethod> _
       Public Shared Function GetStates(ByVal _
         knownCategoryValues As String, _
         ByVal category As String) As CascadingDropDownNameValue()
        
          Return New CascadingDropDownNameValue() { New _
            CascadingDropDownNameValue("Missouri", "Missouri"), _
            New CascadingDropDownNameValue("Oregon", "Oregon") }
       End Function
        
      <WebMethod, System.Web.Script.Services.ScriptMethod> _
       Public Shared Function GetCounties(ByVal _
         knownCategoryValues As String, _
         ByVal category As String) As CascadingDropDownNameValue()
        
          If knownCategoryValues.Contains("Missouri") Then
             Return New CascadingDropDownNameValue() { New _
               CascadingDropDownNameValue("St. Charles", _
                "St. Charles"), _
               New CascadingDropDownNameValue("St. Louis", _
                "St. Louis"), _
               New CascadingDropDownNameValue("Jefferson", _
                "Jefferson"), _
               New CascadingDropDownNameValue("Warren", "Warren"), _
               New CascadingDropDownNameValue("Franklin", "Franklin") }
          End If
        
        
          If knownCategoryValues.Contains("Oregon") Then
            Return New CascadingDropDownNameValue() { New _
              CascadingDropDownNameValue("Baker", "Baker"), _
              New CascadingDropDownNameValue("Benton", "Benton"), _
              New CascadingDropDownNameValue("Clackamas", "Clackamas"),
              New CascadingDropDownNameValue("Clatsop", "Clatsop"), _
              New CascadingDropDownNameValue("Columbia", "Columbia") }
          End If
        
          Return Nothing
       End Function
        
   </script>
 
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
    <title>CascadingDropDown</title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ToolkitScriptManager runat="server" ID="scriptManager" />
    <div>
        <asp:DropDownList runat="server" ID="ddl1" Width="200" />
        <br />
        <asp:DropDownList runat="server" ID="ddl2" Width="200" />
        <br />
        <asp:CascadingDropDown runat="server" ID="cdd1"
            TargetControlID="ddl1"
            PromptText="Select a State"
            Category="state" LoadingText="[Loading States]"
            ServiceMethod="GetStates" />
        <asp:CascadingDropDown runat="server" ID="cdd2"
            TargetControlID="ddl2"
            ParentControlID="ddl1"
            PromptText="Select County" Category="county"
            LoadingText="[Loading Counties]"
            ServiceMethod="GetCounties" />
    </div>
    </form>
</body>
</html>

C#

<%@ Import Namespace="System.Web.Services" %>
<%@ Import Namespace="AjaxControlToolkit" %>
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
    <script runat="server" language="C#">
        
        [WebMethod]
        [System.Web.Script.Services.ScriptMethod]
        public static CascadingDropDownNameValue[]
               GetStates(string knownCategoryValues, string category)
        {
            return new[] {
        new CascadingDropDownNameValue("Missouri", "Missouri"),
        new CascadingDropDownNameValue("Oregon", "Oregon") };
        }
        
        [WebMethod]
        [System.Web.Script.Services.ScriptMethod]
        public static CascadingDropDownNameValue[]
               GetCounties(string knownCategoryValues, string category)
        {
            if (knownCategoryValues.Contains("Missouri"))
            {
                return new[] {
                    new CascadingDropDownNameValue("St. Charles",
                      "St. Charles"),
                    new CascadingDropDownNameValue("St. Louis",
                      "St. Louis"),
                    new CascadingDropDownNameValue("Jefferson",
                      "Jefferson"),
                    new CascadingDropDownNameValue("Warren", "Warren"),
                    new CascadingDropDownNameValue("Franklin",
                      "Franklin") };
            }
            if (knownCategoryValues.Contains("Oregon"))
            {
                return new[] {
                    new CascadingDropDownNameValue("Baker", "Baker"),
                    new CascadingDropDownNameValue("Benton", "Benton"),
                    new CascadingDropDownNameValue("Clackamas",
                      "Clackamas"),
                    new CascadingDropDownNameValue("Clatsop",
                      "Clatsop"),
                    new CascadingDropDownNameValue("Columbia",
                      "Columbia") };
            }
            return null;
        }
        
    </script>

NoBot Control

The NoBot control works to determine how entities interact with your forms. It helps you ensure that actual humans are working with your forms and some automated code isn’t working through your application.

The NoBot control is illustrated in Listing 24-39 (NoBot.aspx in the code download for this chapter).

LISTING 24-39: Using the NoBot control to limit a login form

.ASPX

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="NoBot.aspx.cs" Inherits="NoBot" %>
 
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
 
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
    <title>NoBot Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:NoBot ID="NoBot1" runat="server" CutoffMaximumInstances="3" 
            CutoffWindowSeconds="15" ResponseMinimumDelaySeconds="10" 
            OnGenerateChallengeAndResponse="NoBot1_GenerateChallengeAndResponse" />
        <asp:Login ID="Login1" runat="server">
        </asp:Login>
        <asp:Label ID="Label1" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>

The NoBot control has three important properties to be aware of when controlling how your forms are submitted. These properties include CutoffMaximumInstances, CutoffWindowSeconds, and ResponseMinimumDelaySeconds.

CutoffMaximumInstances is the number of times the end user is allowed to try to submit the form within the number of seconds specified by the CutoffWindowSeconds property. The ResponseMinimumDelaySeconds property defines the minimum number of seconds the end user has to submit the form. If you know the form you are working with will take some time, setting this property to a value (even if it is 5 seconds) will help stop submissions that are not made by humans.

The OnGenerateChallengeAndResponse property enables you to define the server-side method that works with the challenge and enables you to provide a response based on the challenge. This property is used in Listing 24-39 and posts the status of the form submission back to the user.

The code-behind for this page is represented in Listing 24-40 (NoBot.aspx.vb and NoBot.aspx.cs in the code download for this chapter).

LISTING 24-40: The code-behind for the NoBot control’s OnGenerateChallengeAndResponse

VB

Imports System
Imports AjaxControlToolkit
        
Public partial Class NoBot
 Inherits System.Web.UI.Page
    Protected Sub NoBot1_GenerateChallengeAndResponse(ByVal _
      sender As Object, _
      ByVal void As AjaxControlToolkit.NoBotEventArgs)
      Handles NoBot1.GenerateChallengeAndResponse
        
        Dim state As NoBotState
        NoBot1.IsValid(state)
        
        Label1.Text = state.ToString()
    End Sub
End Class

C#

using System;
using AjaxControlToolkit;
        
public partial class NoBot : System.Web.UI.Page
{
    protected void NoBot1_GenerateChallengeAndResponse(object sender,
        AjaxControlToolkit.NoBotEventArgs e)
    {
        NoBotState state;
        NoBot1.IsValid(out state);
        
        Label1.Text = state.ToString();
    }
}

Running this page and trying to submit the form before the ten-second minimum time results in an invalid submission. In addition, trying to submit the form more than three times within 15 seconds results in an invalid submission.

PasswordStrength Control

The PasswordStrength control enables you to check the contents of a password in a TextBox control and validate its strength. It will also then give a message to the end user about whether the strength is reasonable. Listing 24-41 presents a simple example of the PasswordStrength control.

LISTING 24-41: Using the PasswordStrength control with a TextBox control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>Password Strength Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:PasswordStrength ID="PasswordStrength1" runat="server"
         TargetControlID="TextBox1">
        </asp:PasswordStrength>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

This simple page produces a single textbox, and when end users start typing in the textbox, they are notified on the strength of the submission as they type. This is illustrated in Figure 24-42.

FIGURE 24-42

image

Some of the important properties to work with here include MinimumLowerCaseCharacters, MinimumNumericCharacters, MinimumSymbolCharacters, MinimumUpperCaseCharacters, and PreferredPasswordLength.

Rating Control

The Rating control gives your end users the ability to view and set ratings (such as star ratings). You have control over the number of ratings, the look of the filled ratings, the look of the empty ratings, and more. Listing 24-42 shows you a page that shows a five-star rating system that enables end users to set the rating themselves.

LISTING 24-42: A rating control that the end user can manipulate

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>Rating Control</title>
    <style type="text/css">
        .ratingStar {
            font-size: 0pt;
            width: 13px;
            height: 12px;
            margin: 0px;
            padding: 0px;
            cursor: pointer;
            display: block;
            background-repeat: no-repeat;
        }
        
        .filledRatingStar {
            background-image: url(Images/FilledStar.png);
        }
        
        .emptyRatingStar {
            background-image: url(Images/EmptyStar.png);
        }
        
        .savedRatingStar {
            background-image: url(Images/SavedStar.png);
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:Rating ID="Rating1" runat="server"
         StarCssClass="ratingStar"
         WaitingStarCssClass="savedRatingStar"
         FilledStarCssClass="filledRatingStar"
         EmptyStarCssClass="emptyRatingStar">
        </asp:Rating>
    </div>
    </form>
</body>
</html>

Here, the Rating control uses a number of CSS classes to define its look-and-feel in various states. In addition to the CSS class properties (StarCssClass, WaitingStarCssClass, FilledStarCssClass, and EmptyCssClass), you can also specify rating alignments, the number of rating items (the default is 5), the width, the current rating, and more. The code presented in Listing 24-42 produces the results shown in Figure 24-43.

FIGURE 24-43

image

TabContainer Control

The TabContainer and TabPanel controls make presenting the familiar tabbed UI easy. The user is presented with a set of tabs across the top of a single pane of content displayed for the active tab. When the user selects a different tab, the content is changed. Tabs are a great way to control a page that has a lot of content to present. The TabContainer control can contain one or more TabPanel controls that provide you with a set of tabs that show content one tab at a time.

The TabContainer enables you to attach a server event called the ActiveTabChanged event, which is fired during a postback if the active tab has changed. You can also use the OnClientActiveTabChanged event to have your JavaScript event triggered in the browser when the user selects a different tab. The ScrollBars property lets you designate whether scrollbars should be Horizontal, Vertical, Both, None, or set to Auto, in which case the control makes the determination.

The TabPanel control has a <HeaderTemplate> for the tab and a <ContentTemplate> for the body. You can forego using the <HeaderTemplate> and specify the HeaderText property instead. It also has an event that is triggered when the tab is selected called OnClientClick. One particularly interesting feature of the Tabs feature is the ability to disable tabs programmatically in JavaScript in the browser by setting the Enabled property to False.

Listing 24-43 shows an example of a TabContainer control with three TabPanel controls.

LISTING 24-43: Showing three tabs in a TabContainer control

<%@ Page Language="C#" %>
        
<%@ Register Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>
        
<!DOCTYPE html>
<html>
<head runat="server">
    <title>TabContainer Control</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </asp:ToolkitScriptManager>
        <asp:TabContainer ID="TabContainer1" runat="server"
         Height="300px">
            <asp:TabPanel runat="server">
                <HeaderTemplate>Tab 1</HeaderTemplate>
                <ContentTemplate>
                 Here is some tab one content.
                </ContentTemplate>
            </asp:TabPanel>
            <asp:TabPanel runat="server">
                <HeaderTemplate>Tab 2</HeaderTemplate>
                <ContentTemplate>
                 Here is some tab two content.
                </ContentTemplate>
            </asp:TabPanel>
            <asp:TabPanel runat="server">
                <HeaderTemplate>Tab 3</HeaderTemplate>
                <ContentTemplate>
                 Here is some tab three content.
                </ContentTemplate>
            </asp:TabPanel>
        </asp:TabContainer>
    </div>
    </form>
</body>
</html>

Figure 24-44 presents the result of this simple page.

FIGURE 24-44

image

SUMMARY

The Ajax Control Toolkit makes adding rich animations and interactivity to a web application easy. In addition to being able to use the UpdatePanel control to enable asynchronous updates of page content, you can use the UpdatePanelAnimation to show the user that background processing is occurring. The toolkit helps blur the distinction between desktop applications and web applications. Modal dialog boxes and pop-up dialog boxes start to push the web application beyond what the user expects from working in the browser.

As you can see, a myriad of these controls are at your disposal. The best thing about this is that this is a community effort along with Microsoft and the list of available controls is only going to grow over time.

This chapter explored a lot of the Ajax Control Toolkit controls and how to use them in your ASP.NET applications. Remember to visit the Microsoft Ajax page and the Ajax Control Toolkit site for these controls often and take advantage of the newest offerings out there.