Click here to Skip to main content
Click here to Skip to main content

Smum County Modal Form for ASP.NET

By , 17 Mar 2008
 

Sample Image - SmumModalForm.jpg

Introduction

The ModalPopupExtender control provided by the ASP.NET AJAX Control Toolkit allows the display of content in a div panel that floats in the middle of the page and prevents the user from interacting with the rest of the page until the div panel has been closed, thus creating a modal form type of entry on a web page. This is a really useful technology, but I wanted to make a few improvements in this modal form-like interface.

Specifically, I wanted to:

  • Create a panel like control into which I can place content which will be displayed in the modal form without having to include a separate ModalPopupExtender control on the page.
  • Standardize the look of the modal form by automatically including a form-like header when the form is displayed, and allowing both the header and content to be styled using stylesheets.
  • Allow the modal form to be dragged around the page like a real modal form.
  • Provide the modal form with a more opaque drop shadow than the ModalPopupExtender normally provides.

ModalForm Control

To start, since I want this control to be a simple container into which I can drop other controls and content, it makes the most sense to create this control by inheriting from the Panel server control.

[ToolboxData("<{0}:ModalForm runat="server">")]
public class ModalForm : Panel
{
    public ModalForm() : base()
    {}
}

Just doing this gives us all the functionality of the Panel control meaning we have a container into which we can drop other stuff. Now, we need to make it look like a real modal form. This means creating a header with a title and a close icon that can be clicked in order to close the form. This is done during the rendering of the control by the CreateContainerControls routine.

private Panel CreateContainerControls()
{
    Panel header = new Panel();
    header.ID = "Header";   
    _extender.PopupDragHandleControlID = header.ID;   
    header.CssClass = this.HeaderCss;

    Panel title = new Panel();

    //Add title text to title panel.
    LiteralControl titleText = new LiteralControl(this.Title);
    title.Controls.Add(titleText);

    //Place title on left of header panel.
    title.Style.Add("float", "left");
    header.Controls.Add(title);

    //Only create a close image panel 
    //if a close image has been specified.
    HtmlImage imageButton = null;
    if (CloseImageUrl != "")
    {
        Panel closeImage = new Panel();

        //Add image to image panel.
        imageButton = new HtmlImage();
        imageButton.ID = ID + "_Button";
        imageButton.Border = 0;
        imageButton.Src = GetCloseImageUrl();
        imageButton.Style.Add("cursor", "pointer");

        //Both the image and the rollover image will
        //be saved as attributes of the image to facilitate
        //rollover.
        imageButton.Attributes.Add("image", Path.GetFileName(CloseImage));
        imageButton.Attributes.Add("rolloverImage", 
                                   Path.GetFileName(CloseRolloverImage));
        imageButton.Attributes.Add("onMouseOver", 
                                   "RolloverImage(event);");
        imageButton.Attributes.Add("onMouseOut", 
                                   "RolloverImage(event);");

        closeImage.Controls.Add(imageButton);

        //Place image on right of header panel.
        closeImage.Style.Add("float", "right");
        closeImage.CssClass = CloseImageCss;
        header.Controls.Add(closeImage);
    }

    Panel content = new Panel();
    content.CssClass = this.ContentCss;

    //Move all the children of the base panel 
    //to the children of the content panel.
    //Note as a child control is added to content, 
    //it is automatically removed from the base panel.
    int numChildren = this.Controls.Count;
    //Start at 2 since the popup panel and 
    ///the modal popup extender will be 0 and 1.
    for (int i = 2; i < numChildren; i++)
        content.Controls.Add(this.Controls[2]);

    //Add the header and content panels to the popup panel.
    _popup.Controls.Add(header);
    _popup.Controls.Add(content);

    //Now that all controls are in their proper places, 
    //create the cancel javascript for the CancelControlId.
    if (CloseImageUrl != "" && CancelControlId != "")
        imageButton.Attributes.Add("onClick", GetCloseScript());

    //Make sure this panel is hidden to begin.
    this.Style.Add("display", "none");

    return header;
}

