Muchas veces porque queda muy agradable a la vista, es conveniente abrir una ventana (popup) con información adicional sobre un ítem deseado. Otro caso (particularmente el que me tocó desarrollar) puede ser hacer una especie de Wizard donde las ventanas cumplan una suerte de varios pasos donde se pueda ir para atrás,adelante y/o finalizar, al mejor estilo instalación de cualquier soft (siguiente,siguiente,siguiente,instalar…finalizar).
Lo que voy a mostrar parte de una pagina Principal (Pagina Madre) que es la que va a abrir el popup y acá se pueden usar 2 maneras, una ventana modal o una ventana modeless.
ventana modal: Este tipo de ventanas no permite la interacción con la ventana anterior mientras este abierta, de hecho interrumpe cualquier ejecución que se este haciendo por atrás. Por ejemplo si nosotros hacemos un postback y en el servidor abrimos una ventana con el método de JS window.showModalDialog puede ocurrir que la pagina madre quede en blanco o a medio cargar.
ventana modeless: Estas ventanas si permiten la interacción con su ventana madre, de hecho es posible hacer click en la ventana de atrás y lo va a permitir. Por lo comentado arriba este tipo modal puede ser útil. Pero si por ejemplo vamos a abrir una modal de una fila en un gridview que tiene un enlace a eliminarlo, si lo hace mientras esta la modeles abierta se lo va a permitir.
Este ejemplo esta diseñado para IE 6.0 en adelante y voy a usar VS2005. Básicamente voy a hacer esto:

Voy a usar una sola pagina como Wizard pero pueden ser las que se necesiten, al fin y al cabo todas terminan en un pagina de Fin.
La pagina principal va a contar con script porque va a mantener una variable para poder tomarla al final:
<script>
var Guardar;
function DeseaGuardar()
{
window.document.Form1.txtOculto.value=Guardar;
__doPostBack('lnkGuardar','');
}
function Ejecutar()
{
//Agregamos el JS para pasar el parametro
var param='';
param='valor=' + window.document.Form1.TextBox1.value;
WizardGeneral(200,550,'Default2.aspx',param);
}
</script>
La función WizardGeneral esta en un JS que adjunto con todo el proyecto al final y es la que arma la URL para abrir el Wizard de una manera u otra (Modal/Modeless) . Yo lo hago con una función en el evento onclick llamando a Ejecutar pero por ejemplo si queremos hacer popups de una grilla agregándole a todas las rows solo vamos a necesitar el ID de cada row para levantar los datos en el popup con lo cual se puede hacer todo en la 1era carga de la pagina agregando el id en el evento RowDatabound. Yo a modo de ejemplo solo modifico un textbox.
El HTML de la pagina sería algo así:
<HTML>
<HEAD>
<title>Prueba</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="Visual Basic .NET 7.1" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<script language="javascript" src="JS/ScriptJS.js"></script>
</HEAD>
<body style="text-align: left">
<form id="Form1" method="post" runat="server">
<table>
<tr>
</tr>
</table>
<br />
<table width="100%">
<tr>
<td style="text-align: center;" colspan="3">
<asp:Label ID="lblerror" runat="server" Width="100%"></asp:Label></td>
</tr>
<tr>
<td style="width: 24px">
<asp:Label ID="Label1" runat="server" Text="Valor"></asp:Label></td>
<td style="width: 60px">
<asp:TextBox ID="TextBox1" runat="server" Width="279px"></asp:TextBox>
</td>
<td style="width: 100px">
</td>
</tr>
<tr>
<td style="width: 24px">
</td>
<td style="width: 60px; text-align: center;">
<input id="btnBoton" type="button" value="Popup" runat =server /></td>
<td style="width: 100px">
</td>
</tr>
</table>
<br />
<asp:LinkButton ID="lnkGuardar" runat="server"></asp:LinkButton>
<input id="txtOculto" style="width: 54px" runat =server type="hidden" />
</form>
</body>
</HTML>
Al final de la pagina hay 2 elementos importantes un Link, que es el que va a causar el postback de la pagina madre cuando termine el wizard y un hidden que es el que va a tener el valor de retorno del wizard.
El código de servidor es mas o menos este:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Introducir aquí el código de usuario para inicializar la página
If Not Page.IsPostBack Then
Try
txtOculto.Value = ""
btnBoton.Attributes.Add("onclick", "javascript:Ejecutar()")
Catch ex As Exception
lblerror.Text = ex.Message
End Try
End If
End Sub
Protected Sub lnkGuardar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkGuardar.Click
'txtOculto tiene el valor modificado que me devuelve el Wizard
If Not String.IsNullOrEmpty(txtOculto.Value) Then TextBox1.Text = txtOculto.Value
End Sub
Cuando la pagina de fin se cierre “cargar” de nuevo esta pagina ósea va a pasar por el page_load por eso hay que manejar bien el page.ispostback para no pisar valores y luego va a entrar por el click del Link que nosotros le formamos a hacer con la instrucción de Javascript __doPostBack.
La Pagina del Wizard tiene este HTML:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Pagina del Wizard</title>
<base target="_self">
</head>
<body >
<script language="javascript">
1:
2: var sData = dialogArguments;
3: sData.Guardar= '';
4: sData.DeseaGuardar();
5: /*function cargarVentana ()
6: {
7: document.form1.TextBox1.value=window.dialogArguments;
8: }*/
9:
10: function sourceCode() //Para ver el codigo fuente
11: {
12: d=window.open();
13: d.document.open('text/plain').write(document.documentElement.outerHTML);
14: }
</script>
<form id=”form1″ runat=”server” method=”post”>
<table>
<tr>
<td style=”width: 100px”>
<asp:Label ID=”Label1″ runat=”server” Text=”Valor del Wizard” Width=”118px”></asp:Label></td>
<td style=”width: 100px”>
<asp:TextBox ID=”TextBox1″ runat=”server”></asp:TextBox></td>
</tr>
<tr>
<td style=”width: 100px”>
</td>
<td style=”width: 100px”>
<asp:Button ID=”Button1″ runat=”server” Text=”Ejecutar” /></td>
</tr>
<tr>
<td colspan=”2″>
<asp:Label ID=”Label2″ runat=”server” ForeColor=”#0000C0″ Text=”Al cambiar esta valor se modifica el textbox de la pagina principal”></asp:Label></td>
</tr>
</table>
</form>
</body>
</html>
Tiene algunas particularidades la primera es que tiene le atributo target= self esto es para cuando hacemos el response.redirect a la pagina de fin no nos abra una pagina sino que siga en la misma. Después la función Javascript toma el dialogArguments que son las variables o funciones de la pagina madre. Y por ultimo algo que nos puede ser muy útil para depurar es una función para ver el HTML de la pagina cuando se esta ejecutando, porque las modales no dejan hacer click derecho para ver el código. Simplemente se agrega el nombre (sourceCode) en el evento onload del Form y listo apenas carga la pagina tenemos una nueva ventanita con el HTML
.
Este es el código de servidor:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
If Not Page.IsPostBack Then
TextBox1.Text = Request.Params("valor")
Else
Dim strpage As String = "General_Fin_W.aspx"
Dim paramFinal As String = "modo=modificacion&datos=".ToString + TextBox1.Text
strpage += "?".ToString + paramFinal.ToString 'General_Fin_W.aspx?modo=modificacion&datos=
Response.Redirect(strpage)
End If
Catch ex As Exception
Response.Write(ex.Message)
End Try
End Sub
y por ultimo la pagina de Fin HTML y código de Servidor:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title></title>
<script language="JavaScript" type="text/javascript">
1:
2: function CerrarWizard()
3: {
4: var sData = dialogArguments;
5:
6: //var datos= document.Form1.HiddenField1.value; // Esto vale lo que
7: //termina concatenando en el wizard
8: var datos= document.Form1.HiddenField1.value;
9: sData.Guardar=datos;
10: sData.DeseaGuardar();
11: window.close();
12: }
13:
14: function sourceCode() //Para ver el codigo fuente
15: {
16: d=window.open();
17: d.document.open('text/plain').write(document.documentElement.outerHTML);
18: }
19:
20:
</script>
</head>
<body class=”BodyNormal” onactivate =”CerrarWizard();”>
<form id=”Form1″ runat=”server” >
<div style=”text-align: center” >
<asp:Label ID=”lblMensajes” runat=”server” CssClass=”labelmensaje” Width=”98%”>Cargando …</asp:Label><br />
<asp:HiddenField ID=”HiddenField1″ runat=”server” />
</div>
</form>
</body>
</html>
Tiene una simple pantalla blanca con un mensaje cargando…. (pero la idea es que prácticamente no aparezca) porque como se ve en la funcion hace en onload le asigna el valor a sData.Guardar (osea el valor oculto de la pagina madre) y despues hace un window.close.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Select Case Request.Params("modo")
Case "modificacion"
If Not String.IsNullOrEmpty(Request.Params("datos")) Then
HiddenField1.Value = Request.Params("datos")
End If
End Select
End Sub
La idea es hacer una sola pagina de fin en caso de que necesitamos varios Wizard por ejemplo para cargar Personas o Productos, etc. Todas devuelven 1 dato por ejemplo si son Wizard de Alta podrían devolver el ID a la pagina Madre para poder levantarlo desde ahí.
El proyecto completo esta aqui
Actualización del 19/1/10 Lo subí a medifire aqui.
Saludos.