Tal y como prometí en un anterior post, voy a explicar cómo podemos conseguir que un control sea utilizable directamente por los controles de validación estándar que vienen con ASP.NET.
Ciertos controles Web (por ejemplo el control Calendar) no permiten su uso combinado con los controles de validación (estilo RequiredFieldValidator, RangeValidator, etc...), lo cual es una lástima porque para poder validar su contenido tenemos que construir nuestro propio control de validación (en fin...) o bien usar eventos de servidor para poder validarlos. Una de las ventajas de los controles de validación de ASP.NET es que ya realizan una validación en el cliente además de la que se hace en el servidor después, lo que ahorra tiempo y agiliza mucho la interfaz. Además están integrados en la validación de la página y permiten comprobar la propiedad IsValid de ésta antes de continuar con suprocesamiento, algo muy útil también.
Por otro lado es muy habitual combinar diversos controles Web con una propósito común dentro de un control de usuario (.ascx) de forma que podamos reutilizarlos en cualquier lugar de la interfaz. Al igual que (como hemos visto), por defecto, no tienen un método para establecer su foco, tampoco es posible usarlos con los validadores estándar, por lo que pierden parte de su utilidad al no poder usarlos del mismo modo que los controles más habituales.
Sería interesante poder añadir la capacidad de trabajar con los controles de validación a este tipo de controles. Vamos a ver cómo conseguirlo.
Un ejemplo real
Por ejemplo, imagina un control ASCX de selección específico de nuestra aplicación. Éste contiene un par de listas desplegables para seleccionar elementos desde la base de datos, una lista de elementos vacía inicialmente y un botón que permite añadir elementos a esta lista para su selección. Queremos colocar este control en cualquier formulario y que nos sirva, por ejemplo, para seleccionar localidades de un país. Su aspecto sería similar a este:
Este control de la imagen es uno real, usado en diversos lugares de la aplicación de uno de nuestros clientes para permitir la selección de zonas y áreas geográficas relacionadas. Tiene una funcionalidad relativamente compleja que implica el uso de bases de datos, validación de los datos seleccionados, etc... En algunos lugares de la aplicación se permite su uso de forma que no es obligatoria la selección de elementos (por ejemplo para las búsquedas, ya que si no se indica zona alguna no se restringe por dicha dimensión), y en otras zonas es necesario validar que se haya seleccionado como mínimo una zona, o incluso más de una.
Con el control creado de la manera habitual, al colocarlo en un formulario no podemos utilizar los controles de validación con él, por lo que no nos quedaría más remedio que responder a un evento de servidor (por ejemplo a la pulsación del botón de la acción principal del formulario), hacer la comprobación pertinente y mostrar un mensaje en el cliente con una etiqueta, con lo que no se integraría con la validación de los restantes controles.
Añadiendo la funcionalidad de validación
Para que un control pueda ser validado por un validador común debe implementar alguna propiedad de tipo texto que devuelva un valor interpretable por el validador. Normalmente deberíamos hacer que devolviera una cadena vacía en caso de no contener un valor correcto y así funcionará bien con el RequiredFieldValidator.
En nuestro caso hemos definido la propiedad NumItems del control ASCX que simplemente indica el número de zonas seleccionadas en el control en un momento dado:
public string NumItems
{
get
{
if (lstSeleccion.Items.Count > 0)
return lstSeleccion.Items.Count.ToString();
else
return String.Empty;
}
}
Una vez definida esta propiedad debemos indicar al runtime de ASP.NET que será ésta la utilizada para realizar las validaciones. ello se consigue usando el atributo ValidationProperty. Éste toma como parámetro el nombre de la propiedad a utilziar en las validaciones, por lo que en la definición de nuestra clase escribimos:
[ValidationProperty("NumItems"), SupportsEventValidation]
public partial class Controles_SelectorZonas : System.Web.UI.UserControl
{
Así indicamos que los validadores deben usar la propiedad NumItems para realizar la validación. El otro atributo, SupportsEventValidation, se utiliza para indicar al runtime que nuestro control soporta los eventos de validación ya qe de otra forma no se generarían eventos de validación.
Nota: Si quisiésemos hacer algo similar con un control estándar que no soporte validación, como el calendario, tendríamos que crear una nueva clase que heredara de éste y decorarla con este atributo para poder usarlo.
Vale. Listo. Si ahora soltamos el control en un formulario Web y añadimos un control de validación veremos que... ¡no aparece nuestro control en la lista de los controles que podenmos utilizar! :-(
No pasa nada. Es un pequeño efecto secundario. Simplemente añadámoslo a mano en el atributo ControlToValidate del validador y veremos que funciona correctamente. Por ejemplo:
<
asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="lstDestinos"
CssClass="ErrorMsg" Display="Dynamic" ErrorMessage="Debe seleccionar al menos una zona de destino."></asp:RequiredFieldValidator>
El valor del atributo ControlToValidate, que es el nombre del control ascx que queremos validar, lo hemos metido a mano, pero funciona perfectamente que es lo que buscábamos. Ahora nuestro complejo control de usuario se integra bien en la estructura de validación de la pa´gina y podemos trabajar con él como con cualquier otro control validable.
Super-útil ¿no? :-)