When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, July 4, 2007

Displaying Extended Details in a GridView Using an Ajax Pop-Up (Part 1)

By Brian Smith


Introduction


As web developers we are often tasked with building online reports. For ASP.NET 2.0 web applications, the GridView control is commonly used to display report data. A common challenge in building reports is achieving the right balance between readability and information. Users want to have all of the pertinent information available on one screen, but too much data dumped on a single screen leads to information overload and makes the report difficult to digest. Oftentimes, a report displays the high-level information and enables users to drill down into the details. One way to implement drill down details is to add a link to each item in the report that, when clicked, takes the user to a page that shows the selected item's details. This approach works well if the details displayed require significant screen real estate or if the user is likely to only want to view a particular item's details. If, however, a typical user needs to view the details for many items, having to go to a separate web page to view each item's details can be counterproductive. An alternative approach is to have a window appear on screen when mousing over a particular item that would show the item's details.

At work I was asked to build such a report interface: a GridView showing high-level details that, when moused over, show their details in an on screen pop-up window. I decided to use Microsoft's ASP.NET AJAX framework to accomplish this task. In this article, I'll show you how to build your own dynamically-generated pop-up window filled with extended information about an item in a GridView. This is the first of a two-part article series. In this part we'll look at building the application architecture, which will consist of a Typed DataSet and some custom classes. In a future installment we will look at implementing the Ajax-related functionality. Read on to learn more!

- continued -

The Preliminaries


This article is written in a step-by-step manner so that you can build this application from scratch, following along on your own computer. Alternatively, you can go to the end of this article and download the complete source code and database file and run it from your computer. Regardless of what approach you use, you will need Visual Studio 2005 or Visual Studio Web Developer. The code available at the end of this article includes a Microsoft SQL Server 2005 Express Edition database file, although if you are following along at your own computer you can use SQL Server 2005 or SQL Server 2000. Lastly, you will need the Microsoft AJAX Extensions for ASP.NET 2.0 and the Microsoft AJAX Control Toolkit.

If you do not have Microsoft's AJAX Extensions or the Control Toolkit, you can download them from the official ASP.NET AJAX website. Install both of these libraries if you haven't already; make sure you can see the Control Toolkit in your Toolbox in Visual Studio. For more on installing and getting started with the ASP.NET AJAX framework, see How Do I: Get Started with ASP.NET AJAX? and How Do I: Get Started with the ASP.NET AJAX Control Toolkit?

Before we get rolling, let's take a quick look at the end product. The screen shot below shows the demo application. Note that the GridView provides a list of employees. Hovering over the magnifying glass icon for a particular employee record displays details about that employee - namely, the territories he covers - in a pop-up window.

Hovering over the magnifying glass icon for a particular employee record displays details about that employee.

Configuring the Database