In the above, I'm creating a header panel at the top of the ModalForm container panel with a content panel below this. The header panel contains two other panels, one for the caption which is floated to the left, and another for the image that is used to close the modal form which is floated to the right. The header, close image, content, and container panels can all have different stylesheet classes which gives the developer full control over the look of the modal form. Those controls that were children of the ModalForm container panel when the control was designed are moved to the new content panel. Note that I am attaching a JavaScript function to the onClick event of the image that will close the form. This function will simply force a click on whatever control has been setup in the ModalPopupExtender to close the modal form.

Setting the PopupDragHandleControlID property of the modal popup extender control will cause the modal popup to be draggable. The creation of the class level _popup and _extender variables used above will be discussed in the next section.

Creating the ModalPopupExtender on the Fly

So far, we've got a panel control that mimics the look of a modal form, but it doesn't actually have any of the modal form functionality. This is supplied by connecting the ModalForm control to a ModalPopupExtender control that is created on the fly by overriding the control's OnInit and CreateChildControls routines.

protected override void OnInit(EventArgs e)
{
    EnsureChildControls();
    base.OnInit(e);
}

protected override void CreateChildControls()
{
    base.CreateChildControls();

    // Create the extender and the popup control panel to act on.
    _extender = new ModalPopupExtender();
    _extender.ID = ID + "_ModalPopupExtender";

    _popup = new System.Web.UI.WebControls.Panel();
    _popup.ID = ID + "_Popup";

    //Pass on ModalPopup extender properties of this control to the extender.
    _extender.TargetControlID = ActivateControlId;
    _extender.BackgroundCssClass = BackgroundCss;
    _extender.CancelControlID = CancelControlId;
    _extender.OkControlID = OkControlId;
    _extender.DropShadow = DropShadow;
    _extender.OnOkScript = OnOkScript;
    _extender.PopupControlID = _popup.ID;

    //Pass on panel properties of this control to the popup panel.
    _popup.Width = this.Width;
    _popup.CssClass = this.CssClass;
    this.CssClass = "";

    if (!this.DesignMode)
    {
        Controls.AddAt(0, _popup);
        Controls.AddAt(0, _extender);
    }
}

The OnInit override calls EnsureChildControls which forces the CreateChildControls to run. This routine then simply instantiates the ModalPopupExtender control and popup panel on which the modal popup extender will operate. It sets the appropriate properties of these controls, and adds them to the Controls collection of the ModalForm control. Note that all of the properties you can set on the ModalPopupExtender control are exposed as properties of the ModalForm control, which are then passed on to the ModalPopupExtender control at this point.

Fixing Drag

There is a bug in the drag functionality of the ModalPopupExtender, at least in the version of the toolkit I used to create this demo. When the modal popup is dragged and then released, the popup snaps back to its original startup position. To fix this, I made the following changes to the DragPanelExtender which is used to give the modal popup drag functionality. In the onDragEnd method of the FloatingBehavior.js file, insert the line below that is in bold:

