Durante el desarrollo de una aplicación Web, es posible que nos encontremos ante el diseño de un WebForm en el que debido a las características de la información a recabar, resulte conveniente que ciertos datos sean introducidos desde un formulario independiente del principal, empleando una funcionalidad similar a la que ofrecen los cuadros de diálogo de Windows Forms, cuando abrimos un formulario mediante el método ShowDialog de la clase Form.
ModalPopupExtender. Descripción general
Afortunadamente, mediante el uso de AJAX, implementar este funcionamiento no solamente es posible, sino que resulta muy sencillo gracias al uso de ModalPopupExtender, uno de los componentes incluidos en el paquete de controles Ajax Control Toolkit.
ModalPopupExtender es un extensor, lo que significa que permite ampliar o extender la funcionalidad de un control ASP.NET ya existente. Para el caso que nos ocupa, podemos aplicar dicho extensor a un control Panel -también podríamos haber utilizado un control Table-, consiguiendo que el comportamiento de este último se asemeje al de un cuadro o caja de diálogo, de forma que cuando el ModalPopupExtender es activado y el control Panel asociado que representa el diálogo es visualizado, el resto de controles de la página quedan deshabilitados hasta que no pulsemos el botón de confirmación o cancelación que a tal efecto deberemos haber incluido en el control Panel.
En el presente artículo vamos a desarrollar un ejemplo que nos permita describir los elementos más importantes del ModalPopupExtender, así como su aplicación práctica en la construcción de un diálogo de selección de datos.
El escenario de trabajo
Supongamos que debemos desarrollar un formulario Web para realizar una toma de datos, con un aspecto como el mostrado en la siguiente figura.
Entre el conjunto de controles TextBox de este formulario, existe uno: txtSituacion, que el usuario debería rellenar con el nombre de una ciudad, mes y año, en un formato como el del siguiente ejemplo:
Zaragoza, marzo de 2008
A pesar de que el usuario tiene plena libertad para escribir este valor dentro del mencionado TextBox, no estaría de más que recibiera una pequeña ayuda. De esta tarea se van a ocupar varios controles DropDownList, que situados dentro de un control Panel, van a funcionar como un cuadro de diálogo gracias a un ModalPopupExtender, y nos van a permitir seleccionar cada una de las partes del dato a introducir en txtSituacion, dejando a la aplicación el trabajo de unir todos los fragmentos para componer la cadena final resultante, que asignaremos al TextBox.
Los controles principales de la página
En primer lugar crearemos un nuevo proyecto ASP.NET, y nos situaremos en el diseñador de la página Web, donde comenzaremos por agregar los controles que conformarán el formulario de entrada de datos que ya vimos en la anterior figura. Es muy importante no olvidar la inclusión de un componente ScriptManager a la página, dado que vamos a implementar características AJAX en la misma. El siguiente bloque de código muestra todas las instrucciones necesarias.
<form id=»form1″ runat=»server»>
<asp:ScriptManager ID=»ScriptManager1″ runat=»server» />
<div>
<table border=»2″>
<tr>
<td colspan=»2″ align=»center»>
<asp:Label ID=»Label1″ runat=»server» Text=»Datos de solicitud» Font-Bold=»True»
Font-Underline=»True» />
</td>
</tr>
<tr>
<td>
<asp:Label ID=»Label2″ runat=»server» Text=»Nombre:» />
</td>
<td>
<asp:TextBox ID=»txtNombre» runat=»server» />
</td>
</tr>
<tr>
<td>
<asp:Label ID=»Label3″ runat=»server» Text=»e-mail:» />
</td>
<td>
<asp:TextBox ID=»txtEmail» runat=»server» />
</td>
</tr>
<tr>
<td>
<asp:Label ID=»Label7″ runat=»server» Text=»Situación:» />
</td>
<td>
<asp:TextBox ID=»txtSituacion» runat=»server» Width=»300″ />
</td>
</tr>
<tr>
<td>
<asp:Button ID=»btnAsistente» runat=»server» Text=»Asistente de selección» Width=»150″ />
</td>
<td>
<asp:Button ID=»btnGrabar» runat=»server» Text=»Grabar datos» Width=»125″ />
</td>
</tr>
</table>
</div>
</form>
Los controles del cuadro de diálogo
Continuando en este mismo diseñador del formulario Web, como siguiente paso añadiremos un Panel en cuyo interior situaremos los controles que constituirán nuestro cuadro de diálogo. Adicionalmente incluiremos en la cabecera de la página un estilo para que el aspecto del control Panel y su contenido resulte más atractivo al usuario.
<style type=»text/css»>
.CajaDialogo
{
background-color: #99ffcc;
border-width: 4px;
border-style: outset;
border-color: Yellow;
padding: 0px;
width: 200px;
font-weight: bold;
font-style: italic;
}
.CajaDialogo div
{
margin: 5px;
text-align: center;
}
</style>
//….
//….
<asp:Panel ID=»pnlSeleccionarDatos» runat=»server» CssClass=»CajaDialogo»>
<div style=»padding: 10px; background-color: #0033CC; color: #FFFFFF;»>
<asp:Label ID=»Label4″ runat=»server» Text=»Seleccionar datos» />
</div>
<div>
<table>
<tr>
<td>
<asp:Label ID=»Label5″ runat=»server» Text=»Ciudad:» />
</td>
<td>
<asp:DropDownList ID=»ddlCiudades» runat=»server»>
<asp:ListItem>Zamora</asp:ListItem>
<asp:ListItem>Teruel</asp:ListItem>
<asp:ListItem>Salamanca</asp:ListItem>
<asp:ListItem>Sevilla</asp:ListItem>
<asp:ListItem>Lugo</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td>
<asp:Label ID=»Label6″ runat=»server» Text=»Mes:» />
</td>
<td>
<asp:DropDownList ID=»ddlMeses» runat=»server» />
</td>
</tr>
<tr>
<td>
<asp:Label ID=»Label8″ runat=»server» Text=»Año:» />
</td>
<td>
<asp:DropDownList ID=»ddlAnualidades» runat=»server» />
</td>
</tr>
</table>
</div>
<div>
<asp:Button ID=»btnAceptar» runat=»server» Text=»Aceptar» />
<asp:Button ID=»btnCancelar» runat=»server» Text=»Cancelar» />
</div>
</asp:Panel>
La siguiente figura muestra el aspecto del panel recién creado.
Fijándonos en el código aspx que acabamos de escribir, nos habremos percatado de que el único control DropDownList al que hemos añadido valores en su lista es ddlCiudades; esto es debido a que los otros dos controles de lista serán llenados en el code-behind de la página, en el evento Load para ser más exactos.
La técnica seguida para añadir los valores a las listas de mes y año consistirá en inicializar una variable DateTime y dos ArrayList; mediante un bucle incrementaremos el valor del mes y año de la fecha, asignándola a los ArrayList; por último, asignaremos estos ArrayList como origen de datos de los controles DropDownList. El código correspondiente a este proceso lo vemos a continuación.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// rellenar dos listas con los valores
// de meses y años que usaremos
// en los controles de lista desplegable
ArrayList alMeses = new ArrayList();
ArrayList alAnualidades = new ArrayList();
DateTime dtFecha = new DateTime(2000, 1, 1);for (int nContador = 1; nContador <= 12; nContador++)
{
alMeses.Add(dtFecha.ToString(«MMMM»));
alAnualidades.Add(dtFecha.Year);
dtFecha = dtFecha.AddMonths(1);
dtFecha = dtFecha.AddYears(1);
}// asignar las listas a los controles
this.ddlMeses.DataSource = alMeses;
this.ddlMeses.DataBind();this.ddlAnualidades.DataSource = alAnualidades;
this.ddlAnualidades.DataBind();
}
}
La causa de emplear dos técnicas distintas de llenar las listas desplegables -desde código aspx y code-behind- reside simplemente en mostrar al lector las distintas posibilidades existentes de abordar esta operación sobre este tipo de control.
Dotando al Panel del comportamiento de un diálogo. ModalPopupExtender entra en acción
Para proporcionar a nuestro control Panel el comportamiento de un cuadro de diálogo nos queda pendiente el detalle más importante: añadir a la página Web el ya comentado control AJAX ModalPopupExtender, que una vez conectado con el Panel, hará que este funcione como una ventana modal, impidiendo al usuario que interactúe con otros elementos que no sean los contenidos dentro del control Panel.
La siguiente lista muestra las principales propiedades del ModalPopupExtender que tendremos que manipular, para configurar adecuadamente nuestra caja de diálogo.
— TargetControlID. Identificador del control de la página Web que provocará la activación del ModalPopupExtender.
— PopupControlID. Identificador del control que el ModalPopupExtender muestra como cuadro de diálogo modal. Podemos utilizar cualquier control que actúe como contenedor: Panel, Table, etc.
— OkControlID. Identificador de un control situado dentro del cuadro de diálogo, que actuará como botón de confirmación. Esta labor corresponderá habitualmente a un control de tipo Button, pero podemos emplear otros tipos.
— CancelControlID. Identificador de un control situado dentro del cuadro de diálogo, que actuará como botón de cancelación. Esta labor corresponderá habitualmente a un control de tipo Button, pero podemos emplear otros tipos.
— OnOkScript. Código JavaScript que se ejecutará cuando el control asignado a la propiedad OkControlID desencadene su evento Click.
— OnCancelScript. Código JavaScript que se ejecutará cuando el control asignado a la propiedad CancelControlID desencadene su evento Click.
— DropShadow. Valor de tipo bool que permite mostrar una sombra alrededor del borde del cuadro de diálogo, para dotar a este de un efecto de resaltado.
— BackgroundCssClass. Nombre correspondiente a un estilo CSS, que será aplicado al resto de controles de la página Web no pertenecientes al cuadro de diálogo, y que permanecen deshabilitados mientras este último está en funcionamiento.
Según las propiedades que acabamos de mencionar en esta tabla, la configuración del ModalPopupExtender quedaría como muestra el siguiente fuente.
<cc1:ModalPopupExtender ID=»mpeSeleccion» runat=»server»
TargetControlID=»btnAsistente»
PopupControlID=»pnlSeleccionarDatos»
OkControlID=»btnAceptar»
CancelControlID=»btnCancelar»
OnOkScript=»mpeSeleccionOnOk()»
OnCancelScript=»mpeSeleccionOnCancel()»
DropShadow=»True»
BackgroundCssClass=»FondoAplicacion» />
Observemos que los controles para aceptar y cancelar el diálogo corresponden a los botones btnAceptar y btnCancelar incluidos en el Panel pnlSeleccionarDatos. La funcionalidad aportada por estos botones corresponde a las funciones JavaScript indicadas en las propiedades OnOkScript y OnCancelScript, que añadiremos en la cabecera de nuestra página aspx, y que vemos a continuación.
<script language=«javascript» type=«text/javascript»>
function mpeSeleccionOnOk()
{
var ddlCiudades = document.getElementById(«ddlCiudades»);
var ddlMeses = document.getElementById(«ddlMeses»);
var ddlAnualidades = document.getElementById(«ddlAnualidades»);
var txtSituacion = document.getElementById(«txtSituacion»);txtSituacion.value = ddlCiudades.options[ddlCiudades.selectedIndex].value + «, « +
ddlMeses.options[ddlMeses.selectedIndex].value + » de « +
ddlAnualidades.options[ddlAnualidades.selectedIndex].value;
}
function mpeSeleccionOnCancel()
{
var txtSituacion = document.getElementById(«txtSituacion»);
txtSituacion.value = «»;
txtSituacion.style.backgroundColor = «#FFFF99»;
}
</script>
Como ya habíamos comentado, al confirmar la caja de diálogo tomaremos los valores seleccionados en las listas desplegables, y los juntaremos para componer el valor a asignar al TextBox txtSituacion. Por otro lado, si cancelamos el diálogo, vaciaremos el cuadro de texto y le cambiaremos el color de fondo.
Respecto a la apariencia que presentarán los demás controles cuando abramos el cuadro de diálogo, tomarán las características del siguiente estilo que también añadiremos en la cabecera de la página, y utilizaremos desde la propiedad BackgroundCssClass del extensor.
<style type=»text/css»>
/* …. */
.FondoAplicacion
{
background-color: Gray;
filter: alpha(opacity=70);
opacity: 0.7;
}
</style>
No obstante, todavía queda un pequeño pero importante detalle que ajustar, ya que cuando ejecutamos la aplicación, justo al ser presentado el contenido de la página, el Panel del cuadro de diálogo se muestra por un instante para desaparecer a continuación, lo cual produce un desagradable efecto, que podemos corregir si aplicamos a este elemento el valor de estilo «display: none» para ocultarlo, como vemos seguidamente.
<asp:Panel ID=»pnlSeleccionarDatos» runat=»server» CssClass=»CajaDialogo» Style=»display: none;»>
Ahora ya podemos ejecutar la aplicación, en la que al hacer clic sobre el botón btnAsistente, el extensor ModalPopupExtender abrirá el Panel pnlSeleccionarDatos ofreciendo el aspecto de la siguiente figura.
Dado que al cancelar el cuadro de diálogo cambiamos el color de la caja de texto, como detalle complementario vamos a añadir una funcionalidad consistente en devolver a dicha caja su color original cuando vuelva a tomar el foco. Se trata de una operación que bien podíamos haber programado en el código aspx de la página, pero hemos optado por hacerlo en el code-behind a efectos de demostrar las capacidades de generación de código JavaScript de la clase Page.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// generar código JavaScript para asociar
// con el evento onfocus del textbox txtSituacion
System.Text.StringBuilder sbJS = new System.Text.StringBuilder();
sbJS.Append(«function txtSituacionOnFocus()»);
sbJS.Append(«{ n»);
sbJS.Append(» var txtSituacion = document.getElementById(‘txtSituacion’); n»);
sbJS.Append(» txtSituacion.style.backgroundColor = ‘#FFFFFF’; n»);
sbJS.Append(«}»);// registrar en la página el código JavaScript
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
«CodigoJS», sbJS.ToString(), true);// asociar el evento cliente con la función JavaScript para este control
this.txtSituacion.Attributes.Add(«onfocus», «txtSituacionOnFocus()»);
//….
}
}
Y con este detalle habríamos completado el ejemplo, cuyo código fuente se encuentra disponible en los siguientes enlaces para C# y VB.
Espero que os resulte de utilidad.
Un saludo.
lmblanco
Hola Enrique
Muchas gracias por leerlo, y me alegro que te haya gustado 8-DDDD
Un saludo.
Luismi
ifernandez
Gran articulo Luismi, sin duda otra referencia para los favs
Un abrazo
lmblanco
Hola Isaac
Muchas gracias por tu interés, campeón, espero que en algún momento te pueda resultar de ayuda 😎
Saludotes.
Luismi
anonymous
Hola,
La verdad es muy bueno… y es muy util, Felicidades!!!… pero te comento que lo hice y en el panel, adicione unas grillas, pero ya no funciona, no muestra nada… antes lo hacia llamando a otra ventana y funcionaba, pero ahora simplemente no aparece la ventana modal…
saludos,
Marcelo
lmblanco
Hola Marcelo
Gracias por leer el post y por tu opinión. Respecto al problema que comentas, hay que tener en cuenta que el control GridView contiene una «maquinaria» interna compleja, por lo que deberías revisar todos los controles que has añadido tanto a la ventana modal como a la página Web normal, por si estuvieran entrando en conflicto. Además de esto, también hay que tener en cuenta, que cuando utilizas el GridView, al moverte por sus páginas de datos, en cada cambio de página se va a producir un envío del formulario al servidor, y ello hará que se cierre la ventana modal en la que tienes el GridView. Una posible solución, sin hacer un análisis muy detallado del problema, podría consistir en abrir de nuevo la ventana modal al cargar el formulario, usando el método Show del ModalPopupExtender; comprobando, claro está, que la ventana modal necesita ser abierta para proseguir con el uso del GridView. Te adjunto un ejemplo en el que he añadido un GridView a un ModalPopupExtender y sí se visualiza al abrir la ventana modal. También hay que tener en cuenta que este ejemplo es muy básico, y tu problema puede requerir un examen más detallado para localizar la causa.
//====================================================================
< %@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="GridView1._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">
//——————————————————————–
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack)
{
this.mpeDialogo.Show();
}
}
}
//====================================================================
Espero que consigas localizar el problema.
Un saludo.
Luismi