Controles Windows en Web(c#)
[2º Parte]

Fecha: 11/Sep/2003 (14/Sep/2003)
Autor: Unai Zorrilla Castro   
Escríbeme

 
.

En esta segunda parte intentaremos completar más cosas sobre la técnica de embeber controles Windows en Web. En mi anterior colaboración he explicado como crear un control simple y como introducirlo en el iexplorer para ser ejecutado por el cliente de esa web. En esta colaboración trataré de explicaros como inicializar nuestros controles mediante tag de Html, lo que facilitará la reusabilidad de los controles, puesto que podemos adaptar el controles a cada web sin necesidad de volver a cambiar código y volver a compilarlo. Aprenderemos también, y esto me parece lo más interesante, como generar eventos y que estos sean capturados desde la web mediante scripts (jscript o vbscript) lo que nos facilitará muchísimo la sincronización del control con otras acciones propias de la web que necesitemos realizar.

Primeramente creamos un control web, tal y como explicamos en la anterior colaboración. una vez creado y asignado el nombre que deseemos a nuestro control creamos un atributo nuevo que en mi caso le llamaré ParamPasado y que será de tipo string.

private string pasado;
public string ParamPasado
{
    get{ return pasado;}

    set{this.pasado = value ;}
}

Con esto ya hemos creado el atributo que vamos a inicializar, ahora veremos como inicializarlo desde un tag de Html. Como sabéis usábamos object para incluir el control en la web, pues bien entre el inicio y el cierre incluimos lo siguiente

<param name="ParamPasado" value="esto es el parametro pasado en el tag param">

Bien! con esto ya podemos inicializar los controles y que tal y como comente antes nos facilitará mucho la reutilización de los controles en diversas webs. Vamos entonces con el plato fuerte, tomarlo con calma eh!!. Nuestra tarea es conseguir que un evento soltado por nuestro control sea capturado por un script de una página web, Buff! por lo menos eso fue lo que dije yo cuando me vi en la situación de tener que crear un control que necesitaba sincronizarse con una página en Html. Bueno después de leer bastante de la SDK de .NET Framework y diversas consultas, entre ellas al Guille y a Erich Bühler (www.vblibros.com), la solución que he encontrado es exponer el control windows como un objeto COM declarando los eventos y miembros públicos del control y definiendo la interface adecuada. Para ello necesitaba, como sabréis los que tengáis algo de idea de COM es un identificador único para eso objeto, esto no es problema puesto que Visual Studio nos proporciona esta utilidad, para crear uno podéis ejecutar guidgen en el símbolo del sistema que biene con el Visual Studio, o directamente en el Visual Studio dirigiéndonos a Herramientas -> Crear Guid, nos saldrá algo como esto:

Seleccionamos la opción 4 y hacemos click en Copy, ¿ fácil no ? Bueno pues con esto hemos creado un identificador "único" en en mundo que servirá para identificar a nuestro objeto. Bueno ya tememos nuestro guid, guardarlo en un documento de texto para usarlo más tarde ok?

Para crear un evento primero necesitamos crear un delegado y después asociar al evento este delegado, que básicamente es un puntero a una función. El código para crear el evento es el siguiente.

public delegate void TerminarHandler();
public event TerminarHandler Terminado;

Ahora que hemos visto como crear el Guid del control y como crear un evento estamos en disposición de crear definitivamente el control. Escribimos el código y después pasamos a comentarlo.

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace controltest2
{
/// 
/// Descripción breve de UserControl1.
/// 
[ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(IQCDCOMEvents))]
public class micontrol2 : System.Windows.Forms.UserControl,IQCDCOMIncoming // esto no aparece en el código pero lo pongo para explicar alguna cosa 
{
private System.Windows.Forms.Button bt1;
/// 
/// Variable del diseñador requerida.
/// 
private System.ComponentModel.Container components = null;
public delegate void FinHandler();
public event FinHandler OnFin;
private string pasado;
public string ParamPasado
{
get{return this.pasado;}
set{this.pasado = value;}
}
public micontrol2()
{
// Llamada requerida por el Diseñador de formularios Windows.Forms.
InitializeComponent();
// TODO: agregar cualquier inicialización después de llamar a InitForm
}
/// 
/// Limpiar los recursos que se estén utilizando.
/// 
protected override void Dispose( bool disposing )
{
if( disposing )
{
if( components != null )
components.Dispose();
}
base.Dispose( disposing );
}
#region Component Designer generated code
///  
/// Método necesario para admitir el Diseñador, no se puede modificar 
/// el contenido del método con el editor de código.
/// 
private void InitializeComponent()
{
this.bt1 = new System.Windows.Forms.Button();
this.SuspendLayout();
// 
// bt1
// 
this.bt1.Location = new System.Drawing.Point(24, 64);
this.bt1.Name = "bt1";
this.bt1.TabIndex = 0;
this.bt1.Text = "Aceptar";
this.bt1.Click += new System.EventHandler(this.bt1_Click);
// 
// micontrol2
// 
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.bt1});
this.Name = "micontrol2";
this.ResumeLayout(false);
}
#endregion
private void bt1_Click(object sender, System.EventArgs e)
{
bt1.BackColor = System.Drawing.Color.Blue;
bt1.Text = ParamPasado.ToString();
//Lanzamos el evento, si es lanzado y no se implementa saltará una excepcion por lo que para algo serio se debería cachear
OnFin();
}
}
#region exponemos los eventos
[Guid("2BA61129-37D3-4b84-BA47-020F7493A5A3")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IQCDCOMEvents
{
[DispId(0x60020000)]
void OnFin();
}
//
//Necesitamos declarar aqui lo publico de la clase, por lo de el rollo de la especificacion de COM
public interface IQCDCOMIncoming
{
string ParamPasado{get;set;}
}
#endregion
}

Explicación del código.

Como se puede ver se necesita incluir el espacio de nombres System.Runtime.InteropServices para exponer el control como COM. Usamos ClassInterface para especificar que deseamos exponer el control como COM, se le pasa como parámetro la interface IQCDCOMEvents para decirle cuales son los eventos que pueden ser tratados en la Web. La clase del control se puede derivar de IQCDCOMIncoming para que así mismo podamos decirle que atributos o métodos pueden ser llamados desde jscript o vbscritp, esto no lo he hecho en el control pero bueno aquí lo explico. Una vez creado esto fuera del cierre de la clase se crear las interface que he mencionado y aquí es donde se usa lo que habíamos aprendido del GUID, para la interface IQCDCOMEvents, si se crean varios eventos a tratar deben tener un identificador distinto dentro del control, en este caso solo necesitamos que sean distintos dentro del objeto yo uso 0x60020000 y para los siguientes eventos pues 0x600200001 etc ...

Fijaros como se declara ParamPasado en IQCDCOMIncoming, ¡ Cuidado los atributos como ParamPasado o métodos que deseemos que sean tratados deben declararse como public dentro de la clases, esto es importante.!!

Bueno espero que esto os sirva de utilidad, y que aprovechéis toda la potencia de .NET. Se que a muchos no os parecerá muy claro lo de exponer el objeto como COM y tampoco tengo mucho para rebatir aunque bueno esto funciona o sea que.......

 

Código de ejemplo (unaiWebControl2parte.zip - 21.2 KB)
Ejemplo para incluir en el "localhost": unaiWebControl2parteWwwroot.zip 3.42 KB


ir al índice