En respuesta a la consulta de Julitogtu generada en los foros de MSDN, he generado un ejemplo práctico de su consulta. Ya que le aconsejé la utilización de controles de usuarios generados dinámicamente en detrimento de los famosos iframes.
Pero esta generación se complica especialmente si quieres cargar estos controles con llamadas asíncronas, por el hecho de que estos controles se generan en el servidor.
Lo primero que tenemos que hacer es tener los controles de usuario bien organizados para poderlos utilizar desde el cliente con llamadas a métodos de Página o servicios web, de esta manera evitaremos todo el tráfico que genera los updatePanels.
Yo he generado tres controles de usuarios distintos para probar diferentes posibilidades que nos podemos encontrar en la vida real.
-
Un formulario: Encontraremos los típicos controles asp.net para introducir los datos de un formulario.
-
Login: Dentro de este control tendremos otro ASP.NET para la creación de usuarios registrados.
-
Grid: Control de usuarios donde mostraremos los datos de una base de datos con un GridView.
Después en la página principal de la aplicación tendremos un TreeView para seleccionar los controles a cargar y un div donde se mostrara la información.
Cargaremos la lista manualmente y le indicaremos a los nodos que en cuanto se selecciones ejecuten el método de página que devolverá el control de usuario en formato texto, para esto solo le pasaremos el nombre de la función y el identificador del control que queremos cargar en el enlace.
[sourcecode language=»csharp»]
private void CargarDatos()
{
Dictionary<string,string> controles =
new Dictionary<string,string>();
controles.Add("FormControl", "Datos de contacto");
controles.Add("GridControl", "Lista de Productos");
controles.Add("LoginControl", "Iniciar sesión");
foreach (KeyValuePair<string, string> value in controles)
{
TreeNode node = new TreeNode();
node.Text = value.Value;
node.NavigateUrl = "BLOCKED SCRIPTPageMethods.CargarControl(
‘" + value.Key +"’, CargarControlOK, CargarControlKO);";
TreeView1.Nodes.Add(node);
}
}
[/sourcecode]
Código de servidor:
La página contará de un Método de Página que se encargara de cargar el control de Usuario y transformara el control en el resultado HTML que es el que se devolverá al cliente para que se añada al div y muestre el control en el navegador.
[sourcecode language=»csharp»]
[WebMethod]
public static string CargarControl(string tipoControl)
{
StringWriter stringWriter = new StringWriter();
Page page = new Page();
System.Web.UI.HtmlControls.HtmlForm form =
new System.Web.UI.HtmlControls.HtmlForm();
form.ID = "__t";
page.Controls.Add(form);
switch (tipoControl)
{
case "FormControl":
{
UserControls_Form cForm =
(UserControls_Form)page.LoadControl(
"~/UserControls/FormControl.ascx");
form.Controls.Add(cForm);
HttpContext.Current.Server.Execute(page, stringWriter, false);
break;
}
case "GridControl":
{
UserControls_Grid cGrid =
(UserControls_Grid)page.LoadControl(
"~/UserControls/GridControl.ascx");
cGrid.Inicializar("Condiments");
form.Controls.Add(cGrid);
HttpContext.Current.Server.Execute(page, stringWriter, false);
break;
}
case "LoginControl":
{
UserControls_Login cLog =
(UserControls_Login)page.LoadControl(
"~/UserControls/LoginControl.ascx");
form.Controls.Add(cLog);
HttpContext.Current.Server.Execute(page, stringWriter, false);
break;
}
}
//Limpiamos el formulario ASP
string html=(stringWriter != null)?stringWriter.ToString():"<h2>Sin Datos</h2>";
html = html.Substring(html.IndexOf("<div>"));
html = html.Substring(0, html.IndexOf("</form>"));
return html;
}
[/sourcecode]
Al utilizar Métodos de Página o Servicios web no existe el estado y tenemos que generar una página ASP.NET y ejecutarla para que se generen los controles y poder mostrar su resultado HTML. Esta idea esta extraída del fenomenal artículo de Scott Guthrie: Ajax views. Pero uno de los inconvenientes que nos encontramos con esta técnica es que obtenemos el formulario completo, por ese motivo hay que limpiar el HTML y eliminar el rastro del formulario.
Otra cosa que tenemos que tener en cuenta es que podemos controlar en que momento tenemos que cargar los datos en el control, yo en este caso he generado una función que se encarga de inicializar y cargar los datos filtrados directamente con un objeto SQLDataSource.
[sourcecode language=»csharp»]
public void Inicializar(string Categoria)
{
SqlDataSource1.SelectParameters.Add("CategoryName", Categoria);
SqlDataSource1.SelectCommand =
@"SELECT [ProductID], [ProductName], [CategoryName]";
FROM [Alphabetical list of products]
WHERE ([CategoryName] = @CategoryName)
GridView1.DataSourceID = "SqlDataSource1";
GridView1.DataBind();
}
[/sourcecode]
Código Cliente:
Tendremos dos funciones, una para recoger el resultado y cargar el div “utilizando JQuery” y el otro mostraremos un mensaje en el caso que ocurra un error.
[sourcecode language=»javascript»]
function CargarControlOK( resultado ){
if ($(".divBase").length)
$(".divBase")[0].innerHTML = resultado;
}
function CargarControlKO(resultado){
alert("Error al cargar el menú: " + resultado._message)
}
[/sourcecode]
Resultado:
El resultado obtenido en esta práctica, es que al seleccionar un nodo del treeView se genera una llamada asíncrona que no carga todo la página y carga en un div el control de usuario que se especifica en la llamada, de esta manera podemos reutilizar toda la funcionalidad que nos aportan estos controles.
Podéis pasar el código de una página aspx de una forma muy sencilla a un control de usuario sin tener que repicar todo el código Cómo: Convertir páginas de formularios Web Forms en controles de usuario ASP.NET.
Espero que esta información sea de utilidad.