The demo available at the end of this article uses a slightly modified version of the Northwind database. I modified the database by adding two stored procedures, which we'll examine momentarily. (For more information on what stored procedures are, their benefits, and how to create them, see Nathan Pond's article, Writing a Stored Procedure.) The demo available at the end of this article already includes a SQL Server 2005 Express Edition version of the Northwind database in the App_Data folder with the needed stored procedures already added. If you are following along from scratch, start by downloading the Northwind database (if you don't already have it on your computer) and running the following T-SQL statements to create the necessary stored procedures:

create procedure dbo.Sel_EmployeeListing
as

   select Employeeid
      , Firstname + ' ' + LastName as 'Name'
      , Title
      , Address
      , City
      , PostalCode
      , Country
   from employees
go


create procedure dbo.Sel_EmployeeTerritories
   @EmployeeID int
as

   select Rtrim(TerritoryDescription) + ' - (' + Rtrim(RegionDescription) + ')' as 'Territory'
   from territories t with (nolock)
   join region r with (Nolock) on t.regionid = r.regionid
   join employeeterritories et with (Nolock) on t.territoryid = et.territoryid
   where employeeid = @EmployeeID
go

The first stored procedure, Sel_EmployeeListing returns a specified set of fields from all of the records in the Employees table. This stored procedure will be used to populate the GridView with the high-level report items. The second stored procedure, Sel_EmployeeTerritories, returns all of the territories for a specified employee. This stored procedure will be used to populate the details pop-up with the territories covered by the employee who is currently moused over.

Creating the Ajax Website in Visual Studio


If you are following along at your computer, the next step is to create a new Ajax Control Toolkit website in Visual Studio 2005. The Ajax Control Toolkit website option, shown in the screen shot below, is available once you have installed the ASP.NET AJAX framework.

Create a new Ajax Control Toolkit website in Visual Studio 2005.

Creating an Ajax Control Toolkit website through Visual Studio automatically adds a Default.aspx page with the following markup:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
   <title>Untitled Page</title>
</head>
<body>
   <form id="form1" runat="server">
      

<ajaxToolkit:ToolkitScriptManager ID="ScriptManager1" runat="server" />


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

Note the <ajaxToolkit:ToolkitScriptManager> markup within the Web Form. This control is automatically placed on ASP.NET pages when you create a Control Toolkit website; it can also be manually added. You must have a Script Manager control on your page if you wish to accomplish any of the following Ajax-related tasks:

  • Client-script functionality of the Microsoft AJAX Library, and any custom script that you want to send to the browser.
  • Partial-page rendering, which enables regions on the page to be independently refreshed without a postback. If you are going to use an UpdatePanel, UpdateProgress, or Timer control on your page, a ScriptManager control must be present as well.
  • JavaScript proxy classes for Web services, which enable you to use client script to access Web services.
  • JavaScript classes to access ASP.NET authentication and profile application services.
It's a safe bet to assume that if you need to make any partial-page postbacks that you will need a Script Manager control. For more information on this control, see Microsoft's ScriptManager Control Overview.

Creating an Infrastructure to Access Data


There are many ways to retrieve data through an ASP.NET application. You can use a SqlDataSource control and work directly with the database; you can write ADO.NET code to connect to the database and retrieve the results from a stored procedure. Rather than accessing the database directly, however, ideally all data access will flow through a formalized Data Access Layer (DAL). A DAL can be implemented in a variety of ways: as a set of custom classes, through Typed DataSets, or via tools like NHibernate and CodeSmith. I decided to use the patterns put forth by Scott Mitchell in his ASP.NET 2.0 Data Tutorials. Specifically, Scott uses Typed DataSets as the Data Access Layer along with a manually-created Business Logic Layer (BLL). Data is accessed from ASP.NET pages via ObjectDataSources that communicate with the BLL. You will see this pattern in action as we go through the article.

If you haven't at least started reading Scott's Working with Data tutorials, I would suggest you go read at least the first two. They discuss using Typed DataSets and making a custom BLL to get at your data. Also check out Using Strongly-Typed Data Access in Visual Studio 2005 and ASP.NET 2.0. As you'll see from those two resources, the amount of code you write is limited to the BLL and any logic you choose to write in your ASP.NET pages' code-behind classes.

Let's get going! Start by creating two directories under the App_Code directory: DAL and BLL:

Create the DAL and BLL folders.

Right-click on the DAL folder and choose "Add New Item...". Choose the DataSet template and name it Northwind.xsd.

Create a Typed DataSet.

After you do this, Visual Studio will churn for a while creating the XML file and classes associated with the Typed DataSet. It will then bring up a wizard inferface for you to build a TableAdapter. The TableAdapter is the code that retrieves the data from the database and populates it into a DataTable; the TableAdapter's corresponding DataTable is automatically created upon completion of the wizard. The first step in the TableAdapter wizard asks you to either choose an existing connection string or build a new one. Since we've yet to create a connection to the database, choose to create a new connection string. If the database file is in the App_Data folder you can select it from the drop-down list. If the database is registered on a database server, click the New Connection button to specify the database server, authentication information, and other connection details.

After specifying the connection details, click Next. Now you are asked to choose how to retrieve the data: via an ad-hoc SQL statement, through a new stored procedure, or from an existing stored procedure. Since we already created the stored procedures needed for this application, choose "Use existing stored procedures" and click Next.

Choose the Use existing stored procedures option.

We are now asked to assign stored procedures for the TableAdapter's SELECT, INSERT, UPDATE, and DELETE commands. Since this is a simple example, we do not need to use the INSERT, DELETE, or UPDATE commands. Therefore, simply associate the sel_EmployeeListing stored procedure with the SELECT command.

Specify the SELECT command.

The next step in the wizard allows us to determine what methods we want the TableAdapter to support as well as the names of the methods. I unchecked the 'Fill a DataTable' method and left the 'Return a DataTable', although it's fine to leave both checkboxes checked. A detailed discussion of the differences between these two choices is beyond the scope of this article. See Scott's first data tutorial (Creating a Data Access Layer) for a more detailed discussion. Also change the method name in the textbox from GetData to GetEmployees.

Check only the Return a DataTable option.

Click Finish to complete the creation of the TableAdapter and its associated DataTable.

At this point we have a DAL capable of returning all employees. We also need a way to return a particular employees territories. To accomplish this, right-click in the DataSet designer and choose "Add --> TableAdapter". This will add another TableAdapter (and DataTable) to the DataSet and will start by launching the TableAdapter wizard. Choose the same options as with the first TableAdapter, but bind this one's SELECT command to the Sel_EmployeeTerritories stored procedure (instead of sel_EmployeeListing). Also name the TableAdapter's method SelectTerritories (instead of GetEmployees).

When the TableAdapter wizard generates the DataTable and TableAdapters it chooses their names based on the name of the stored procedure bound to the SELECT command. Consequently, the names are prefixed with an unsightly sel_. We can get rid of that prefix in the DataTable and TableAdapter names by right-clicking on the DataTable or TableAdapter name and choosing "Rename". After removing the sel_ prefix, your DataSet designer should look like the following:

The DataSet should contain two DataTables and TableAdapters.

Creating a Business Logic Layer


The next item on our list is to create the Business Logic Layer (BLL). We are going to create two class files, one for each TableAdapter/DataTable. Right-click on the 'BLL' directory and add two C# class files: EmployeesBLL and TerritoriesBLL.

Create two class files in the App_Code folder.

Open the EmployeesBLL.cs file and add the code using NorthwindTableAdapters to top of file. This using statement references the namespace where the DataSet's TableAdapter classes are located (NorthwindTableAdapters) Next, add the attribute [System.ComponentModel.DataObject] to the class declaration. The DataObject attribute marks the class as being an object suitable for binding to an ObjectDataSource control. See Creating an ObjectDataSource Control Source for more information on this attribute and other related attributes.

Next, add a property that provides easy access to an instance of the EmployeeListingTableAdapter class. The EmployeeListingTableAdapter class is the TableAdapter class that we created through the wizard in an earlier step. This class has the GetEmployees method that returns all employees. The following property simplifies the code needed to invoke a method from the TableAdapter since the property handles the instantiation (if needed):

private EmployeeListingTableAdapter m_tEmployeesListing = null;
protected EmployeeListingTableAdapter Adapter
{
    get
    {
       if (m_tEmployeesListing == null)
            m_tEmployeesListing = new EmployeeListingTableAdapter();

       return m_tEmployeesListing;
    }
}

Let's now implement a method in our BLL called GetEmployees. This methods acts as a "proxy," doing nothing more than executing the TableAdapter's SELECT command and returning the results. The GetEmployees will return the strongly-typed DataTable Northwind.EamployeeListingDataTable. Decorate this method with the [System.ComponentModel.DataObjectMethodAttribute()] attribute so that the method will appear in the ObjectDataSource wizard.

[System.ComponentModel.DataObjectMethodAttribute( System.ComponentModel.DataObjectMethodType.Select, true)]
public Northwind.EmployeeListingDataTable GetEmployees()
{
   return Adapter.GetEmployees();
}

The DataObjectMethodAttribute indicates the purpose of the method. In this case, it denotes that the GetEmployees method in the BLL is a method that returns data. This information is used by Visual Studio when displaying the ObjectDataSource control's wizard in the Designer. We'll see the ObjectDataSource wizard in use momentarily, which should clearly illustrate the role these attribute values play.

The complete code for the EmployeesBLL class should look similar to the following:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;

[System.ComponentModel.DataObject]
public class EmployeesBLL
{
   private EmployeeListingTableAdapter m_tEmployeesListing = null;
   protected EmployeeListingTableAdapter Adapter
   {
      get
      {
         if (m_tEmployeesListing == null)
            m_tEmployeesListing = new EmployeeListingTableAdapter();

         return m_tEmployeesListing;
      }
   }

   [System.ComponentModel.DataObjectMethodAttribute
      (System.ComponentModel.DataObjectMethodType.Select, true)]
   public Northwind.EmployeeListingDataTable GetEmployees()
   {
      return Adapter.GetEmployees();
   }
}

We now need to write the code for the the TerritoriesBLL class. We don't need to add the DataObject or DataObjectMethodAttribute attributes to this class file since the TerritoriesBLL class will be accessed programmatically to display the pop-up (rather than through an ObjectDataSource). Of course it doesn't hurt to add this metadata, but I omitted it in the code available at the end of this article. Similar to the EmployeesBLL class, the TerritoriesBLL class needs a property that returns a EmployeeTerritoriesTableAdapter instance and a method that returns the set of territories for a particular employee.

After you've written the code for this class, it should look similar to the following:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;

public class TerritoriesBLL
{
   private EmployeeTerritoriesTableAdapter m_tEmployeeTerritories = null;
   protected EmployeeTerritoriesTableAdapter Adapter
   {
      get
      {
         if (m_tEmployeeTerritories == null)
            m_tEmployeeTerritories = new EmployeeTerritoriesTableAdapter();

         return m_tEmployeeTerritories;
      }
   }


   public Northwind.EmployeeTerritoriesDataTable SelectTerritories(int iEmployeeID)
   {
      return Adapter.SelectTerritories(iEmployeeID);
   }
}

Note that the SelectTerritories method accepts an integer as its input and returns the results from the TableAdapter's SelectTerritories method, using the passed-in employee ID value.

Displaying Employee Information in a GridView


Now that we have completed the DAL and BLL, we are ready to display the list of employees in a GridView on an ASP.NET page. Open the Default.aspx page and examine it in the Design view. Drag and drop an ObjectDataSource from the Toolbox onto the Designer. Click on the Configure Data Source link from the ObjectDataSource's smart tag. This will bring up the ObjectDataSource wizard, prompting you to specify the source of the data.

Choose the business object from the drop-down list.

The first screen of the wizard asks you to specify the business object from which the data will be pulled. The drop-down list should list the EmployeesBLL class along with the EmployeesTableAdapter and TerritoriesTableAdapter classes. The reason these three classes appear in the drop-down list (and why TerritoriesBLL does not) is because they are marked with the DataObject attribute. Recall that we added this attribute manually to the EmployeesBLL class; the two TableAdapter classes are auto-generated by the Typed DataSet and automatically have this attribute injected.

Select the EmployeesBLL class from the drop-down list and click Next. The next screen asks you to specify what method the ObjectDataSource should invoke to select, insert, update, and delete data. In the SELECT tab there should only be one option in the drop-down list: GetEmployees. If you look at the other tabs they are empty because the EmployeesBLL class doesn't have any implementations for those commands. Back on the SELECT tab, make sure the GetEmployees method is selected, then click Finish.

Next drag a GridView onto the Designer. In the GridView's smart tag there's a "Choose Data Source" drop-down list, which includes the ObjectDataSource on the page. Upon choosing this option the GridView will be updated to include a column for each of the fields returned by the ObjectDataSource. Since the ObjectDataSource is calling the BLL's GetEmployees method, which is returning an EmployeesDataTable, the fields are those that were specified in the column list in the Sel_EmployeeListing stored procedure.

Bind the ObjectDataSource to the GridView.

After binding the ObjectDataSource to the GridView, take a moment to view Default.aspx in a browser. Note that the set of Employees are listed.

The GridView lists the employees.

Looking Forward...


At this point we have built the infrastructure necessary to retrieve both high-level and detailed report information. Moreover, we have created a simplified report, namely a GridView listing a set of employees. At this point we are ready to Ajax-ify our application through the use of a pop-up control to display detailed information about the moused over employee. This is tackled in Part 2 of this article series.

Happy Programming!

  • By Brian Smith


  • Read Part 2


    Attachments


  • Download the code used in this article
  • Further Readings


  • Working with Data in ASP.NET 2.0 (Scott Mitchell's tutorial series)
  • Microsoft ASP.NET AJAX


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article