El Blog de Óscar Sotorrío Sánchez - MCP Application Development Foundation - C#

Todo lo que vaya aprendiendo de .NET, C#, ASP.NET, SQL Server, etc, lo compartiré con vosotros.

El autor:

Óscar Sotorrío Sánchez
Contacto Send mail

Encuéntralo

Álguien dijo...


La humanidad partiendo de la nada, ha llegado a alcanzar las más altas cotas de miseria.

Groucho Marx

Acceder a las propiedades y controles de una MasterPage (II)

La forma recomendada por MSDN de acceder a las propiedades de una MasterPage es utilizando la directiva @MasterType. Al colocar esta directiva en nuestra página de contenido, obtenemos una referencia con establecimiento inflexible de tipos a nuestra MasterType.

<%@ MasterType VirtualPath="~/MasterPage.master" %> 

Esta directiva tiene dos posibles atributos que son mutuamente excluyentes, VitualPath y TypeName. Es decir, solo podemos utilizar uno de ellos al mismo tiempo. En el ejemplo anterior hacemos referencia a la MasterPage por medio de la ruta vitual. Pero también podríamos hacerlo con idénticos resultados por medio del atributo TypeName y especificando el nombre de la clase de nuestra MasterPage.

De esta forma ya estará a nuestra disposición la referencia a la MasterPage por medio de la propiedad Master de la página de contenido, como vimos en el ejemplo anterior. Por lo tanto podremos acceder a sus propiedades directamente o a sus controles por medio del método FinControl().

Otra forma de tener acceso a los controles de la MasterPage es creando una propiedad del tipo del control. Por ejemplo, para un control Label:

    public string TextoLabel
    {
        
get 
        
{
            
return Label1.Text;
        
}
        
set
        
{
            Label1.Text 
= value;
        
}
    }

    
public Label ControlLabel
    {
        
get 
        
{
            
return Label1;
        
}
        
set
        
{
            Label1 
= value;
        
}
    }

Como vemos podemos crear una propiedad haciendo referencia una propiedad concreta del control (en este caso Label1.Text) o directamente una propiedad del tipo de control para tener acceso a todas sus propiedades y métodos.

 


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on lunes, 28 de diciembre de 2009 15:04
Permalink | Comentarios (0) | Post RSSRSS comment feed

Acceder a las propiedades y controles de una ContentPage desde una MasterPage

Este caso se podría decir que es lo contrario de Acceder a las propiedades y controles de una MasterPage. Ahora queremos acceder a las propiedades y controles que tengamos declarados en nuestra página de contenido o Content Page (también content), desde la master que la contiene.

 

Acceso a los controles

En el código de la master, utilizando el método FindControl() del control de servidor ContentPlaceHolder encontraremos los controles a los que queremos tener acceso. No olvidemos que el control ContentPlaceHolder es el contenedor que contiene nuestra página de contenido.

 

            Label2.Text ((TextBox)ContentPlaceHolder1.FindControl("TextBox1")).Text;

 

Acceso a las propiedades

Para acceder a las propiedades de la página de contendido deberemos "kurrarnoslo" un poco más. En primer lugar declararemos una interfaz que implemente las firmas de las propiedades a las que queremos tener acceso. Por ejemplo:

            public interface miInterfaz
            {
                
string miPropiedad { get; set; }
            }

Esta interfaz deberá ser implementada por nuestra Content Page y por consiguiente también las propiedades que contenga la interfaz. Hecho esto, podremos acceder desde la Master Page a la propiedades implementadas en la content con un código como este:

 

        var miContent (miInterfaz)this.Page;

        if 
(miContent != null)
            Label1.Text 
miContent.miPropiedad;

 

Nota: Parte de este artículo ha sido escrito gracias a unos buenos compañeros de los foros.

 


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on lunes, 21 de diciembre de 2009 23:03
Permalink | Comentarios (0) | Post RSSRSS comment feed

Acceder a las propiedades y controles de una MasterPage (I)

Supongamos que tenemos una página principal o Master Page llamada miMasterPage. Esta master contendrá una propiedad pública implementada por nosotros y un control de tipo TextBox.

Para mayor claridad, de ahora en adelante, nos referiremos a las páginas que contiene una Master Page como Content Page. Ahora queremos acceder desde el Code Behind de una de las páginas content a las propiedades públicas y a los controles que contiene la master.

Lo primero que tenemos que hacer es instanciar un objeto de tipo miMasterPage por medio de la propiedad Master que contiene todas las páginas content.

        var miMaster (miMasterPage)this.Master;

De esta forma el objeto miMaster representa una instancia de nuestra Master Page y por lo tanto tendremos acceso directo a todas sus propiedades públicas y controles.

        Label1.Text miMaster.miPropiedad;
        
Label2.Text ((TextBox)miMaster.FindControl("TextBox1")).Text;

