May the Force be with you.

AJAX Control Toolkit - Modal Popup Extender - The famous one - Help to solve common problems

Since the 5 january 2009, I've been working a lot with the Modalpopup extender at my job. I did a lot of non-standard and custom things with it, so I became a master of this control, lol!

Actually, I've just seen a lot of differents behavior about this Ajax Control and I found how to solve them.

First, let's dress a list of redundant problems.          (Note : each things below will be also in my code snippet)
  • You get an error if you don't assign a value to TargetControlID ?

  • This problem is very common when you have a dynamic control to bind with the TargetControlID of your modal popup extender. Even if it sounds the good thing to do, using the DynamicControlID won't solve your problem. The TargetControlID is mandatory.

    So, the easiest way to do it is to add a dummycontrol to bind it with the ID. Then, on your dynamic buttons you can add a javascript function on the OnClientClick event to show the modal popup.

  • Code behind event are not firing when you click on the modal popup extender Ok button ?

  • In the Modal popup extender you have two similar property "OkControlID" and "CancelControlID", when you bind a button to those it won't do any postback to the server. Don't forget that modal popup is ClientSide, if you want to do a postback to the server then don't bind your button ID with one of those.

    There are two way to catch the click event; assign your code behind function name to the "OnClick" Event of the button or add Handles yourButton.Click to your code behind function.

  • Your .gif or any other animated image in your Modal Popup Extender stop animating in IE ?

  • This behavior is pretty anoying but actually it's very easy to solve it. You must include your whole page content in an UpdatePanel. If you are using a MasterPage put the Update Panel right after your ContentPlaceHolder tag, otherwise just after your Form and ScriptManager tag. You must put all page content in there including each modal popup extender and their pannel.

    It's also strongly recommended to put the content of your panel (linked to the PopupControlID of your current Modal Popup Extender) in another UpdatePanel if you don't want to have some strange behavior.

  • Your modal popup extender (blinks - flash - shows up) only a short moment on the page load ?

  • Another common problem who can be solve pretty quickly. Please just add this property to your Panel (the one linked with your modal popup of course) : Sytle="display:none". The problem will be solved for most people...

    That's suppose to solve it actually, but I'm still having trouble for Firefox. On my job website, the modal popup still appear for 1 second on the page load which is pretty anoying. I tought with the 3.0.6 patch of FF it could be solved but it wasn't. In another hand it's working in all other browsers, so I guess it's maybe just a special config to set for Firefox otherwise it's prolly a problem on their side.

    Whatever it is, I'm still on it !

  • You've set the background property to transparent but it display solid black or another non-transparent color.

  • It's not a big deal here, most of developer will solve alone this problem. It seems that some addict of the wizard tool who don't understand what they do had troubles with that. Actually, I don't really understand why it could be usefull to do that... Anyway, just don't set the background:transparent because if you are using a DropShadow on the ModalPopup, in reality a black square is displayed backward, so you will just see it.

  • You modify server-side the content of your modal popup but when it shows up it's still unmodified.

  • That's why it's usefull to have an UpdatePanel wraped around your current Panel content, server-side after any modifications and after the call Modal.show(), just update your pannel like that myUpdatePanel.Update(). That will solve the problem.

    Note that it's not mandatory to use the Update Panel to wrap the content of the Panel linked with your Modal popup extender, but according to some Microsoft expert like Vince Xu for example, it's a good practice to use it in this case.

I made a little project as an example if you want to see it working, there is 2 practical applications in it.

The first example is very usefull to warn user or if you want him to wait during the loading process. I used it without any button, so it's really when you need to do some processing server-side. Example creating a .zip file fetched from the database. When the file is ready, you can reload the page with a Response.Redirect and then the modal popup will hide because of the reloading. So during that time, the user won't think your page is freezed.

The second one is only a simple form with some Javascript feature in it. Like a default text for the required field, a bit like your Google sreach bar on your browser, when you click in it the text disapear. I also explain how to do a post-back from your modal popup extender.

I also put the code below if you don't want to download the source code.

Hope it will help.
Good luck !


<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Deal with Modal Popup Extender</title>
    <link href="App_Themes/default/default.css" rel="stylesheet" type="text/css" />
    
    <script type="text/javascript" language="javascript">
     //This function is not used in the code, but it's a nice example
     //how to do an ASP.Net Post back with JavaScript
     function fnClickOK(sender, e)
     {
        __doPostBack(sender,e); 
     } 
     function openProcessModal()
     {
        var modal = $find('mpeProcessing');
        modal.show();
     }
     function loadDefaultValue()
     {
        //assign the default value
        document.getElementById('tbxUsername').value = "This field is mandatory";
        document.getElementById('tbxEmail').value = "This field is mandatory";
        document.getElementById('tbxCommentTitle').value = "This field is mandatory";
        document.getElementById('tbxComment').value = "This field is mandatory";
        //assing the default value color
        document.getElementById('tbxUsername').style.color= "gray";        
        document.getElementById('tbxEmail').style.color= "gray";        
        document.getElementById('tbxCommentTitle').style.color= "gray";        
        document.getElementById('tbxComment').style.color= "gray";        
     }
     function clearFieldOnFocus(btnId)
     {
	//I base my validation on the style color
        if (document.getElementById(btnId).style.color == "gray")
        {
            document.getElementById(btnId).value = "";
            document.getElementById(btnId).style.color= "black"; 
        }
     }
 </script>
</head>
<body>
<form id="example" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="upMainDiv" runat="server">
<ContentTemplate>
<div id="MainDiv">
    <p>
      <asp:LinkButton ID="lbtnProcess" runat="server" OnClick="doProcessing" 
                      OnClientClick="openProcessModal()" 
                      Text="Download and test processing modal popup" />
      <br /><br />
      <asp:LinkButton ID="lbtnForm" runat="server" OnClientClick="loadDefaultValue()" 
                      Text="Open form and test the form modal popup" />
    </p>
</div>
<asp:Label ID="dummyLabel" runat="server" Enabled="false" />
<cc1:ModalPopupExtender ID="mpeProcessing" runat="server" TargetControlID="dummyLabel" 
                        PopupControlID="panProcessing"
                        BackgroundCssClass="AJAX_ModalPopup_Background"
                        RepositionMode="RepositionOnWindowResizeAndScroll" />
<asp:Panel ID="panProcessing" runat="server" style="display:none" 
           CssClass="AJAX_ModalPopup_ProcessPanelStyle">
    <asp:UpdatePanel ID="upProcessing" runat="server" UpdateMode="Always">
        <ContentTemplate>
    
        <asp:Image ID="imgProcessing" runat="server" ImageUrl="~/images/loading.gif" />
        <br /><br />
        <asp:Label ID="lblProcessing" runat="server" 
             Text="Yeah yeah yeah... I'm really doing something in backgroung, just wait man !" />
                       
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Panel>
<cc1:ModalPopupExtender ID="mpeForm" runat="server" TargetControlID="lbtnForm" 
                        PopupControlID="panForm" CancelControlID="btnCancel"
                        BackgroundCssClass="AJAX_ModalPopup_Background" 
                        RepositionMode="RepositionOnWindowResizeAndScroll"/>
<asp:Panel ID="panForm" runat="server" style="display:none" 
           CssClass="AJAX_ModalPopup_FormPanelStyle">
    <asp:UpdatePanel ID="upForm" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
    
    <%-- The property here -> HorizontalAlign="Center" is to center the table in Firefox --%>
    <asp:Table ID="tlbForm" runat="server" CssClass="ASP_tblForm" HorizontalAlign="Center">
        <asp:TableRow>
            <asp:TableCell runat="server" ColumnSpan="2">
                <asp:Label ID="lblTitle" runat="server" Text="Adding a comment"
                           CssClass="ASP_tblFormTitle_Style" /><br /><br />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ASP_FieldTitle" >
                <asp:Label ID="lblUsername" runat="server" Text="Username :"/>
            </asp:TableCell>
            <asp:TableCell CssClass="ASP_Field">
                <asp:TextBox ID="tbxUsername" runat="server" Width="160px" MaxLength="20"/>
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ASP_FieldTitle" >
                <asp:Label ID="lblEmail" runat="server" Text="Email :"/>
            </asp:TableCell>
            <asp:TableCell CssClass="ASP_Field">
                <asp:TextBox ID="tbxEmail" runat="server" Width="220px" MaxLength="50"/>
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ASP_FieldTitle" >
                <asp:Label ID="lblCommentTitle" runat="server" Text="Comment title :"/>
            </asp:TableCell>
            <asp:TableCell CssClass="ASP_Field">
                <asp:TextBox ID="tbxCommentTitle" runat="server" Width="250px" MaxLength="50"/>
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ASP_FieldTitle" >
                <asp:Label ID="lblComment" runat="server" Text="Comment :"/>
            </asp:TableCell>
            <asp:TableCell CssClass="ASP_Field">
                <asp:TextBox ID="tbxComment" runat="server"  Width="342px" TextMode="MultiLine"  
                             Wrap="true" Rows="7" MaxLength="250" 
			      CssClass="ASP_TextBox_Multiline"/>
            </asp:TableCell>
        </asp:TableRow>
    </asp:Table>
    
    <asp:Button ID="btnSumbit" runat="server" Text="Sumbit" CssClass="ASP_Button_Style"/>
    <asp:Button ID="btnCancel" runat="server" Text="Cancel" CssClass="ASP_Button_Style"/>
        
    </ContentTemplate>
    </asp:UpdatePanel>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
 
Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Me.tbxUsername.Attributes.Add("OnFocus", "clearFieldOnFocus(this.id)")
        Me.tbxEmail.Attributes.Add("OnFocus", "clearFieldOnFocus(this.id)")
        Me.tbxCommentTitle.Attributes.Add("OnFocus", "clearFieldOnFocus(this.id)")
        Me.tbxComment.Attributes.Add("OnFocus", "clearFieldOnFocus(this.id)")
    End Sub

    Public Sub sumbitForm(ByVal sender As System.Object, _ 
			    ByVal e As System.EventArgs) Handles btnSumbit.Click
        'Do processing, saving the comment into the database for example.
    End Sub

    Public Sub doProcessing(ByVal sender As System.Object, _ 
			     ByVal e As System.EventArgs) Handles lbtnProcess.Click
        'Here you could so some processing like fetching your .zip file like I said before. 
        Threading.Thread.Sleep(2500)
        Response.Redirect(Request.Url.ToString(), False)
    End Sub
End Class
				

How to send a mail with ASP.NET with attachment or not, using the FileUpload control

This is my first snippet, a really big one, I show you how to send a mail in ASP.NET using VB.
Later, I will probably put this class in the download section and replace this snippet with another one.

Of course you can add this class to your ASP.NET project and use it.

In this case I just code it for only one file attachment per mail.
					
Imports Microsoft.VisualBasic
Imports System.Net
Imports System.IO
'Next line needed to accessing Web.Config file with AppSettings
Imports System.Configuration.ConfigurationManager

Public Class UtilMail

    Private _smtpServer As New Mail.SmtpClient(AppSettings("smtpIPAddress"), _
					       AppSettings("smtpPortNumber"))
    Private _mail As Mail.MailMessage
    Private _SourceMail As String
    Private _DestinationMail As String
    Private _Subject As String
    Private _Body As String

    Public Property SourceMail() As String
        Get
            Return _SourceMail
        End Get
        Set(ByVal value As String)
            _SourceMail = value.Trim
        End Set
    End Property
    
    Public Property DestinationMail() As String
        Get
            Return _DestinationMail
        End Get
        Set(ByVal value As String)
            _DestinationMail = value.Trim
        End Set
    End Property

    Public Property Subject() As String
        Get
            Return _Subject
        End Get
        Set(ByVal value As String)
            _Subject = value.Trim
        End Set
    End Property

    Public Property Body() As String
        Get
            Return _Body
        End Get
        Set(ByVal value As String)
            _Body = value.Trim
        End Set
    End Property

    Public Sub New()
        DestinationMail() = AppSettings("destination_emailAdress")
        _SourceMail = ""
        _DestinationMail = ""
        _Subject = ""
        _Body = ""
    End Sub

    Public Sub SendMail(ByRef FileUpload As WebControls.FileUpload)

        _mail = New Mail.MailMessage(_SourceMail, _DestinationMail, _Subject, _Body)

        Try
	'Of course the FileUpload.HasFile return a boolean value
            SendFile(FileUpload, FileUpload.HasFile)

        Catch ex As Exception
            Throw New Exception("Error during email sending process. (" & ex & ")")
        End Try

    End Sub

    Private Sub SendFile(ByRef FileUpload As WebControls.FileUpload, _ 
			 Optional ByVal AttachFile As Boolean = True)

        If AttachFile Then
	
	   'Here I am using a System.IO function to get the temporary folder on the server 
            Dim strPath As String = Path.GetTempFileName()
	   'and I save the file there.
	   'strPath contains the full path of the file with file name and his extension
            FileUpload.PostedFile.SaveAs(strPath)

            Dim mailAttach As New Mail.Attachment(strPath)

	   'Okay, here I create another thread who will wait before deleting the TempFile
	   'I use that to prevent the file deletion if the mail isn't sended.
	   'Like you see, AddressOf is a reference to the name of the method you want to use
            AddHandler _smtpServer.SendCompleted, AddressOf DeleteTempfile

	   'Here I'm locking the mail variable for precaution
            SyncLock (_mail)
                _mail.Attachments.Add(mailAttach)
                _mail.Attachments.Item(0).Name = FileUpload.PostedFile.FileName
	   'The new thread will begin on next line
                _smtpServer.SendAsync(_mail, strPath)
            End SyncLock
        Else
            _smtpServer.Send(_mail)
        End If
    End Sub

    Private Sub DeleteTempfile(ByVal sender As Object,  _ 
			       ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
 
	If e.Error Is Nothing Then
            SyncLock (_mail)
	   'I had a problem here because even if the mail was sent, the TempFile 
	   'was still locked by the server so we need next line for releasing the lock
                _mail.Attachments.Dispose()
            End SyncLock

	   'after that we can delete it without any problems.
            System.IO.File.Delete(e.UserState.ToString)
        Else
            Throw New Exception(e.Error.ToString)
        End If
	
    End Sub
    
End Class
					

WARNING - you must include Async="true" in the Page tag of your aspx page to be able to use mutli-threading.

For the AppSettings() method you need to insert key like that in your Web.Config, section <configuration>
<appSettings>
	<add key="destination_emailAdress" value="forcemagic@forcemagic.org"/>
</appSettings>
If you have any comments or suggesions, send me a mail forcemagic at forcemagic.org!
Thanks in advance for any comments and suggestions.