// void onDragEnd(Canceled)
this.onDragEnd = function(canceled) {
    canceled = false;
    if (!canceled) {
        var handler = this.get_events().getHandler('move');
        if(handler) {
            var cancelArgs = new Sys.CancelEventArgs();
            handler(this, cancelArgs);
            canceled = cancelArgs.get_cancel();
        }            
    }
//etc....

If the DragPanelExtender is used elsewhere in your website, this change may prevent the drag panel extender from working as you expect, but for our purposes with the modal popup extender, this works.

The ModalPopupExtender initially displays the modal form directly in the center of the visible browser window, and keeps it there when the browser window is scrolled or resized. Since our modal form is draggable, we can move it away from this initial display position. However, when the browser window is resized or scrolled, the modal form will be put right back in the middle of the browser window. To keep this from happening, we need to make a small change to the ModalPopupExtender control in order to disable this functionality. The change must be made in the ModalPoupBehavior.js JavaScript file which performs client side functionality for the ModalPopupExtender control. Specifically, the bolded lines below from the _attachPopup function, which add a client side handler to the resize and scroll events of the browser window, must be commented out:

_attachPopup : function() {
    if (this._DropShadow && !this._dropShadowBehavior) {
        this._dropShadowBehavior = $create(AjaxControlToolkit.DropShadowBehavior, {}, 
                                           null, null, this._foregroundElement);
        this._dropShadowBehavior.set_Opacity(.25);
        this._dropShadowBehavior.set_Width(10);
    }

    //$addHandler(window, 'resize', this._resizeHandler);
    //$addHandler(window, 'scroll', this._scrollHandler);
    this._windowHandlersAttached = true;
},

In addition, the bolded lines below from the _detachPopup function, which detaches the resize and scroll event handlers from the browser window, must be commented out:

_detachPopup : function() {
    if (this._windowHandlersAttached) {
        if (this._scrollHandler) {
            //$removeHandler(window, 'scroll', this._scrollHandler);
        }

        if (this._resizeHandler) {
            //$removeHandler(window, 'resize', this._resizeHandler);
        }
    }

    if (this._dropShadowBehavior) {
        this._dropShadowBehavior.dispose();
        this._dropShadowBehavior = null;
    }
},

Altering the Drop Shadow

The ModalPopupExtender natively allows you to specify that the modal form should appear with a drop shadow, but the default shadow it uses is a solid black which looks pretty bad. By tweaking the _attachPopup function in the modalbehavior.js file, we can easily alter the characteristics of the drop panel that is attached to the modal form. I added the bolded lines below to this routine in order to give the drop shadow an opacity of 25% and a width of 10 pixels:

_attachPopup : function() {
    if (this._DropShadow && !this._dropShadowBehavior) {
        this._dropShadowBehavior = $create(AjaxControlToolkit.DropShadowBehavior, 
                                      {}, null, null, this._foregroundElement);
        this._dropShadowBehavior.set_Opacity(.25);
        this._dropShadowBehavior.set_Width(10);
    }

    //$addHandler(window, 'resize', this._resizeHandler);
    //$addHandler(window, 'scroll', this._scrollHandler);
    this._windowHandlersAttached = true;
},

In Conclusion

The ModalForm control can be used in a web application at any point where you might choose to use a modal form in a WinForms application. For example, it could be used where a MultiView control may normally be used, in order to display a data entry form to the user. Or, it may be used to create a more user friendly and attractive message box. In any case, I think this project shows how those controls included in the ASP.NET AJAX Control Toolkit can be extended and modified in order to meet the needs of your application.

Demo Notes

Web.config, in the demo project, is setup to use the Basic theme which has an associated stylesheet and theme defined in the App_Themes folder. This is what gives the modal form its look. Web.config is also setup to recognize the 'ajaxtoolkit' prefix for the AJAX Control Toolkit assembly and the 'sc' prefix for the SmumCounty.WebControls assembly.

Since the ModalForm control creates and uses a ModalPopupExtender control from the ASP.NET AJAX Control Toolkit, this control may only be used with an AJAX enabled web project, and the form on which the control resides must also host a ScriptManager control.

The JavaScript file modalform.js has been included as an embedded resource in the project, and thus does not need to be distributed as a separate JavaScript file on the website that uses the ModalForm control.

The demo solution included above includes a project called AjaxControlToolkit. This is the ASP.NET AJAX Control Toolkit but with many of the controls removed to make the download smaller and with changes to the ModalPopupExtender as indicated above.

Revision History

  • November 15, 2006 – Created.
  • July 23, 2007 – Revised to work with the latest AJAX Control Toolkit.
  • August 1, 2007 – Fixed a small bug related to having more than one Smum Modal Form on a page.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Lou Flees
Web Developer
United States United States
Member
Lou has been a software developer for more than 16 years now mostly working on database applications. He is a big fan of the .NET environment.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 4memberDu Anh Quy24 Nov '10 - 17:32 
GeneralThe background is not on the entire pagememberEthan Decoster21 Nov '09 - 5:21 
Generalmodal background hidden in firefoxmemberDavid Oabile12 Mar '08 - 15:03 
GeneralRe: modal background hidden in firefoxmemberLou Flees17 Mar '08 - 10:54 
QuestionHow to make the Popup stay after a postbackmembersalsagirl29 Oct '07 - 4:45 
AnswerRe: How to make the Popup stay after a postbackmemberLou Flees30 Oct '07 - 3:31 
QuestionYour control do not work with updatePanel??memberdenzzo27 Oct '07 - 15:52 
AnswerRe: Your control do not work with updatePanel??memberLou Flees30 Oct '07 - 3:38 
QuestionHow to show this modal control from javascript codememberdenzzo23 Oct '07 - 18:07 
AnswerRe: How to show this modal control from javascript codememberLou Flees24 Oct '07 - 2:45 
GeneralRe: How to show this modal control from javascript codememberLou Flees24 Oct '07 - 2:50 
GeneralChild Control's event fires twicemembercarternc1 Oct '07 - 5:25 
QuestionClose image not workingmembermsmyth10 Aug '07 - 8:23 
AnswerRe: Close image not workingmemberLou Flees17 Aug '07 - 1:54 
GeneralMultiple Panel Control on a formmemberaibo29 Jul '07 - 2:15 
GeneralRe: Multiple Panel Control on a formmemberLou Flees29 Jul '07 - 11:23 
GeneralRe: Multiple Panel Control on a formmemberLou Flees1 Aug '07 - 11:14 
GeneralRe: Multiple Panel Control on a formmemberaibo2 Aug '07 - 8:12 
GeneralRe: Multiple Panel Control on a formmemberLou Flees2 Aug '07 - 8:23 
GeneralRe: Multiple Panel Control on a formmemberaibo2 Aug '07 - 11:07 
GeneralNew VersionmemberMander8123 Jul '07 - 4:19 
GeneralRe: New VersionmemberLou Flees23 Jul '07 - 6:31 
GeneralMicrosoft.web.extensions DLL is missingmemberthenucklehead5 Apr '07 - 20:17 
GeneralRe: Microsoft.web.extensions DLL is missingmemberLou Flees6 Apr '07 - 11:56 
GeneralRe: Microsoft.web.extensions DLL is missingmembercmbeginner1 Jun '07 - 21:55 
GeneralRe: Microsoft.web.extensions DLL is missingmemberrama charan21 Jul '07 - 3:13 
Generalarticle out of datemembersofter5 Apr '07 - 4:16 
GeneralRe: article out of datememberLou Flees6 Apr '07 - 11:57 
GeneralRe: article out of datememberLou Flees23 Jul '07 - 6:33 
GeneralInvoking from the code behindmemberbgriffin_tpa4 Apr '07 - 7:02 
Generalmodal background hidden in firefoxmembermich_antony7 Feb '07 - 1:27 
GeneralRe: modal background hidden in firefoxmemberLou Flees8 Feb '07 - 3:34 
GeneralRe: modal background hidden in firefoxmemberMike.Pappas6 Mar '07 - 6:40 
GeneralRe: modal background hidden in firefoxmemberMarkHaliday13 Mar '07 - 10:58 
GeneralRe: modal background hidden in firefoxmemberLou Flees14 Mar '07 - 14:04 
GeneralI cann't download the source code!memberdefcjjava21 Nov '06 - 3:38 
GeneralRe: I can't download the source code!memberLou Flees21 Nov '06 - 9:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 17 Mar 2008
Article Copyright 2006 by Lou Flees
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid