miércoles, 5 de noviembre de 2008

Vamos a revitalizar este blog!!!

Buenas!!!

Hace mucho que tenía abandonado este blog...

La verdad es que no tengo mucho tiempo y que, además, los blogs de Blogspot no son el mejor sitio para escribir código, ya que no tienen un editor en condiciones...

Bueno, como he dicho voy a intentar revitalizar este blog. En principio seguiré aquí, pero la idea que tengo es la de moverlo todo a un nuevo blog personalizado... en cuanto tenga tiempo!!

Ahora mismo creo que lo importante es que sepáis que mi compañero y subgurim y yo hemos empezado una aventurilla en la que también se han embarcado tres amig@s más... Os iré contando cómo van las cosas, pero tiene todo muy buena pinta...

Antes de acabar quería decir que pongáis un enlace comunactivo para mi amigo Subgurim!!!

Sed buen@s y... nos vemos pronto!!

martes, 9 de octubre de 2007

Responder a eventos de CheckBox dentro de controles ASP.NET

Al hilo del comentario de Alex en el artículo anterior, explicaré cómo podemos hacer lo mismo que se explicaba en dicho artículo, si nuestro botón pasa a ser un CheckBox.
La verdad, no conocía la respuesta... Pero ahora ya sí!

Si necesitamos que un GridView contenga un CheckBox y que se realice una acción cada vez que éste se seleccione o se deseleccione, sencillamente tendremos que crear un método que responda a dicha acción y asociar el CheckBox a dicho método.
Por ejemplo:

<asp:TemplateField HeaderText="Total">
<ItemTemplate>
<asp:CheckBox Id="CheckBox1" runat="server" OnCheckedChanged="CheckBox1_CheckedChanged1" AutoPostBack="true"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>


El .cs asociado tendría un método:

protected void CheckBox1_CheckedChanged1(object sender, EventArgs e)
{
//Código asociado
}


Pero, de esta forma no podemos acceder a las propiedades de la fila en la que nos encontramos.

Para ello, tendríamos que añadir unas cositas en el código asociado al CheckBox, de forma que podamos saber en qué fila nos encotramos y, una vez hecho esto, poder acceder a una de las columnas.
El código que habría que incluir en dicho método sería:

protected void CheckBox1_CheckedChanged1(object sender, EventArgs e)
{
CheckBox checkbox = (CheckBox)sender;
GridViewRow row = (GridViewRow)checkbox.NamingContainer;
//Todo lo que queramos hacer aquí
}


Como vemos, lo primero que hacemos es obtener el CheckBox que ha invocado al método.
Una vez lo hemos hecho, podemos conocer el contenedor de dicho objeto, con lo que conoceríamos la fila del GridView que contiene el CheckBox que ha sido seleccionado/deseleccionado y, con ella, todos los valores de sus columnas.

Pero este método no sólo sirve para CheckBoxes. En realidad sirve para cualquier control, por ejemplo un Button.
Es decir, podemos hacer lo mismo que explicamos en el artículo anterior de esta forma.
Lo que tendríamos que hacer es añadir el evento "OnClick" al Button y asociarle el método correspondiente (por ejemplo "Button1_Click") y en dicho método, poner el mismo código que arriba, pero referente a un Button:

protected void button1_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
GridViewRow row = (GridViewRow)button.NamingContainer;
//Código que queramos
}


Espero que os sirva de ayuda!

Saludos!

jueves, 6 de septiembre de 2007

Responder a eventos de botones dentro de controles ASP.NET

En ocasiones necesitamos que en la plantilla de un elemento de un control haya un botón con alguna funcionalidad.

Podemos pensar que esto es tan sencillo como introducir el botón en dicha plantilla en el lugar que queremos y asignarle un evento en su propiedad OnClick. En algunas ocasiones puede serlo (así de fácil), pero en otras podemos necesitar algunas funcionalidades adicionales que no tendríamos de esta forma, o al menos no las tendríamos de forma sencilla.

Por ejemplo, imaginaos que tenemos un gridview con varias columnas, una de las cuales el un entero que va de 1 a 10. Imaginad que queremos introducir un botón que nos permita modificar dicho entero de forma que se le reste 1 a la cantidad que haya en ese momento en dicha fila, siempre que esta sea mayor a 1.
Pues bien, en este caso tendríamos que acceder a un valor de una columna dentro de una fila del GridView. Y claro, cómo accedemos al valor de la fila en la que está el botón en cuestión... Y si no podemos acceder a la fila, ¿cómo accedemos a la columna?

Ya no parece tan fácil, verdad? Pues nada más lejos de la realidad.
Lo que tenemos que hacer es capturar el evento del botón en el método RowCommand y, una vez en él, actuar en función del botón que hemos pulsado.

Pero, ¿cómo sabemos qué botón hemos pulsado? No os preocupéis, esto es bastante sencillo. Sólo tenemos que fijar la propiedad CommandName del botón y luego acceder a ella para saber qué botón se ha pulsado...
Es un poco lioso de explicar y tal vez no haya quedado muy claro, así que pongamos un ejemplo.

Este ejemplo es el mismo con el que se explica esto en el MSDN de Microsoft y lo podéis encontrar aquí.

Aquí teneís los pasos:
  1. Insertemos un botón en el GridView con la propiedad CommandName="boton".
  2. Creamos el método RowCommand del gridview. En dicho método haremos lo siguiente:
    1. comprobar la propiedad CommandName para saber el botón que ha generado el evento
    2. realizar las acciones necesarias
Por ejemplo:
protected void GridView1_RowCommand(object source,
GridViewCommandEventArgs e)
{
if (e.CommandName == "boton")
{
// Aquí añadimos el código en respuesta al click en el botón
}
}
Como véis es bastante sencillo responder a los eventos de un botón que insertamos dentro de un ItemTemplate de un control. Fijaos que de esta forma estamos ejecutando un método al que hemos pasado un argumento del tipo GridViewCommandEventArgs, a partir del cual podemos acceder a las características y propiedades que necesitamos del gridview, como la fila que contiene el botón que ha generado el evento.

Por lo tanto, de esta forma, a diferencia que con el evento OnClick, podemos acceder a todo la información que podemos necesitar.

Espero que esto os sirva de ayuda.

Saludos!

sábado, 1 de septiembre de 2007

Empezando 1.0

Hoy empiezo este nuevo blog.

Al final he decidido separarlo del primero para tener uno que se centrase en ASP.NET exclusivamente.
Espero que encontréis por aquí cosas interesantes y que os ayuden.

Muchas gracias y un saludo!!

lunes, 27 de agosto de 2007

Dar formato a la fecha en un GridView: DataFormatString y HtmlEncode...

A veces nos podemos encontrar con que necesitamos que el formato en que se muestra una fecha en un GridView sea el que nosotros queramos.
Esto se puede solucionar de forma sencilla. Simplemente tenemos que establecer la propiedad DataFormatString al formato de fecha que queremos que se muestre.
Por ejemplo, si queremos que sólo se muestren el día, el mes y el año de una fecha, tendríamos que establecer dicha propiedad a:
dataformatstring="{0:MM/dd/yyyy}"
Sencillo, no? Pues con eso no es suficiente!
Comom podéis leer en este post del blog de Peter Kellner, para que el formato se aplique de verdad en la columna del GridView, tenemos que modificar el valor por defecto de otra propiedad del campo del GridView en cuestión. Esta propiedad es htmlencode y el valor al que la tenemos que poner es a "false". Es decir:
htmlencode="false"
¿Y para que sirve la propiedad "HtmlEncode"? Pues evita los ataques del tipo "cross-site scripting" y que se muestre contenido malicioso. Por eso Microsoft recomienda que siempre que se pueda se encuentre a "true".

Si es así, está claro, no? Bueno, la explicación sencilla viene ahora. Según nos explica muy bien Peter Keller, es que esta si esta propiedad se encuentra activa, no se puede pasar información al campo enlazado (boundfield) del control.
Ahora sí, no?

En fin, el código final de la columna del GridView será:
<asp :BoundField DataField=“Fecha”
DataFormatString=“{0:M-dd-yyyy}”
HeaderText=“Fecha” />
Cómo podéis ver es sencillo.
Sólo por mencionarlo, Peter Keller nos da otra solución, que es hacer que la columna sea una plantilla (con una etiqueta o un campo de texto) y establecer el formato directamente sobre dicha etiqueta o campo de texto.
En su post podéis encontrar un ejemplo.

Como siempre espero que os haya servido de ayuda.

Un saludo!

domingo, 26 de agosto de 2007

El Gridview y la Paginación

Cuando trabajamos con un gridview, una de las opciones con la que nos encontramos es permitir la paginación, es decir, que los resultados no se muestren todos seguidos, sino que se muestren en diferentes páginas. El número de páginas, dependerán del número de resultados que se muestren (mejor dicho, que le eigamos que muestre) por cada una de las páginas.

Hasta aquí podemos decir que la teoría es muy bonita y todo funciona muy bien, siempre que no queramos hacer nada que se salga un poco de lo normal... Siempre que consideremos que enlazar un gridview con un dataset o con una lista enlazada creada por nosotros se salga un poco de lo normal...

Bueno, el caso es que, cuando trabajamos con un data source de los que nos proporciona el framework de ASP.NET, como por ejemplo un ObjectDataSource, no encontramos ningún problema con la paginación, ya que simplemente tenemos que configurar un par de opciones (que el gridview permita paginación y el número de entradas que queremos que se muestren por cada página) para que todo se ajuste a lo que queremos.

Pero... y si no enlazamos con uno de los data sources que proporciona ASP.NET?? Pues bien, si, por ejemplo enlazamos el gridview con una lista enlazada o un dataset creado por nosotros, al activar la paginación nos encontraremos con un pequeño problema. Y es que, al hacer click sobre una página diferente a la que nos encontramos, obtendremos un error. Algo así:
El GridView "nombre_del_GridView" ha generado el evento PageIndexChanging, que no estaba controlado.
¿Y esto por qué? Pues bien, sencillamente porque a paginacion del control GridView viene asociado o esta intrinsecamente asociado al control proveedor de datos que se lo esta vinculando el datasource debe soportar ICollection. Aquí tenéis la explicación sobre la paginación del GridView.
Bueno, y entonces, ¿cómo lo solucionamos? Pues bien sencillo. Lo único que hay que hacer es incluir en nuestro código un método asociado al evento PageIndexChanging. De esta forma ya no nos aparecerá el error. Para que la funcionalidad sea la que queremos, pues sólo tenemos que incluir un código como este:

protected void GridView2_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView2.PageIndex = e.NewPageIndex;
List lista = obtenerLista;
GridView2.DataSource = llista;
GridView2.DataBind();
}


NOTA: en el ejemplo véis que he incluido un método para obtener la lista que luego se enlazará al GridView. Aquí hay que obtener el datasource que queramos para el GridView.

Y ya está! Así de sencillo.
Espero que os haya servido de algo.

Un saludo!

viernes, 24 de agosto de 2007

RequiredFielValidator, Buttons y ValidationGroup

Esta mañana me he encontrado con un pequeño obstáculo en la programación de mi proyecto. Como considero que es interesante que la gente lo sepa, pues aquí os lo dejo, por si alguna vez os hace falta.
Primero os pongo en situación...

En un control de usuario, necesitaba insertar unos controles de validación de ASP.NET. Concretamente, necesitaba el control RequiredFieldValidator. Como supongo que sabéis, este control evalúa el valor de un control de entrada en una aplicación ASP.NET para asegurarnos que tiene algún valor. De esta forma evitamos errores en la introducción de valores.
Este control forma parte de un grupo de controles de validación que nos permiten no sólo evitar que un control de entrada se deje vacío, sino además podemos hacer que sigan ciertas normas.

El caso es que en el control había diferentes popups cada uno con su texto de entrada y sus botones asociados para introducir los datos o cancelar la introducción. La verdad es que es un tema un poco difícil de explicar, así que propondré un escenario parecido pero más sencillo.

Imaginad que estamos programando una web en la que, entre otras cosas, tenemos que poder introducir nuevos productos que luego podremos vender. Asimismo, tenemos que poder introducir algún tipo de clasificación. Concretamente, tenemos una página de la web en la que podemos crear nuevos tipos y subtipos de productos. Simplificando al máximo, el código sería el siguiente:

<h3>Nuevo Tipo</h3>

<asp:label id="tipoLabel" runat="server" text="Introducir nuevo tipo:"></asp:label>
<asp:textbox id="tipoTextBox" runat="server"></asp:textbox>

<asp:button id="introducirTipoButton" runat="server" text="Introducir" >
</asp:button>

<h3>Nuevo Subtipo</h3>

<asp:label id="subtipoLabel" runat="server" text="Introducir nuevo subtipo:"></asp:label>
<asp:textbox id="subtipoTextBox" runat="server"></asp:textbox>
<asp:button id="introducirSubtipoButton" runat="server" text="Introducir" validationgroup="subtipoValidation">
</asp:button>


A este código le añadimos dos controles de validación del tipo RequiredFielValidator para evitar que un usuario "despistado" pueda darle a cualquiera de los botones e introducir una clase o subclase vacías. El código resultante será:
<h3>Nuevo Tipo</h3>

<asp:label id="tipoLabel" runat="server" text="Introducir nuevo tipo:"></asp:label>
<asp:textbox id="tipoTextBox" runat="server"></asp:textbox>
<asp:RequiredFieldValidator ID="tipoRequiredFieldValidator"
runat="server"
ErrorMessage="Escribe algo!!"
ControlToValidate="tipoTextBox"/
<
<asp:button id="introducirTipoButton" runat="server" text="Introducir" validationgroup="tipoValidation">
</asp:button>

<h3>Nuevo Subtipo</h3>

<asp:label id="subtipoLabel" runat="server" text="Introducir nuevo subtipo:"></asp:label>
<asp:textbox id="subtipoTextBox" runat="server"></asp:textbox>
<asp:button id="introducirSubtipoButton" runat="server" text="Introducir" >
</asp:button>
<asp:RequiredFieldValidator ID="subtipoRequiredFieldValidator"
runat="server"
ErrorMessage="Aquí también tienes que escribir algo!!"
ControlToValidate="subtipoTextBox" /
>

Parece que todo está correcto, ¿verdad? Pues bien, probadlo y veréis como no es así.
El problema reside en que los controles de validación están esperando una señal para comprobar si el usuario ha rellenado o no el textbox correspondiente. Como los dos botones causan validación (es el comportamiento por defecto) en cuanto apretamos uno de ellos, pues los controles de validación comprueban si hemos escrito algo en los controles que ellos controlan, valga la redundancia, de forma que apretemos el que apretemos siempre saldrán los mensajes de comprobación.
La solución que se creó para esto es bien sencilla. Podemos asociar los controles (el Button y el RequiredFielValidator) a un grupo de validación mediante la propiedad ValidationGroup. De esta forma, el Button sólo enviará la señal a aquellos controles que formen parte del mismo grupo de validación.
El código quedaría así:
<h3>Nuevo Tipo</h3>

<asp:label id="tipoLabel" runat="server" text="Introducir nuevo tipo:"></asp:label>
<asp:textbox id="tipoTextBox" runat="server"></asp:textbox>
<asp:RequiredFieldValidator ID="tipoRequiredFieldValidator"
runat="server"
ErrorMessage="Escribe algo!!"
ControlToValidate="tipoTextBox"
ValidationGroup="tipoValidation" /
<
<asp:button id="introducirTipoButton" runat="server" text="Introducir" validationgroup="tipoValidation">
</asp:button>

<h3>Nuevo Subtipo</h3>

<asp:label id="subtipoLabel" runat="server" text="Introducir nuevo subtipo:"></asp:label>
<asp:textbox id="subtipoTextBox" runat="server"></asp:textbox>
<asp:button id="introducirSubtipoButton" runat="server" text="Introducir" validationgroup="subtipoValidation">
</asp:button>
<asp:RequiredFieldValidator ID="subtipoRequiredFieldValidator"
runat="server"
ErrorMessage="Aquí también tienes que escribir algo!!"
ControlToValidate="subtipoTextBox"
ValidationGroup="subtipoValidation" /
>
Sencillo, ¿verdad? Una vez se conoce la solución, sí que es sencillo. Por si os sirve de algo, la solución la encontre en este post de los foros de ASP.NET.

¿Le ponemos la guinda al pastel?
Imaginad que todo esto lo tengáis en un popup y queráis poner un botón que cancele la introducción y cierre el popup. Independientemente del código asociado, al introducir un botón, cuando hagamos click en él, se producirá la validación de nuevo y, si tenemos algún control de validación sin grupo de validación asociado, puede que haga que dicho control salte porque no se cumple la condición que el valida. Por supuesto, no se cerrará el popup...
¿Y esto por qué pasa? Sencillamente, porque, como hemos dicho, los controles Button por defecto tienen una propiedad activada que se llama CausesValidation (causa validación).
Lo único que tenemos que hacer es poner dicha propiedad a false... (OJO, siempre que no necesitemos dicha validación!!).
Por ejemplo, el botón quedaría así:
<asp:Button ID="cancelButton"
runat="server"
Text="Cancelar"
CausesValidation="false" /
>

Esta solución la tuve que aplicar en un PopupControlExtender del Ajax Control Tookit de ASP.NET para cerrar el popup que se abre y que no me causara la validación de los datos introducidos. El post dónde encontré la solución lo podéis leer aquí.
Espero que os pueda servir de algo.

Un saludo!