Dialog Hell
ASP.NET is a great tool, but it definately has its limitations. One of those limitations is the fact that it has no built in support for any kind of UI that uses dialogs. I assume that if you have been using ASP.NET for a decent amount of time, you have run into this problem more than once.
At the base level, the problem is pretty simple to solve, but if you have a lot of dialogs in your application, you can wind up writing a lot of extra code just to get things working. This isn't even to mention that things go from bad to worse if you want your dialogs to function like real dialogs (ie. they are reusable, so you can launch, wait for the user to select an item, and then do something based off of that selection back in the code behind for the page that launched the dialog).
While building our ASP.NET based CMS (<shameless_plug>a very cool product which is due for release in the near future</shameless_plug>), it quickly became aparent that all the JavaScript coding that we were doing was quite redundant and was quite a pain. So, I put together a few classes to handle most of the basic dialog functionality. If you are in the same type of situation, you may find these classes useful. Basically, there is one base class that can be used to create a draggable dialog control (Dialog). This class basically handles launching the dialog and processing the return results (an “Open“ function is included to create the JS launch script for your dialog). The second class, “DialogPage“ serves as the base page class for your dialogs (just change inheritance on the Page class in your code behind file). It contains a few helper methods to close the window and return results. A third class, PostBackHandler is a stripped down control with no UI that allows you to handle the results of the dialog via a PostBack event. Using this type of approach definately makes working with the custom dialogs in your project a lot more developer-friendly (not to mention that you can extend the base classes to have things like modal dialog support, and all your dialogs will be automatically upgraded).
public abstract class Dialog : Control, INamingContainer{
public Dialog(){
pbhDialogHandler.ID = "pbhDialogHandler";
pbhDialogHandler.PostBack+=
new PostBackEventHandler(pbhDialogHandler_PostBack);Controls.Add(pbhDialogHandler);
}
protected override void OnPreRender(EventArgs e){
base.OnPreRender (e);Page.RegisterStartupScript("__dialog","<script>function __processDialogResults(controlID, results) { __doPostBack(controlID,results); }</script>");
}
PostBackHandler pbhDialogHandler =
new PostBackHandler();protected override void CreateChildControls(){
base.CreateChildControls ();}
void pbhDialogHandler_PostBack(object sender, PostBackEventArgs e){
ProcessDialogResults(e.EventArgument);
}
protected virtual void ProcessDialogResults(string results){
}
protected void Open(string windowName, string url, int width, int height){
if(url.StartsWith("~/")){
url = Page.Request.ApplicationPath+"/"+url.Substring(2);
}
if(url.IndexOf("?") == -1){
url = url+"?ControlID="+HttpUtility.UrlEncode(
this.pbhDialogHandler.UniqueID.Replace(":","$"));}
else{
url = url+"&ControlID="+HttpUtility.UrlEncode(
this.pbhDialogHandler.UniqueID.Replace(":","$"));}
Page.RegisterStartupScript("__open", "<script>window.open('"+url+"', '"+windowName+"', 'width="+width+", height="+height+", scrollbars=no, resizable=no, toolbar=no, location=no,menubar=no, directories=no');</script>");
}
public abstract void ShowDialog();}
public abstract class DialogPage : Page{
public DialogPage(){
}
string ControlID{
get{
return HttpUtility.UrlDecode(Request["ControlID"]);}
}
protected void Close(string results){
Page.RegisterStartupScript("__close", "<script>window.opener.__processDialogResults('"+ControlID+"',\""+results.Replace("\"", "\\\"")+"\"); window.close();</script>");
}
protected void Close(){
Page.RegisterStartupScript("__close", "<script>window.close();</script>");
}
}
public class PostBackEventArgs{
string eventArgument;public string EventArgument{
get{
return eventArgument;}
set{
eventArgument=
value;}
}
}
public delegate void PostBackEventHandler(object sender, PostBackEventArgs e);public class PostBackHandler : Control, IPostBackEventHandler{
public PostBackHandler(){
}
public event PostBackEventHandler PostBack;#region
IPostBackEventHandler Memberspublic void RaisePostBackEvent(string eventArgument){
PostBackEventArgs e =
new PostBackEventArgs();e.EventArgument = eventArgument;
if(PostBack != null){
PostBack(
this, e);}
}
#endregion
}