domingo, 26 de septiembre de 2010

Linq: Usar operadores de Linq en lugar de un foreach

Éste es un caso en el que quería llenar un DropDownList utilizando el CascadingDropDown. En el método del WebService, quise usar el método AddRange, y así evitar tener que implementar un foreach para iterar por la colección de filas de un DataTable.

Por ejemplo, tengo un método que se llama Clientes.Listar(), el cual devuelve la lista de filas en un objeto DataTable, entonces para llenar al DropDownList tengo que usar un foreach para recuperar el valor que se va a mostrar en el DropDown y el valor llave que se utilizaría para saber cuál item se seleccionó. Utilizando el método AddRange del tipo List y las técnicas de Linq, tenemos el siguiente código de ejemplo:

--------------------
List valores = new List();
Clientes clientes = new Clientes();

valores.AddRange
(
    from fila in clientes.Listar().AsEnumerable()
    select new CascadingDropDownNameValue(fila["NOMBRE"].ToString(), fila["CODIGO"].ToString())
);
return values.ToArray();

--------------------
Otra alternativa de Linq pero expresada en secuencia de operadores de Linq sería de la siguiente forma:

--------------------
values.AddRange(clientes.Listar().AsEnumerable().Select(
fila => new CascadingDropDownNameValue
(
    fila["NOMBRE"].ToString(),
    fila["CODIGO"].ToString()
)));
--------------------

Cualquiera de los dos casos anteriores sirven para reemplazar el siguiente código:

foreach (DataRow fila in clientes.Listar().Rows)
{
     values.Add(new CascadingDropDownNameValue(fila["NOMBRE"].ToString(),   
     fila["CODIGO"].ToString()));
}

La diferencia, entre éste foreach y el uso de Linq es que Linq me permite hacer muchas cosas en una sola línea de código, en el peor de los casos tengo que agregar otras líneas, pero con las técnicas tradicionales, en lo personal, el código se vuelve para mí muy tedioso y en ocasiones dificil de entender.

Algunos dicen que Linq es más rápido, otros dicen que no siempre es el más rápido, independientemente de la eficiencia con que resuelva Linq el problema, prefiero Linq porque me permite codificar mejor casos difíciles donde tengo que dar tratamiento a por ejemplo muchos campos de una tabla o muchos datos de un arreglo, etc.

domingo, 12 de septiembre de 2010

Asp.Net: Valor enviado desde servidor no se actualiza con Javascript

Existe un caso especial en el que deseamos actualizar un valor, por ejemplo un contador de filas de un GridView, el cual está dentro de un UpdatePanel. Para actualizar el valor, se decide registrar una variable dinámica la cual se asocia al objeto window.document, quedando en la página del cliente de la siguiente forma:

<script type="text/javascript">//<![CDATA[
document.TotalRows='5';//]]>
</script>


Para registrar una variable al objeto document de Javascript desde el Code-Behind con C#, se hace de la siguiente forma:

if (!ClientScript.IsClientScriptBlockRegistered("total"))
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "total",
"document.TotalDeFilas ='" + gridView.Rows.Count + "';", true);

En el caso que estaba resolviendo, el código anterior lo coloqué en el evento Page_Load() de una página *.aspx.

Ahora bien, cada vez que un usuario agregue un registro nuevo o elimine un registro, el valor debe cambiar en la página. Si utilizamos la siguiente línea de código, nos daremos cuenta que no va a funcionar, aunque la línea de código éste buena:

ClientScript.RegisterClientScriptBlock(this.GetType(), "total", "document.TotalDeFilas ='" + gridView.Rows.Count.ToString() + "';", true);

¿Por qué no se actualiza el valor en la página después de por ejemplo eliminar un registro?

Muy simple (aunque me tomo como tres horas darme cuenta, jaja!), eso ocurre porque el GridView está dentro del UpdatePanel. Entonces para solucionarlo; es decir, para actualizar el valor, hay que usar el objeto ScriptManager en lugar del objeto ClientScriptManager. La línea de código sería entonces:

ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "total", "document.TotalDeFilas ='" + GridView.Rows.Count + "';", true);

Lo que vale la pena tener en mente es que si uno desea actualizar valores de objetos que están dentro de un UpdatePanel usando javascript, lo mejor es usar ScriptManager en el CodeBehind.