Para acceder a los controles deberemos utilizar el método FindControl(). Pero como vemos, una vez creada la instancia de nuestra Master Page la forma de acceder a las propiedades y controles es muy natural.

 

Ver también como Acceder a las propiedades y controles de una ContentPage desde una MasterPage


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on lunes, 21 de diciembre de 2009 21:33
Permalink | Comentarios (0) | Post RSSRSS comment feed

AJAX en ASP.NET 2.0 con Page Methods

En el artículo anterior de esta serie vimos la potencia y facilitdad que nos ofrece un control UpdatePanel combinado con un ScriptManager. Pero no es oro todo lo que reluce. ¿Que sucede si tenemos una página con muchos controles pero solo queremos actualizar por AJAX uno de ellos?.

Tenemos que tener en cuenta que cuando utilizamos un UpdatePanel estamos enviando al servidor todo el HTML de la página. Es decir, no solo estamos enviando el contenido del UpdatePanel, enviamos también todos los controles que encuentran fuera. Y esto aumenta mucho el tráfico hacia el servidor. Además, en el servidor se disparan todos los eventos del ciclo de vida de la página y de todos los controles que contenga. Lo que recarga las funciones realizadas por el servidor.

Eso si, el servidor gracias al UpdatePanel y a las librerías cliente que nos ofrece el ScriptManager, solo envía el HTML necesario para actualizar los controles que se encuentren dentro del UpdatePanel.

Estas consideraciones debemos tenerlas en cuenta si estamos implementado AJAX en una página muy pesada con mucho controles. La implementación de los métodos de página o Page Methods nos ofrece la posibilidad de tener más control sobre la forma de actualizar la página a cambio de perder un poco de automatización.

 

 

 

Código Cliente

Lo primero que tenemos que hacer es habilitar la funcionalidad de los métodos de página en el control ScriptManager por medio de la propiedad EnablePageMethods.

    <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
        
<Scripts>
            
<asp:ScriptReference Path="funcionesPageMethods.js" />
        </
Scripts>
    
</asp:ScriptManager> 

Por otro lado, hemos añadido una referencia al archivo JavaScript que contendrá las funciones necesarias para el envío y recogida de datos de forma asíncrona. Este es el código.

//Funcion que llama al método de la página de forma asíncrona.
function EnviarDatos() {

    
//$get('') == document.getElementById('')
    
var nombreSeleccionado $get("listaNombres").value;
    
    
//Llamada al metodo de la página.
    
PageMethods.ObtenerDatos(nombreSeleccionado, RecogerRespuesta, RecogerErrores);
}


//Funcion que recoge los datos desde el servidor.
function RecogerRespuesta(datosRecibidos)
{
    $
get("txRespuesta").innerText datosRecibidos;
}


//Función que recoge los posibles errores.
function RecogerErrores(error) {

    
alert("Error: " + error.get_message());
}

Ya estamos acostumbrados a este tipo de implementación, una función para enviar los datos asíncronos, otra para recogerlos y una función para recoger los errores que se produzcan durante la llamada. Lo único que merece la pena resaltar es esta linea.

 PageMethods.ObtenerDatos(nombreSeleccionado, RecogerRespuesta, RecogerErrores);

 

La clase PageMethods intrínseca de la librería ASP.NET AJAX nos permite llamar a la función ObetenerDatos() que es un método estático que se encuentra en nuestra página.

 

Código Servidor

En el código de servidor solo tendremos que implementar el método que se encarga de recoger los datos desde el cliente y enviarlos asíncronamente una vez manipulados de vuelta al cliente. 

    [System.Web.Services.WebMethod]
    
public static string ObtenerDatos(string nombreSelec)
    {
        
//Antes de enviar la petición simulamos una tarea larga.
        
System.Threading.Thread.Sleep(5000);
        
        return 
ManejarDatos.ObtenerCategoria(nombreSelec, rutaDatos);
    
}

Como vemos este método tiene que ser static y estar decorado con el atributo System.Web.Services.WebMethod.

 

Código de descarga 

El código completo mencionado en este artículo se encuentra en la carpeta AJAX_NET_3.5/Retro_Llamdas/AJAX_PageMethods del siquiente enlace. Para probar la aplicación ejecutar la página AJAX_PageMethods.aspx de la carpeta mencionada.

 

AJAX_ASP.NET.rar (15,45 kb)


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on sábado, 12 de diciembre de 2009 11:56
Permalink | Comentarios (0) | Post RSSRSS comment feed

Enviar datos asíncronos a un control fuera de un UpdatePanel

Es posible que a muchos este título les suene a chino, y quizás también, no sea un caso que se de muy a menudo. Pero opino que es una característica que debemos conocer para tener más control sobre las aplicaciones ASP.NET AJAX.

 

El problema

Comenzemos plantenado el problema. Cuando utilizamos AJAX Extensions en una aplicación ASP.NET sabemos que en la respuesta asíncrona del servidor solo se envía de vuelta al cliente web una porción muy pequeña de HTML. Exactamente, solo se envía el HTML necesario para actualizar los controles que se encuentran dentro de un UpdatePanel, es lo que se conoce como repintado parcial. ¿Pero que ocurre si queremos, en algunas ocasiones, actualizar un control que se encuentra fuera de un UpdatePanel?. Es decir, ¿como podemos decirle al servidor que envíe otros datos además del HTML del repintado parcial?.

Veámoslo con un pequeño ejemplo.

    <div>
        
<asp:TextBox ID="TextBox1" runat="server">
            
</asp:TextBox><asp:Button ID="Button1" runat="server" Text="Button" 
            onclick
="Button1_Click" />
        <
br />
        <
br />
    
<!-----------Sección que se actualiza por AJAX (repintado parcial)--------------->
        
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
            
<ContentTemplate>
                
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
            
</ContentTemplate>
            
<Triggers><asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" /></Triggers>
        
</asp:UpdatePanel>
    
<!-------------------------------------------------------------------------------->    
        
<br />
        <
br />
        <
asp:Label ID="Label2" runat="server" Text="Label"></asp:Label>
    
</div>

 

¿Que tenemos aquí?. Tenemos un TextBox donde el usuario introducirá su nombre y tenemos dos Labels que mostrarán un saludo al usuario cuando hagan Click sobre el Button. Como podemos observar uno de los Labels se encuentra dentro de un UpdatePanel y el otro fuera. El que esta dentro se aprovechará de la funcionalidad de AJAX para actualizar su contendido de manera asíncrona.

Añadamos código para manejar el evento del Button y veamos que sucede.

 

        protected void Button1_Click(object sender, EventArgs e)
        {
            
string datosEnviados "Hola " + TextBox1.Text;

            
Label1.Text datosEnviados;
            
Label2.Text datosEnviados;
        
}

 

Al ejecutarse el evento vemos que solo se actualiza el Label1. El Label2 no se entera de nada. ¿Porque?.

Ya lo hemos comentado ante. El servidor solo está enviando al cliente el HTML necesario para actualizar los controles que se encuentran dentro del UpdatePanel.Repito la pregunta, ¿como podemos decirle al servidor que envíe otros datos además del HTML del repintado parcial?.

 

La solución

Cambiamos el código del evento del Button por el siguiente:

            string datosEnviados "Hola " + TextBox1.Text;
            
Label1.Text datosEnviados;

            
ScriptManager1.RegisterDataItem(Label2, datosEnviados);

El método RegisterDataItem() del ScriptManager envía datos en una llamanda asíncrona a los controles que se encuentran fuera del UpdatePanel. Ahora debemos manegar el siguiente evento en el cliente.

    <script type="text/javascript" language="javascript">
        Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(RecogerDatosHandler)
;

        function 
RecogerDatosHandler(sender, args) {
            
var datos args.get_dataItems();
            
$get("Label2").innerHTML datos["Label2"];
        
}
    </script>

En primer lugar obtenemos una instancia de la clase Sys.WebFroms.PageRequestManager que es la encargada de actualizar los controles que se encuentran dentro del UpdatePanel. Antes de que esta actualización ocurra, gestionamos el evento pageLoading() y recogemos los datos enviados desde el servidor para actualizar el Label2.

Hemos creado nuestro propio manejador del evento, RecogerDatosHandler(), que por medio del la colección args podemos acceder a los datos enviados desde el servidor.

Nota: La definición del script cliente anterior debe colocarse después de la definición del controls ScriptManager, de lo contrario nos dará un error diciendo que el espacio de nombres Sys no está definico aún, ¡como es lógico!.

 


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on martes, 08 de diciembre de 2009 17:48
Permalink | Comentarios (0) | Post RSSRSS comment feed

GridView: acceder a los valores de las columnas no visibles

Cuando intentamos acceder al valor de una celda, de una columna marcada en el GridView como no visible, nos encotramos ante un problema. Dado que, normalmente las columnas marchadas como no visibles, suelen almacenar datos nada importantes para el usuario (id, codigos, valores ocultos, etc) pero si de suma importancia para el funcionamiento interno de nuestra aplicación.

Por lo tanto, lógicamente el siguiente intento no nos devolverá nada porque la columna no visible no ha sido "pintada".

string id gvEmpleados.Rows[e.RowIndex].Cells[celdaId].Text;

Para resolver este pequeño problema debemos utilizar las propiedades DataKayNames y Datakeys del GridView. Veamos un ejemplo.

Tenemos el siguiente XML que deseamos mostrar por pantalla al usuario por medio de una rejilla como GridView.

<?xml version="1.0" encoding="utf-8"?>
<empleados>
    
<empleado id="1" idEmpresa="034/9435" Nombre="Pedro" Telefono="985945452" Pais="Mexico" />
    <
empleado id="2" idEmpresa="035/3245" Nombre="Antonio" Telefono="887404730" Pais="Perú" />
    <
empleado id="3" idEmpresa="078/4324" Nombre="Jorge" Telefono="9149858353" Pais="España" />
    <
empleado id="4" idEmpresa="045/3243" Nombre="Elena" Telefono="893737581" Pais="Argentina" />
    <
empleado id="5" idEmpresa="074/5425" Nombre="Raquel" Telefono="9984573423" Pais="España" />
</
empleados> 

Nuestro GridView tendrá la siguiente definición de código HTML en nuestra página.

 

<asp:GridView ID="gvEmpleados" runat="server" AutoGenerateColumns="False" 
            DataSourceID
="XmlDataSourceEmpleados" DataKeyNames="id,idEmpresa" 
            onrowdeleting
="gvEmpleados_RowDeleting" 
            onselectedindexchanging
="gvEmpleados_SelectedIndexChanging">
            
<Columns>
                
<asp:CommandField ShowSelectButton="True" />
                <
asp:BoundField DataField="id" HeaderText="id" SortExpression="id" 
                    Visible
="False" />
                <
asp:BoundField DataField="idEmpresa" HeaderText="idEmpresa" 
                    SortExpression
="idEmpresa" Visible="False" />
                <
asp:BoundField DataField="Nombre" HeaderText="Nombre" 
                    SortExpression
="Nombre" />
                <
asp:BoundField DataField="Telefono" HeaderText="Telefono" 
                    SortExpression
="Telefono" />
                <
asp:BoundField DataField="Pais" HeaderText="Pais" SortExpression="Pais" />
                <
asp:CommandField ShowDeleteButton="True" />
            </
Columns>
        
</asp:GridView>
        
<asp:XmlDataSource ID="XmlDataSourceEmpleados" runat="server" 
            DataFile
="~/App_Data/empleados.xml"></asp:XmlDataSource>
He marcado en negrita y un poco más grande las columnas no visibles al usuario. También podemos ver la propiedad DataKeyNames. Esta propiedad permite establecer (también recuperar) una colección de columnas que serán tratadas como claves primarias del origen de datos.
 
Ahora solo nos queda desde código acceder a estos valores cuando el usuario dispare cualquiera de los eventos del GridView. Ya sea para actualizar, eliminar, seleccionar, etc una fila. Un par de ejemplos:
 
 
    protected void gvEmpleados_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
    {
        var colsNoVisible 
gvEmpleados.DataKeys[e.NewSelectedIndex].Values;
        string 
id (string)colsNoVisible[0];
        string 
idEmpresa (string)colsNoVisible[1];
    
}
    
protected void gvEmpleados_RowDeleting(object sender, GridViewDeleteEventArgs e)
    {
        var colsNoVisible 
gvEmpleados.DataKeys[e.RowIndex].Values;
        string 
id (string) colsNoVisible[0];
        string 
idEmpresa (string) colsNoVisible[1];
    
}

La propiedad DataKeys nos permite acceder a las columnas que son tratadas como claves primarias en el origen de datos. De esta forma nosotros podemos trabajar por debajo con registros únicos como ids y mostrar al usuario solo la información que le interesa.

 


Posted by Oscar.SS on domingo, 06 de diciembre de 2009 15:26
Permalink | Comentarios (0) | Post RSSRSS comment feed

AJAX en ASP.NET 2.0 con AJAX Extensions

Quizás aquí algunos esperaban erroneamente que el título hablara de ASP.NET 3.5 pero como ya he comentado alguna vez (creo!!), las versiones de ASP.NET saltan de la 2.0 a la 4.0. No así las versiones de la plataforma .NET que si han seguido un camino más continuado 2.0, 3.0, 3.5, y 4.0.

Por lo tanto, este árticulos y los siguientes tratarán de lo que se puede hacer con AJAX en ASP.NET 2.0 con el framework 3.0 o 3.5. Por otra parte, igualmente válido son para aquellos que trabajan con ASP.NET 2.0 sobre .NET 2.0 y tienes instaladas las plantillas AJAX Extensions. (Ver gráfico evolución plataforma)

 

 

Código Cliente

En este caso el código cliente se redece a incluir un control ScriptManager y un control UdatePanel dentro del cuerpo de la página.

    <form id="form1" runat="server">
    
<asp:ScriptManager ID="ScriptManager1" runat="server">
    
</asp:ScriptManager>
    
<div>
        
<p style="text-align:center; font-size:xx-large; color:Blue; text-decoration:underline">AJAX con AJAX Extensions</p>
        
<span>Seleccionar un nombre:</span>
        
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" 
            onselectedindexchanged
="DropDownList1_SelectedIndexChanged">
            
<asp:ListItem Selected="True">Oscar</asp:ListItem>
            
<asp:ListItem>David</asp:ListItem>
            
<asp:ListItem>Diego</asp:ListItem>
            
<asp:ListItem>Sergio</asp:ListItem>
            
<asp:ListItem>Luis</asp:ListItem>
        
</asp:DropDownList>
        
<br />
        <
br />
        <
asp:UpdatePanel ID="UpdatePanel1" runat="server">
            
<ContentTemplate>
                Categoria profesional:  
<asp:Label ID="Label1" runat="server" ForeColor="Red"></asp:Label>
            
</ContentTemplate>
            
<Triggers><asp:AsyncPostBackTrigger ControlID="DropDownList1" 
                    EventName
="SelectedIndexChanged" /></Triggers>
        
</asp:UpdatePanel>
        
<br />
        <
br />
        <
span>Mientras se ejecuata la petición de datos escribir aquí para comprobar el AJAX.</span>
        
<input id="Text1" type="text" />
    </
div>
    
</form>


El control ScriptManager es el encargado de registrar en el cliente todo el código script necesario para soportar AJAX.  Debe aparecer antes que ningún otro control en la página.

En el control UpdatePanel, dentro de <ContentTamplate>, incluiremos únicamente el contenido HTML que deba ser actualizado cuando el servidor devuelva los datos. Este control se encarga de enviar desde el servior solo la porción de HTML que contiene, realizando lo que se denomina un repintado parcial de la página. Dentro de <Triggers> se declaran los controles y eventos que disparan este repintado parcial.

¡Y ya esta!. No hay que hacer nada más. No hay que escribir ni una linea de código cliente, entre el control ScriptManager y el UpdatePanel, se encargar de envíar los datos al servidor y de recibirlos mostrandolos al usuario.

 

Código Servidor

Y en el servidor no tenemos que hacer nada especial para manipular la funcionalidad AJAX. Simplemente incluiremos el código necesario dentro del evento del control que hemos declarado anteriormente dentro de <Triggers> en el UpdatePanel.

    protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
    {
        
string rutaDatos Server.MapPath("~/App_Data/datos.xml");

        string 
nombreSelec DropDownList1.SelectedValue;

        
//Antes de enviar la petición simulamos una tarea larga.
        
System.Threading.Thread.Sleep(5000);

        
Label1.Text ManejarDatos.ObtenerCategoria(nombreSelec, rutaDatos);
    
} 


Código de descarga 

El código completo mencionado en este artículo se encuentra en la carpeta AJAX_NET_3.5/AJAX_Extensions del siquiente enlace. Para probar la aplicación ejecutar la página AJAX_Extensions.aspx de la carpeta mencionada.

AJAX_ASP.NET.rar (15,45 kb)


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on sábado, 14 de noviembre de 2009 13:03
Permalink | Comentarios (0) | Post RSSRSS comment feed

AJAX en ASP.NET 2.0 con Script CallBacks

Con la llegada de ASP.NET 2.0 se puso a nuestra disposición otra técnica para realizar llamadas en segundo plano desde el cliente. Esta técnica es denominada Script CallBacks. La ventaja más notable de esta forma de implementar AJAX es que nos evita tener que escribir tanto código cliente. En concreto, nos evita tener que escribir todo el código JavaScript para crear, configurar y enviar los datos al servidor con XMLHTTPRequest, tal y como vimos en el post anterior. Naturalmente si tendremos que utilizar código cliente para manipular los datos una vez devueltos por el servidor.

Comencemos recordando la interfaz de usuario que teníamos en el ejemplo anterior.

  

 

Código Servidor

Antes de nada, debemos saber que la técnica de Script CallBacks se apoya en la interfaz ICallbackEventHandler. Por lo tanto debemos implementar esta interfaz en la página que recibe la llamada asíncrona. Más tarde veremos cuales son los métodos de esta interfaz.

Ya hemos comentado antes que no necesitamos escribir todo el JavaScript a mano para enviar los datos asíncronamente al servidor. Pero entoces...¿como enviamos los datos?. En realidad, desde el cliente si llamaremos e inviaremos los datos al servidor pero todo esto lo configuraremos desde el propio servidor. Veamos como.

         this.listaNombres.Attributes["onchange"ObtenerFuncionCliente();

En primer lugar, asignamos al evento onchange de la lista de nombres una cadena que será devuelta por la función ObtenerFuncionCliente(). Esta cadena contiene el nombre de una función JavaScript proporcionada por ASP.NET. Esta función cliente será la encargada de realizar la llamada asíncrona y de enviar los datos al servidor. La función toma la forma siguiente:

 

WebForm_DoCallback("Control", "DatosEnviados", "FuncionRecogerDatos", "idLlamada", "FuncionRecogerErrores", "Asíncrono")

 

  • Control (string). Nombre del control que implementa la interfaz ICallbackEventHandler.
  • DatosEnviados (string). Cadena con los datos enviados desde el cliente al servidor.
  • FuncionRecogerDatos (string). Nombre de la función cliente que será la encargada de recoger y manipular debidamente los datos recibidos desde el servidor.
  • idLlamada (string). Parámetro opcional, un identificador único de esta llamada. Sirve para diferenciarla de otras llamadas en contextos de llamadas múltiples. Puede ser null.
  • FuncionRecogerErrores (string). Nombre de la función cliente encargada de recoger y manipular los errores producidos.
  • Asíncrono (bool). Determina si la llamada será realizada de forma asíncrona o no.
Pero como ya hemos comentado, esta función de JavaScript y todos sus parámetros serán configurados con código servidor.
  
    private string ObtenerFuncionCliente()
    {
        
//Obtener los parámetros de la función cliente.
        
var control = this;

        string 
datoRecibido = string.Format("document.getElementById('{0}').value"this.listaNombres.ClientID);
        
        string 
FuncionCliente "RecogerRespuestaCallBack";

        string 
idLlamada "null";

        string 
FuncionClienteError "MostrarError";

        bool 
llamadaAsincrona = true;

        
//Configurar la función cliente con los parámetros anteriores.
        
string funcionConfigurada Page.ClientScript.GetCallbackEventReference(
            control, datoRecibido, FuncionCliente, idLlamada, FuncionClienteError, llamadaAsincrona)
;

        
//Devolvemos la instrución JavaScript con el nombre de la función que realiza la llamada.
        
return string.Format("javascript:{0}", funcionConfigurada);
    
}

El método GetCallbackEventReferecen() devuelve una referencia a la función cliente WebForm_DoCallback() que hemos comentado antes. Entendamos lo que hemos hecho hasta ahora.

En la primera petición a nuestra página, esta devolverá entre todo el código HTML un fragmento de JavaScript con la función WebForm_DoCallback() y todos sus parámetros. Esta función sera la encargada de enviar los datos al servidor cuando se produzca el evento onchange.

 

La interfaz ICallbackEventHandler implementa únicamente dos métodos: 

  • RaiseCallbackEnvent(). Esta función será llamada automaticamente cuando se reciba una llamada en segundo plano desde el cliente.
  • GetCallbackResult(). Devuelve una cadena con los datos y llama automaticamente a la función JavaScript encargada de recoger los datos en el cliente.

    public void RaiseCallbackEvent(string datosCliente)
    {
        datoRecibido 
datosCliente;
    
}

    
public string GetCallbackResult()
    {
        
string rutaDatos Server.MapPath("~/App_Data/datos.xml");

        
//Antes de enviar la petición simulamos una tarea larga.
        
System.Threading.Thread.Sleep(5000);

        return 
ManejarDatos.ObtenerRespuesta(datoRecibido, rutaDatos);
    
}

Código Ciente
Poco queda por decir. Ahora solo tendremos que implementar las dos funciones Java Script que especificamos al configurar los parámetros del método GetCallbackEventReferecen(). Una función para recoger y mostrar los datos al usuario y otra para el control de los posibles errores que se produzcan.
//Funcion que es llamada automaticamente para procesar la respuesta del servidor.
function RecogerRespuestaCallBack(xmlReturn, idLlamada) {
    
try {
       
//CargarXmlString() parsea una cadena en un documento XML.
        
var datosReturn CargarXmlString(xmlReturn).getElementsByTagName("categoria");
        
var resp document.getElementById("txRespuesta");
        
resp.innerText datosReturn[0].childNodes[0].nodeValue;
    
}
    
catch (ex) {
        MostrarError(ex)
;
    
}

}


//Funcion llamada automaticamente cuando se produce un error.
function MostrarError(ex) {
    alert(
"Error: " + ex);
}

 

Código de descarga 

El código completo mencionado en este artículo se encuentra en la carpeta AJAX_NET_2.0 del siquiente enlace. Para probar la aplicación ejecutar la página AJAX_ScriptCallBacks.aspx de la carpeta mencionada.

AJAX_ASP.NET.rar (15,45 kb)


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on viernes, 23 de octubre de 2009 22:14
Permalink | Comentarios (2) | Post RSSRSS comment feed

AJAX en ASP.NET 1.0 con XMLHTTPRequest

Este es el primero de una serie de artículos que escribiré sobre la implementación de un mismo ejemplo de AJAX en las diferentes versiones del framework.

Cuando veamos el ejemplo de AJAX con .NET Framework 3.5, podremos observar que todo esta muy encapsulado y aunque es muy intuitivo y productivo nos aleja bastante de lo que ocurre "por debajo".

Esto tiene dos consecuencias negativas, que tenemos menos control y que los programadores noveles, que comienzan sus primeros pasos directamente en la ultima versión de la plataforma no comprenden como funcionan conjuntamente estas tecnologías. Precisamente este es el motivo que impulsa esta serie de artículos.

¡Comencemos ya!. En primer lugar veamos la interfaz de usuario y expliquemos que pretendemos hacer. Recuerdo que el ejemplo será el mismo en todos los artículos de la serie pero implementados de forma diferente.

 


La aplicación es muy simple. El usuario selecciona un nombre de empleado y se devuelve por AJAX la categoría profesional del mismo. Estos datos están guardados en el servidor en un archivo XML. En el servidor, se ha relentizado la devolución de los datos para simular una tarea muy larga a la hora de obtener los datos.
 
El campo de texto inferior solo sirve para comprobar como a pesar de que se esta realizando una petición al servidor, el usuario puede seguir interactuando con la IU escribiendo al tiempo que los datos vuelven desde el servidor.
 
 
Código Cliente
El código cliente consiste en crear un objeto de tipo XMLHTTPRequest, configurarlo y enviar los datos al servidor. También implementaremos una función para recoger los datos devueltos por el servidor y mostrar el resultado. Mencionar que este código, al ser solo JavaScript, es compatible con cualquier plataforma, ya sea PHP, Java o .NET como en este caso.
Esta es la función que envía los datos al servidor.
function EnviarPeticion(datoEnviado) {

    
//Crear transmisor
    
try {
        transmisor 
= new ActiveXObject('Msxml2.XMLHTTP');
    
}
    
catch (ex1) {
        
try {
            transmisor 
= new ActiveXObject('Microsoft.XMLHTTP')//Inferior a IE7.
        
}
        
catch (ex2) {
            
try {
                transmisor 
= new XMLHttpRequest()//IE7, Mozilla FireFox, etc.
            
}
            
catch (ex3) {
                transmisor 
= false;
            
}
        }
    }

    
//Configurar el transmisor y enviar los datos.
    
if (transmisor != null) {
        transmisor.onreadystatechange 
RecogerRespuesta;

        
//Envio de datos con POST.
        
transmisor.open("POST""AJAX_XMLHTTPRequest.aspx"true);
        
transmisor.setRequestHeader("Content-Type""application/x-www-form-urlencoded");
        
transmisor.send("opcion=" + datoEnviado);  // param1=valor&param2=valor
    
}
}

En primer lugar creamos un objeto transmisor de tipo XMLHTTPRequest que nos permitirá comunicarnos con el servidor. Este objeto tiene diferentes implementaciones dependiendo del tipo de navegador cliente.

A continuación configuramos el transmisor para enviar los datos. La propiedad onreadystatechange determina cual será la función a la que se llamará automaticamente cuando los datos estén de vuelta desde el servidor.

La función open() abre la conexión con los siguientes parámetros, todos de tipo cadena menos un boleano:

  • POST/GET: método de envío del protocolo HTTP.
  • Página de servidor a la que se envía la petición. Es recomendable que esta página no contenga código HTML. Solo la declaración de la directiva @Page.
  • True/False (bool): Realizar una llamada asíncrona (true) o una llamada no asíncrona (false).
  • Usuario: Nombre de usuario. Este parámetro y el siguiente solo es necesario para páginas con autentificación de usuarios.
  • Contraseña: Contraseña del usuario. Opcional.
La función setRequestHeader() solamente es necesario si estamos enviando la petición por el método POST. Se encarga de especificar los atributos necesarios en la cabecera de la petición HTTP.
La función send() envía los datos al servidor en formato cadena. La cadena formada debe tener la forma param1=valor&param2=valor&param3=valor etc.
Con esto hemos realizado una llamada asíncrona hacia el servidor. Allí, lo veremos a continuación, se recogerá los datos enviados por el cliente, se manipularan debidamente y de devolverán al cliente. Concretamente a la función cliente especificada en la propiedad onreadystatechange.
function RecogerRespuesta() {
    
if (transmisor.readyState == 4)    // 4 = completado
    
{
        
if (transmisor.status == 200)    // 200 = OK
        
{
            
var datosReturn transmisor.responseXML.getElementsByTagName("categoria");
            var 
resp = document.getElementById("txRespuesta");
            
resp.innerText datosReturn[0].childNodes[0].nodeValue;
        
}
        
else //En caso de error
        
{
            
alert("Error: " + transmisor.status + " / " + transmisor.statusText);
        
}
    }
}

Primero comprobamos que la petición a finalizado con la propiedad readyState y a continuación comprobamos que no se han producido errores con la propiedad status.

Con la propiedad responseXML recogemos los datos como un documento XML dado que así han sido enviados desde el servidor. También pueden ser recogidos como una cadena con la propiedad responseText en el caso de que solo se enviará desde el servidor una cadena.

Accedemos al nodo que nos interesa del documento XML con la función getElementByTagName() y utilizando el DOM lo mostramos por pantalla.

 

Código Servidor 

El código cliente consiste básicamente en recoger los datos con el objeto Request, leer el archivo XML y buscar en el dato requerido. Construir luego un XML con el dato requerido y devolverlo al cliente con el método Response.Write().

Este es un ejemplo del código que se ejecutará en el evento Load() de la página.

        //Recogemos el dato enviado desde el cliente.
        
string datoRecibido Request.Params["opcion"];

        
// Se devuelve como XML.
        
Response.ContentType "text/xml";
        
// Evitar que haya caché.
        
Response.AppendHeader("cache-control""no-cache");
        
Response.Expires -1;

        
//Antes de enviar la petición simulamos una tarea larga.
        
System.Threading.Thread.Sleep(5000);

        
//Enviamos y cerramos la respuesta.
        
Response.Write(ManejarDatos.ObtenerRespuesta(datoRecibido, rutaDatos));
        
Response.End();

No hay mucho que comentar. Indicar que ManejarDatos es una clase con métodos estáticos que encapsula toda la funcionalidad para recuperar el dato requerido desde el XML en el servidor y con este dato construir el XML  que será devuelto al cliente.

 

Código de descarga 

El código completo mencionado en este artículo se encuentra en la carpeta AJAX_NET_1.x del siquiente enlace. Para probar la aplicación ejecutar la página index.htm de la carpeta mencionada.

AJAX_ASP.NET.rar (15,45 kb)


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on domingo, 18 de octubre de 2009 15:51
Permalink | Comentarios (2) | Post RSSRSS comment feed

Cuidado con los eventos onmouseover y onmouseout

Los eventos de JavaScript onmouseover y onmouseout son muy caprichosos y dependiendo del explorador que utilicemos para ver la página, se comportarán de una forma o de otra.

Para comprender mejor como se comportan estos eventos he realizado un sencillo ejemplo de menú despleglable típico de JavaScript. Podéis ver el ejemplo aquí.

Os aconsejo que dediquéis unos segundos en ver el código fuente del ejemplo. Como pedéis apreciar, la página esta dividida principalmente en 3 elementos <div> que resumo a continuación.

 

- id="interfaz", es el bloque principal que se muestra al usuario.

- id="MenuError", es el menú desplegable que no funciona correctamente (ahora veremos porqué).

- id="MenuOK", es el menú desplegable que funciona correctamente.

 

En la página del ejemplo hay dos iconos como este  . El icono de la izquierda mostrará el menú que funciona y el icono de la derecha mostrará el que no funciona correctamente.

Antes de explicar porque no funciona el menú del icono de la derecha, vamos a ver que acciones hemos realizado para darle la funcionabilidad esperada.

 

1- Hemos marcado con position:absolute tanto el objeto interfaz como el objeto MenuError.

2- También hemos marcado al objeto MenuError con display:none. Para que de forma predeterminada no se muestre el menú desplegable.

3- En el evento onmouseover de la imagen del icono de la derecha hemos llamado a la función MostrarMenu(id). Esta función lo único que hace es cambiar el atributo display para que se muestre el menú y darle una posición donde mostrarse.

4- En el evento onmouseout del objeto MenuError hemos llamado a la función OcultarMenu(). Con la intención de que si salimos con el ratón del area del menú, este debería ocultarse.

 

Bien, con esto todo debería funcionar correctamente. Si colocamos el ratón sobre el icono de la derecha estamos llamando a MostrarMenu(id) y el menú se muestra. Y cuando salimos del area del menú, estamos llamando a OculatarMenu() y el menú debería ocultarse.

Ahora dirijase a la página del ejemplo y coloque el ratón sobre el icono de la derecha he intente hacer click sobre una de las opciones del menú. ¿Que ocurre?. El menú se oculta cuando el ratón se coloca sobre el area del menú, o al menos, eso parece. ¿Porque?.

Lo que sucede es que cuando "paseamos" el ratón por el menú para llegar hacer click por ejemplo en la opción 1, estamos entrando y saliendo en varios objetos. Estos objetos son hijos del menú, o mejor dicho, del objeto padre <div> "MenuError".

Cuando salimos por ejemplo del primer <tr>, automaticamente se dispara al evento onmouseout del padre, y por lo tanto se llama a la función OcultarMenu(). Este es el comportamiento caprichoso al que me refería al principio y al parecer es el comportamiento predeterminado en el DOM.

¿Como solucionarlo?.

 

5- En el evento onmouseover del objeto MenuOK hemos llamado a la función MostarMenu(id).

 

Logicamente si cuando entro en un objeto hijo también se llama al evento onmouseover del padre, puedo aprovecharme de ello, llamando a MostrarMenu(id). De esta forma, después de todo el paseo de entrar y salir de los distintos objetos hijos (tr, td, img, etc), me aseguro que la última acción realizada será entrar en el elemento que contiene la opción 1 (o la opción 2) y por lo tanto estaremos disparando el evento onmouseover del padre que llama a MostrarMenu(id).

Comprobar que en el menú que se despliega con el icono de la izquierda podéis hacer click sobre las opciones del menú. Fijaros que la única diferencia en el código con este menú y el que no funciona es haber incluido onmouseover="MostarMenu('MenuOK');" en el objeto <div>.


Tags:
Categories: Desarrollo Web
Posted by Oscar.SS on sábado, 15 de agosto de 2009 1:11
Permalink | Comentarios (0) | Post RSSRSS comment feed