Introduction
Often when programming in ASP.NET, you want to pop up a dialog window that requests some kind of user input. When the user is finished with the dialog and closes it, you want the main form to fire a server event that performs some kind of refresh or other actions. Surprisingly, this task is not as easy as it seems, and a Google search turns up lots of confusing information. You can easily end up writing much more code than you need to. After some experimenting, I think I found a reasonably neat and tidy way to accomplish this, and so that I never have to do it again, I wrapped the code for opening and closing the dialog into a pair of server controls.
This article presents a pair of server controls, DialogOpener
and DialogCloser
, that enable you to quickly set up a dialog that opens, receives user input, closes, and fires an event of your choice on the main form.
DialogOpener
Here is the code for the DialogOpener
control:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web;
namespace ExWebCtlLib
{
[DefaultProperty("Text"), ToolboxData("<ExWebCtlLib:DialogOpener
runat="server"></WebCtlLib:DialogOpener>")]
public class DialogOpener : System.Web.UI.WebControls.WebControl,
IPostBackEventHandler
{
true)>
public event EventHandler DialogClosed
{
add
{
dialogClosed += value;
}
remove
{
dialogClosed += value;
}
}
private event EventHandler dialogClosed;
true), Category("Appearance"), DefaultValue("")>
public string Text
{
get
{
return text;
}
set
{
text = value;
}
}
private string text = "Open Dialog";
true), Category("Appearance"), DefaultValue("")>
public string DialogName
{
get
{
return dialogname;
}
set
{
dialogname = value;
}
}
private string dialogname = "Dialog";
true), Category("Appearance"), DefaultValue(true)>
public bool Scrollbars
{
get
{
return scrollbars;
}
set
{
scrollbars = value;
}
}
private bool scrollbars = true;
true), Category("Appearance"), DefaultValue("")>
public string DialogPagePath
{
get
{
return dialogPagePath;
}
set
{
dialogPagePath = value;
}
}
private string dialogPagePath = "";
true), Category("Appearance"), DefaultValue("")>
public string DialogParam
{
get
{
if( ViewState[ this.ID + "DialogParam" ] == null )
return dialogParam;
else
return (string)ViewState[ this.ID + "DialogParam" ];
}
set
{
dialogParam = value;
ViewState[ this.ID + "DialogParam" ] = value;
}
}
private string dialogParam = "-1";
protected override void Render(HtmlTextWriter output)
{
string url = HttpContext.Current.Request.ApplicationPath + "/" +
DialogPagePath + @"?PostBackEventReference=" +
Page.Server.UrlEncode( Page.GetPostBackEventReference(this) ).Replace(
"'", "%27" ) + @"&DialogParam=" + DialogParam;
string height = Height.Value.ToString();
string width = Width.Value.ToString();
string scrollbars = Scrollbars ? "yes" : "no";
output.Write( @"<input id=""ExFxDialogOpener"" type=""button""
value=""" + Text + @""" class=""" + CssClass + @"""
onclick=""javascript:OpenDialog('" + url + "', '" +
DialogName + "', " + height + ", " + width + ", '" +
scrollbars + "' " + @" );"">" );
}
public void RaisePostBackEvent(string eventArgument)
{
if( dialogClosed != null )
dialogClosed( this, new EventArgs() );
}
}
}
The code is mostly very straightforward, just some simple properties with getters and setters. The interesting property is the DialogClosed
event property. This event will fire on the form when the dialog is closed. Now look at the construction of the URL, specifically the PostBackEventReference
param. The HTML that gets generated by the control looks something like this, depending on the exact settings of the control:
<input id="ExFxDialogOpener" type="button" value="Image Gallery"
class="Button" onclick="javascript:OpenDialog(
'/html/Forms/Fx/ImageGallery.aspx?PostBackEventReference=
__doPostBack(%27_ctl15%24ImageGalleryOpener%27%2c%27%27)
&DialogParam=SelectImage', 'Dialog', 456, 580, 'yes' );">
The PostBackEventReference
is passed as a URL param to the dialog. We'll use that information in the dialog to fire the server event on closing.
The script calls the JavaScript function OpenDialog(...)
. You'll need to ensure that the OpenDialog
script is in your page by using RegisterClientScript
to register it in your main form, or modify the control to call window.open
directly. Here's the script for OpenDialog
.
function OpenDialog( url, name, height, width, scrollbars )
{
if( scrollbars == null )
scrollbars = "yes";
var top = (screen.height - height) / 2;
var left = (screen.width - width) / 2;
window.open( url, name, "width = " + width + ",
height = " + height + ", menubar = no,
scrollbars = " + scrollbars + ", toolbar = no,
location = no, directories = no, resizable = no,
top = " + top + ", left = " + left );
(Since we have standard JavaScript registration templates in our shop, OpenDialog
is always available on our pages, which is why it's not included in the DialogOpener
code.)
DialogCloser
The DialogCloser
control generates the necessary JavaScript to close the dialog and fire the server event on the main form. It does this by reading the PostBackEventReference
that we passed in the URL using DialogOpener
and constructing the required JavaScript.
Here's the code for DialogCloser
:
public class DialogCloser : System.Web.UI.WebControls.WebControl
{
public void Close()
{
if( HttpContext.Current.Request[ "PostBackEventReference" ] == null )
Page.RegisterStartupScript("__close", "<script>window.close();</script>");
else
{
string script = String.Format("<script>window.opener.{0};
window.close();</script>", HttpContext.Current.Request[
"PostBackEventReference" ] );
Page.RegisterStartupScript( "__close", script );
}
}
}
Here's an example of the JavaScript that gets registered when DialogCloser.Close
is called:
<script>
window.opener.__doPostBack('_ctl15$ImageGalleryOpener','');
window.close();
</script>
Compiling the Controls
To compile the controls, just create a couple of new server control classes in your own server control library. If you don't have a server control library, create a new project of type "Class Library", drop in the code, compile, then right click on your toolbox, click Add/Remove Items and browse to the .dll you just created. Click OK and the two controls will appear on your toolbox.
Using the Controls
Using the controls is easy. Create two aspx pages. One will be the main form and the other will be the dialog. Drop the DialogOpener
onto the main form and open the Properties sheet. Set the DialogPagePath
property to the path and name of the dialog page. Double-click the DialogClosed
event and write the code you want to run when the dialog closes.
Drop the DialogCloser
control onto the dialog form. Somewhere in the dialog code, when you want the dialog to close, write the following line:
DialogCloser.close();
Run the main form. Click on the DialogOpener button. Close the dialog. The DialogClosed
event will be called on the main form and your event handler code will run.
Conclusion
This short article has shown you how to create a pair of useful server controls that you can drop on a pair of forms to handle dialog opening and closing, and calling a server event on the main form when the dialog closes. I hope this saves you some headache searching for the answer like I did!