Printer Friendly Version      Send     
Click to Rate and Give Feedback
Related Articles
The goal of the ADO.NET Data Services Framework is to create a simple REST-based framework for exposing and consuming data-centric services easily.

By Elisa Flasko and Mike Flasko (August 2008)
We introduce you to the EDI functionality within BizTalk Server 2006 R2, illustrating schema creation, document mapping, EDI delivery and transmission, and exception handling.

By Mark Beckner (August 2008)
In this excerpt from his upcoming book, Laurence Moroney explains the basics of Silverlight animation and the animation tools available in Expression Blend.

By Lawrence Moroney (August 2008)
We build a Silverlight 2.0 application using the InkPresenter to let users annotate a pre-defined collection of images, perform handwriting recognition, and save the annotations and recognized text into a server-side database.

By Julia Lerman (August 2008)
More ...
Articles by this Author
Dino Esposito compares the use of AJAX patterns and DOM manipulations to the use of the ASP.NET partial rendering engine.

By Dino Esposito (August 2008)
In this installment, the author provides an enhanced implementation of the BST pattern and compares it to HTM solutions.

By Dino Esposito (July 2008)
AJAX is meant to go beyond mere partial page rendering. Find out where Dino Esposito thinks dynamic pages are headed in the future with ASP.NET AJAX.

By Dino Esposito (June 2008)
This month we begin a look at the Single Page Interface (SPI) model and some design patterns for designing AJAX applications.

By Dino Esposito (May 2008)
This month, use nested ListView controls to create hierarchical views of data and extend the eventing model of the ListView by deriving a custom ListView class.

By Dino Esposito (April 2008)
This month Dino looks at AJAX control extenders again, adding more advanced features including masked editing and autocompletion.

By Dino Esposito (February 2008)
AJAX Extenders extend the behavior and features of ordinary Web controls so you can reduce postbacks and control input even better than with AJAX alone.

By Dino Esposito (January 2008)
Dino Esposito introduces the Microsoft AJAX Library and the JavaScript library for ASP.NET AJAX 1.0.

By Dino Esposito (December 2007)
More ...
Popular Articles
Learn how to create a workflow that uses InfoPath forms and other office documents for passing data to targeted activities and for use in Office documents.

By Rick Spiewak (June 2008)
Microsoft Robotics Studio is not just for playing with robots. It also allows you to build service-based applications for a wide range of hardware devices.

By Sara Morgan (June 2008)
We build a Silverlight 2.0 application using the InkPresenter to let users annotate a pre-defined collection of images, perform handwriting recognition, and save the annotations and recognized text into a server-side database.

By Julia Lerman (August 2008)
Here we present a rundown of the various language paradigms of CLR-based languages via short language introductions and code samples.

By Joel Pobar (May 2008)
More ...
Read the Blog
One of the neat things about XAML is that you can not only declare your objects using an XML syntax, but that you can define transformations to rotate, move, and skew your objects. In the August 2008 issue of MSDN Magazine, in an article adapted from his upcoming book Introducing Microsoft Silverlight ...
Read more!
Microsoft has a long history of introducing new features to shipped products, often under the banner of Power Toys or Power Tools. In the August 2008 issue of MSDN Magazine, Brian Randell takes you on a tour of some useful tools for ...
Read more!
Designing software is often an exercise in managing complexity. You can take steps to limit the complexity of any given class by only assigning it a discrete set of responsibilities, applying a concept known as object role stereotypes. In the August 2008 issue of MSDN Magazine, Jeremy Miller explains ...
Read more!
When you evaluate any new technology, pattern, or strategy, you have to consider how that new piece of the puzzle is going to mesh with your existing application architecture. With the Entity Framework, integration is not a problem. In the July 2008 issue of MSDN Magazine, John Papa demonstrated ...
Read more!
Electronic Document Interchange (EDI) encompasses the largest share of real-world business-to-business commerce—nearly 90 percent of the current market—and is growing rapidly year over year. In the August 2008 issue of MSDN Magazine, Mark Beckner introduces ...
Read more!
Separation of presentation and data is not a new idea, but with the growing popularity of technologies such as AJAX and Silver­light, it has become much more prevalent. ADO.NET Data Services Framework began as a way to help developers looking to expose and consume data via services from their applications.. In the August 2008 issue of MSDN ...
Read more!
More ...
Cutting Edge
Modal Dialog Boxes with AJAX
Dino Esposito

Code download available at: CuttingEdge2008_Launch.exe (419 KB)
Browse the Code Online
Dialog boxes have been around in Windows® for a long time, and they do have their advantages. But if you want your Web application to have dialog boxes, you're basically stuck with popups, and, as you know, most users disable them with popup blockers. So what are you to do if you need a popup dialog?
With Microsoft® ASP.NET AJAX, dialog boxes are especially important for displaying context-sensitive information without a page reload or new page. It is therefore important to devise a different implementation of dialog boxes that are as effective as modal popups but hassle-free for users.
Neither ASP.NET nor AJAX extensions have built-in support for popups or Web dialog boxes; however, the AJAX Control Toolkit does. The AJAX Control Toolkit is a shared-source library of ASP.NET extender controls. One of its most useful controls is the ModalPopupExtender control that I briefly introduced in the January 2008 installment of Cutting Edge (msdn.microsoft.com/msdnmag/issues/08/01/CuttingEdge). The ModalPopup extender takes the markup generated by a server-side ASP.NET panel and shows or hides it as the user clicks on an associated HTML element. Initially styled as hidden, the dialog box is downloaded onto the client when the page is loaded and then shown or hidden on demand. How is modality guaranteed? Take a look at the code snippet in Figure 1.
The code shows an excerpt from the script used to initialize the ModalPopup extender on the client. Note that an ASP.NET AJAX extender usually comprises a server control—the extender—and a client behavior class written in JavaScript. The code in Figure 1 comes from the ModalPopup extender's client behavior class. If you download the source code for the AJAX Control Toolkit from codeplex.com/atlascontroltoolkit, you'll find the aforementioned script code in the modalpopupbehavior.js file.
As you can see in Figure 1, the root element of the dialog's markup tree is designated as the foreground element and programmatically hidden from view. At the same time, a DIV tag is dynamically created and designated as the background element. The tag is given a fixed position at coordinates 0,0 and styled appropriately. The DIV tag is also given an extremely high (but arbitrary) z-index that virtually ensures it will sit on top of all other elements in the document, since the z-index property sets the stack order of an HTML element, and the element with the greatest stack order is always displayed on top of elements with lower stack order.
The DIV is then added to the Document Object Model (DOM) as a child of the foreground element's parent. Finally, the foreground element—the dialog box content—is given a z-index just higher than that of the background.
The net effect of this intermediate DIV is that a new transparent element is layered over all page elements except the popup panel. A click handler is also dynamically applied to the extender controls target in order to ensure that any user input performed outside the popup panel (on the foreground element) is lost and never reaches the intended target. This is the behavior that ensures modality.
The content of the server panel you define in the source ASPX page is popped up as a modal window, just like a classic Windows message box. At the same time, it delivers an unprecedented level of UI flexibility—after all, it's an ASP.NET panel, so you can fill it with any combination of controls you like, and you can style it however you like.

The ModalPopupExtender Control
Setting up a modal popup using the AJAX Control Toolkit library is a relatively simple task. You start by defining a panel to provide the UI, and then add a button control to trigger the display of the dialog:
<asp:Button runat="server" ID="btnEditCustomer"
    Text="Edit text" />
<asp:Panel runat="server" ID="pnlEditCustomer">
  ...
</asp:Panel>
Next, you set up the extender and specify the target control ID and the popup control ID:
<act:ModalPopupExtender ID="ModalPopupExtender1"
    runat="server"  
    TargetControlID="btnEditCustomer"
    PopupControlID="pnlEditCustomer"
    BackgroundCssClass="modalBackground"
    OkControlID="editBox_OK"
    OnOkScript="yes()" />
The target control ID of a ModalPopup extender is the ID of the server control that, when clicked, causes the dialog box to pop up. The popup control ID is the ID of the server control that provides the content for the dialog box.
The AJAX Control Toolkit framework does not provide any default style for the dialog box. The user has to employ the visual elements in the panel to dismiss the dialog box. Figure 2 shows a sample dialog box in action. It allows confirmation and provides some information. But if you want context-sensitive dialogs where some further user interaction is required, you need to do some more work.
Figure 2 Sample Web Modal Dialog Box in Action (Click the image for a larger view)
To make the ModalPopup extender more like that of a Windows dialog box, a number of features can be added. For instance, the ability to dismiss the dialog box by simply pressing the Esc key—a common functionality in Windows but not supported yet in the AJAX Control Toolkit—is a good idea.
Before I implement any of these features, let's briefly review the methods and properties of the ModalPopupExtender control. Figure 3 lists its properties but does not include all the properties automatically inherited from base classes.
The signature of the ModalPopupExtender control class is shown here:
    public class ModalPopupExtender :
        DynamicPopulateExtenderControlBase 
The base class here is a library-defined extender that provides DynamicPopulate support to multiple extenders. DynamicPopulate is another extender in the AJAX Control Toolkit that replaces the markup of a DOM element with text returned by a Web service call. The ModalPopup extender has dependencies on other AJAX Control Toolkit extenders including DropShadow and DragPanel.
The content of the dialog box is fully determined by a DOM sub-tree rooted in an element specified through the PopupControlID property. Quite often, this element will be an ASP.NET server control such as a Panel. The position of the popup is determined by the X and Y properties, but the popup will be centered horizontally if no coordinates are specified.
Just as in any classic Windows dialog box, the Web modal popup can be dragged around. To enable this, you specify in the PopupDragHandleControlID property the ID of the element to be used as the drag handle, and the embedded script does the rest. Note that you can drag the modal popup around, but only within the page area covered by the DOM. In other words, if your page area is defined by a DIV with a height of 100 pixels, and you display the page in a browser window of 1600 by 1024 pixels, you can only drag the popup vertically for 100 pixels, regardless of the physical height of the browser window.
By setting the RepositionMode property to any value but "None" (the default), you enable the behavior's script to update the position of the popup when the user scrolls or resizes the Web browser window (see Figure 4).
Figure 4 Repositioning the Modal Dialog (Click the image for a larger view)

Closing the Popup Using the Esc Key
In Windows, the user can dismiss a message or dialog box by pressing the Esc key. In the AJAX Control Toolkit, this ability is not present natively in the modal popup behavior. As you'll see in a moment, though, detecting and handling the Esc key is not a big issue. Consider the following JavaScript code, which is attached to the KeyDown event of the page's DOM:
   function OnKeyPress(args)
   {
     if(args.keyCode == Sys.UI.Key.esc)
     {
       $find("ModalPopupExtender1").hide();
     }
   }
The code is triggered by keystrokes that affect the entire document. The handler receives a Sys.UI.DomEvent object through the args parameter. The object describes the mouse and keyboard status when a DOM-level event is caught. In particular, the keyCode property indicates the ASCII code of the key pressed. Additional information about the Ctrl, Shift, and Alt keys is available, as well as information about the mouse position and button status. The Sys.UI.Key enumeration lists some predefined constants for the code of the most commonly used keys, including Esc, Enter, and Del buttons. Using these tools, detecting if the Esc key is pressed is a breeze. Now let's see how you can programmatically hide the popup.
An AJAX Control Toolkit extender has a client and server programming interface. The server interface is an ASP.NET server control; the client interface is a JavaScript behavior class. This class exposes a JavaScript programming model that mirrors the server-side programming model, so each of the properties in Figure 3 has its JavaScript counterpart. The container of these properties is an object with the ModalPopup extender control ID. This control is not part of the DOM, as it is created by the infrastructure of the Microsoft AJAX Library. Hence, you can't use the $get function to get an instance of a behavior class; you must use the $find function instead. Both the server and client API of the modal popup have show and hide methods to control visibility.
Note that the OnKeyPress event handler will not work unless you register it with the Microsoft AJAX Library. The best place to run this registration code is the pageLoad function, like so:
function pageLoad(sender, args) 
{
  $addHandler(document, "keydown", OnKeyPress);
}
The Microsoft AJAX Library invokes the pageLoad function when all of its startup tasks have completed and everything in the library and the page has been initialized. The library also automatically wires its loading stage to any JavaScript function with that name that can be found in the page. Now, any modal popup managed through the AJAX Control Toolkit's ModalPopup extender can be dismissed with the Esc key.

Adding Animation on Display
With this completed, we can progress to other things. Wouldn't you love to achieve the same kind of fade-in effect Windows Vista® uses for your Web applications? The effect is built-in for regular Windows-managed windows, such as the window that pops up when the window.alert method is invoked. On custom modal popups, like those I'm building here, you have to provide for it yourself.
Animation may become a native feature of the ModalPopup extender in the near future, but, for the time being, getting it to work is relatively easy thanks to the animation API already available in the AJAX Control Toolkit library. The following code refers to the Animation extender, which supports animation for a number of common predefined DOM events such as OnLoad, OnClick, OnMouseOver, and OnMouseOut. The TargetControlID points to the DOM element whose events will trigger the animation:
<act:AnimationExtender ID="popUpAnimation" runat="server" 
  TargetControlID="btnViewMore">
  <Animations>
    <OnClick>
      <Parallel AnimationTarget="pnlViewCustomer" 
        Duration=".3" Fps="25">
        <FadeIn />
      </Parallel>                    
    </OnClick>
  </Animations>
</act:AnimationExtender>
Animations can be combined in a sequence, and a few can even be played in parallel. The preceding code just fades in the panel associated with a modal popup for the specified duration and number of frames after the button is clicked. The code below shows a more sophisticated animation that executes multiple effects:
<act:AnimationExtender ID="popUpAnimation" runat="server" 
  TargetControlID="btnViewMore">
  <Animations>
    <OnClick>
      <Parallel AnimationTarget="pnlViewCustomer" 
        Duration=".3" Fps="25">
        <Move Horizontal="100" Vertical="100" />
        <Resize Width="280" Height="180" />
        <Color PropertyKey="backgroundColor" 
          StartValue="#FFFFFF" 
          EndValue="#FFFF00" />
      </Parallel>                    
    </OnClick>
  </Animations>
</act:AnimationExtender>
Here, the modal popup is first moved to a new relative position and then resized and colored. The gallery of examples at asp.net/AJAX/AjaxControlToolkit/Samples/Animation/Animation.aspx shows some demos; however, most of them can't be applied to a modal popup without modifying the source code. The main issue lies in the fact that the modal popup is displayed before the animation starts. While that might work for a simple fade-in effect, if you want to create explosions or wipe-out effects, you need to get clever.
The ModalPopup extender fires a few helpful events on the client, including the showing event. Here's how you can subscribe to it:
function pageLoad(sender, args) 
{
    $find("ModalPopupExtender1").add_showing(onModalShowing);
}
Any code you associate with the showing event runs just before the popup is displayed. You can use this event to perform any client-side initialization tasks. Other client events to which you can bind include hiding, hidden, and shown.
Initializing the Elements of the Popup
On the client, the ModalPopup extender toggles the visibility of the DOM tree, as identified by the PopupControlID attribute. In the source code for the client behavior, you'll see additional code to intercept markup that was downloaded from the server as a constituent part of the host page, and you can style it for display.
For this reason you can't make changes to the template or content of the popup once the page has been served. Consider the following scenario. Your user chooses a customer from, say, a dropdown list and views some details. Next, he may want to edit some of the customer information. In a traditional Web application, you just redirect the user to a new page or, perhaps, make a postback to load a different view. In ASP.NET 2.0 and newer versions, this is what the DetailsView control does. In a desktop application, you would use a modal dialog box. For AJAX-enabled applications, a Web dialog box is now an option.
The dialog box used to edit a customer, however, has a fixed layout that is populated with new content every time it is going to pop up. Suppose that you originate a full postback when a customer is selected. In the selection-changed event, you update the customer view and optionally the controls in the modal popup. In this way, when the button is clicked to pop up the dialog box the latest information is already loaded.
But an AJAX application doesn't normally perform full postbacks. Figure 5 shows a fragment of an ASP.NET AJAX page that uses partial rendering to update a customer view instead. The updatable region is linked to the SelectedIndexChanged event on the child dropdown list control. The dropdown list, in turn, has the AutoPostBack property set to true. The net effect is that whenever the user changes the selection in the dropdown list, the table in Figure 5 is updated without a full page reload. So far, so good.
The next step entails updating the panel in Figure 6, which represents the content of the modal popup. The panel must be in sync with the customer's view.
You can update the panel being displayed in the popup when a new customer is displayed or just before the popup is displayed:
<act:ModalPopupExtender ID="ModalPopupExtender1" runat="server"  
  TargetControlID="hiddenTargetControlForModalPopup"
  PopupControlID="pnlEditCustomer"
  BackgroundCssClass="modalBackground"
  DropShadow="false"
  OkControlID="editBox_OK"
  OnOkScript="ok()"
  OnCancelScript="cancel()"
  CancelControlID="editBox_Cancel" />
If you update the popup content just before display (the approach I recommend), then your dialog initialization code needs to run on the server, but you won't have any postback event from any control that brings up the modal dialog. And even if you did, it would be too late for you to edit the controls in the dialog box. The ModalPopup extender, in fact, adds a client-side onclick event handler to the target control and prevents the default action—in this case, a postback—from taking place.
The idea, then, is to use a fake target control for the ModalPopup extender so that the extender will never be automatically kicked off out of your control. How would you then trigger the modal popup? Here's an example. When the button below is clicked, it executes its server-side OnClick handler over a partial rendering operation:
<asp:UpdatePanel runat="server" ID="DialogBoxUpdatePanel" 
  UpdateMode="Conditional">
  <ContentTemplate>
    <asp:Button runat="server" ID="btnEditText" 
      Text="Edit text" 
      OnClick="btnEditText_Click" />
  </ContentTemplate>
</asp:UpdatePanel>
This has two benefits. First, no full refresh affects the page. Second, the OnClick server code can be used to properly initialize the popup panel and then order the extender to show the popup:
protected void btnEditText_Click(object sender, EventArgs e)
{
    InitDialog();
    ModalPanel1.Update();
    ModalPopupExtender1.Show();
}
The InitDialog method contains the internal code required to initialize all controls in the panel in Figure 6. This code is sufficient to change the state of involved controls but doesn't modify their markup. This is because you're executing the code over a partial rendering postback. So in the next step, you explicitly refresh the updatable panel. Finally, call the Show method on the ModalPopup extender. This last call ensures that the script to show the dialog as the page loads is properly downloaded to the browser. Figure 7 shows a sample page in action designed along these guidelines.
Figure 7 Modal Dialog Box with Data from Current Context (Click the image for a larger view)
Do you really need all those partial rendering regions in the page? Well, if your only purpose is find out how to initialize the dialog box with server code, then you could perhaps save some updatable regions. However, if your dialog requires server-side initialization work, then it likely requires some work to update the underlying page with collected data. In that case you would need to return data to the server.

Returning Data to the Server
The ModalPopup extender allows you to identify controls that serve as the OK and Cancel buttons by using the properties OkControlID and CancelControlID for this purpose. When any of these buttons are clicked, the popup is dismissed and some JavaScript code optionally executes. You may define a JavaScript function to run when the OK and Cancel buttons are clicked by using the OnOkScript and OnCancelScript properties. The popup doesn't post back when any of the predefined OK and Cancel buttons are clicked. The following code excerpt from the modalpopupbehavior.js source file explains. This code belongs to the built-in handlers of the click event for both the OK and Cancel buttons:
var element = $get(this._OkControlID);
if (element && !element.disabled) {
   if (this.hide() && this._OnOkScript) {
      window.setTimeout(this._OnOkScript, 0);
   }
   e.preventDefault();
   return false;
}
Here's a sample handler for the OK button:
function onOK(sender, e) 
{
  // refresh the UI

  // if you need to run server code, you
  // can invoke a Web service method
}

It's Your Turn
To refresh, I didn't add code to the existing control or client behavior to complete this sample. I simply used the existing set of members (both client and server) to improve the initialization of the dialog and the data exchange with the host page. To avoid full page refreshes, I employed partial rendering whenever it made sense.
To replicate the tricks in the sample code discussed here in your own application, install the latest version of the AJAX Control Toolkit and then wrap the modal panel in an UpdatePanel region, paying attention to not include the OK and Cancel buttons in the partial region. Next, bind the ModalPopup extender to an invisible control and display and hide the popup programmatically. Finally, if you need additional buttons in the popup to post without leaving the dialog, all that you have to do is add these buttons to the UpdatePanel that wraps the popup. For more details, have a look at the source code; a line of code is worth a thousand words.

Send your questions and comments for Dino to cutting@microsoft.com.


Dino Esposito is the author of Programming ASP.NET 3.5 Core Reference (Microsoft Press, 2008). Based in Italy, Dino is a frequent speaker at industry events worldwide. You can join his blog at weblogs.asp.net/despos.

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker