ModalPopupExtender. Creando cajas de diálogo en ASP.NET mediante AJAX

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” />
&nbsp;&nbsp;
<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.


 

Sin categoría

91 thoughts on “ModalPopupExtender. Creando cajas de diálogo en ASP.NET mediante AJAX

  1. Hola Isaac

    Muchas gracias por tu interés, campeón, espero que en algún momento te pueda resultar de ayuda 😎

    Saludotes.
    Luismi

  2. 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

  3. 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">


    pruebas con gridview



















    //——————————————————————–
    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

  • Excelente el articulo. Pero tengo un problema que no he encontrado como solucionarlo, lo que pasa es que yo deseo que desde el ModalPopupExtender cuando presione el boton OK, me realice la funcion de guardado en una base de datos SQL con los datos del formulario que se encuentra en el ModalPopupExtender.

    Me podrias colaborar.

    Gracias de antemano

  • Hola Juan Pablo

    Gracias por leer el artículo y por tu opinión 😎

    Respecto al problema que mencionas, si necesitas acceder a una base de datos desde ajax para poder realizar algún tipo de operación sobre los registros de una tabla (consulta, alta, baja o modificación), el modo de resolverlo es mediante un servicio de tipo asmx o wcf.

    En primer lugar debes crear en tu proyecto un servicio, por ejemplo de tipo WCF, y escribir en él los métodos de acceso a la base de datos.

    A continuación, dentro del WebForm que contiene el código ajax que deseas comunicar con el origen de datos, añade al ScriptManager una referencia al servicio de la siguiente forma:





    Seguidamente, en el bloque de código javascript del WebForm, escribe un método que será el encargado de llamar al método(s) necesario(s) del servicio, algo parecido a lo siguiente:

    Y a grandes rasgos, estos serían los pasos principales a realizar. Ya que se trata de un requerimiento bastante habitual, quería preparar un post para el blog basado en este tipo de funcionalidades, dado que es un tema que puede resultar interesante. Espero poder publicarlo en los próximos días/semanas.

    Un saludo.
    Luismi

  • Hola, me parece buenisimo tu ejemplo, sabes yo tengo un inconveniente, al utilizar el modal dentro de una pagina q hereda de un masterpage, el detalle es q se posiciona en la parte superior izquierda, saben xq podria ser?? …
    saludos

    daniel lt

  • Hola Luis. No puedo más que felicitarte por tu excelente artículo. Me ha sacado muchas dudas, y me ha resultado bastante útil.
    El problema es que estoy haciendo un proyecto muy similar, pero cuando se ejecuta el código JavaScript correspondiente a los eventos del botón OK y Cancelar del formulario, no se actualizan los controles en el sitio.

    Es decir, tengo este código en el evento que se dispara al apretar el botón Aceptar:
    function mpeSeleccionOnOk()
    {
    var CajaTexto=document.getElementById(“txtProveedor”);
    var CajaTexto2=document.getElementById(“txtOwner”);

    CajaTexto.Value=CajaTexto2.Value;

    }

    Se ejecuta (porque si modifico algo intencionalmente obtengo un error). Pero la caja de texto llamada txtProveedor no cambia su valor para nada.
    ¿Qué me está faltando?
    Saludos y muchas gracias

  • Pido perdón por lo anterior, encontré el problema. Yo ponía el código Javascript fuera del formulario (

    ) y por eso no funcionaba.

    Ahora tengo otro problema. En lugar de usar un combo yo uso un Listbox para que el usuario seleccione una opción ¿como paso la selección del ListBox a una caja de texto en la función Javascript del botón OK?

    Gracias y un gran saludo

  • Hola Franco

    Gracias por tu interés en el artículo y me alegra que te haya sido de ayuda 😎

    Celebro que resolvieras el primer problema que comentabas, respecto a tu otra duda en la manipulación del ListBox desde Javascript, el modo de selección en el ListBox es también utilizando su colección options. Supongamos que en el ejemplo del artículo, utilizamos dentro del panel que usaremos como diálogo un ListBox:

    //———————————————————


    //———————————————————

    Ahora pasamos al código Javascript que se ejecutará al pulsar el botón ok del cuadro de diálogo, y utilizamos de forma combinada las propiedades options y selectedIndex del ListBox como vemos a continuación, para obtener el elemento seleccionado:

    //———————————————————

    //———————————————————

    Espero que te sirva para solucionar el problema.

    Un saludo.
    Luismi

  • Hola excelente articulo, una pregunta no se porq cuando activo mi Popup la barra de desplazamiento esta activa pero no funciona, es decir no veo todo el contenido de lo q contiene mi panel.
    no se si es un problema de version del ajax??

    Saludos.

  • exelente el articulo….pero tengo un problema tengo una aplicacion un boton carga el model con un gridview 2 cajas de texo y un boton, en mi gridview hay una columna de tipo templateField con un input tipo boton que cada vez que le doy aceptar mediando un javascript carga algunos datos del grid a las caja de texto .El problema es que cada vex que le pulso el boton del grid se cierra el modelPoput…..de ante mano se agradece la solucion .
    Salu2….

  • Hola Marcos

    Gracias por leer el artículo.

    Acabo de probar a añadir al ejemplo una barra de desplazamiento vertical sobre el panel que funciona como caja de diálogo, utilizando la propiedad ScrollBars del control Panel, de la siguiente forma:

    y al ejecutar la aplicación y abrir el ModalPopupExtender, la barra de desplazamiento está activa y me funciona correctamente, desplazando el contenido del panel al moverla.

    Es posible que sea alguna cuestión relacionada con las versiones. Actualmente estoy utilizando Visual Studio 2008 con el SP1 instalado para .NET Framework y Visual Studio. También utilizo el Ajax Control Toolkit para .NET Framework SP1.

    Un saludo.
    Luismi

  • Hola Martín

    Gracias por leer el artículo, y en cuanto al problema que mencionas es necesario tener presente que el control GridView, como ya comenté en otra respuesta a este mismo post, es un control complejo, y la interacción con el mismo puede producir el envío del formulario al servidor con el consiguiente cierre del ModalPopupExtender.

    Intenta revisar el diseño de la funcionalidad que proporcionas en el ModalPopupExtender, situando si es posible, las operaciones que realizas al pulsar uno de los botones de la columna del grid fuera de dicho grid, en un único botón.

    Un saludo.
    Luismi

  • Está muy interesante el contenido, pero quisiera saber, como seria una ventana modal, con un gridview, es decir, con solo seleccionar un registro de la grilla, me pase el valor en la caja de texto, en este caso txtsituacion

  • Hola Pepe

    Gracias por leer el post, y respecto a tu pregunta, puedes configurar el control GridView para que mediante la propiedad AutoGenerateSelectButton se muestre para cada fila un link que te permita seleccionar dicha fila, de forma que posteriormente en el evento SelectedIndexChanged, obtengas la fila seleccionada y extraigas el valor que necesites de la celda. El código de marcado necesario sería similar al siguiente:

    //—————————————-

    pruebas con gridview



















    //—————————————-

    En cuanto al codebehind, el evento a manejar sería el siguiente.

    //—————————————-
    protected void GridView2_SelectedIndexChanged(object sender, EventArgs e)
    {
    this.txtSituacion.Text = this.GridView2.SelectedRow.Cells[2].Text;
    this.mpeDialogo.Hide();
    }
    //—————————————-

    Espero que este ejemplo te sirva.

    Un saludo.
    Luismi