Bases de datos Visual Basic 8

Anuncio
VisualBasic2005_07.qxp
02/08/2007
16:29
PÆgina 262
Bases de datos con Visual Basic
End Sub
Protected Sub dsFormView_Deleting(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.SqlDataSourceCommandEventArgs) _
Handles dsFormView.Deleting
'Test for Order Details records
End Sub
Protected Sub dsFormView_Updating(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.SqlDataSourceCommandEventArgs) _
Handles dsFormView.Updating
'Substitute NULL for 1/1/20599
If
e.Command.Parameters("@ShippedDate").Value.ToString.Contains("1/1/2099") Then
e.Command.Parameters("@ShippedDate").Value = DBNull.Value
End If
End Sub
End Class
El evento DataBound se dispara cuando todas las filas de DataSource están pobladas. El
método FormView.DataItem(ColumnName) devuelve el último valor vinculado de la fila
de datos seleccionada actualmente. Las sentencias DimvarNameAsControlType =
CType(FormView.FindControl(ControlId), ControlType) devuelve una referencia al control
que permite definir sus valores de propiedad, por ejemplo Text o Enabled. El manejador
de evento también desactiva el botón Delete para los pedidos que ya se han enviado.
7.4.3 Editar, añadir y borrar registros
El control FormView es mejor elección para editar registros que DataList, ya que
FormView sólo muestra un elemento. Se puede crear una plantilla EditItem o InsertItem
rápidamente en el modo Código del editor copiando y pegando el nodo <ItemTemplate>
y sus hijos. (Para borrar una fila no se necesita ninguna plantilla). El diseñador renombra automáticamente las etiquetas con valores Id duplicados en LabelN, donde N es un
número secuencial.
Renombre el <ItemTemplate> que ha copiado y póngale el nombre <EditItemTemplate>, y
sustituya todas las instancias de Label en los nodos hijo de <EditItemTemplate> por
TextBox para completar la nueva plantilla. Si la plantilla Items tiene bordes, desactive la
propiedad cell border de la tabla para eliminarlos. Otra alternativa es dar a la propiedad
BorderColor el valor BgColor de la tabla o el BackColor del FormView. La figura siguiente
muestra el FormView de la figura anterior con la plantilla EditItem activa.
Una vez finalizado el diseño de la plantilla EditItem, copie y pegue en modo Código el
nodo <EditItemTemplate> y sus hijos y renombre la copia como <InsertItemTemplate> para
que se puedan añadir nuevos ítems.
262
VisualBasic2005_07.qxp
02/08/2007
16:29
PÆgina 263
Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0
7.4.4 Añadir botones de comando
Los controles FormView definen un conjunto de expresiones de modo y acción para activar las plantillas EditItem o InsertItem, cancelar operaciones de edición o inserción y ejecutar los comandos de DataSource UpdateCommand, InsertCommand o DeleteCommand.
Para añadir un control Button, LinkButton o ImageButton a una plantilla y asignarles una
acción hay que escribir el nombre de la acción en el cuadro de texto de la propiedad
CommandName. A diferencia de otros botones similares en las plantillas DataList, para
activar plantillas o actualizar, insertar o borrar ítems, no se necesita código de manejador de evento.
Aquí vemos cómo utilizar los tres modos para activar las plantillas:
Q
Q
Q
Edit – activa la plantilla EditItem. Añade un botón Edit o Update a la plantilla Item
por defecto, con el valor edit o Edit en su propiedad CommandName.
New – activa la plantilla InsertItem. Añade un botón New a la plantilla por defecto
Item con el valor new o New en su propiedad CommandName.
Cancel – reactiva la plantilla Item por defecto. Añade botones Cancel a las plantillas
EditItem e InsertItem con el valor cancel o Cancel en su propiedad CommandName.
Las siguientes acciones son para ejecutar comandos:
Q
Q
Update – ejecuta UpdateCommand de DataSource y activa la plantilla Item. Añade un
botón Save o Update a la plantilla EditItem, con el valor update o Update en su propiedad CommandName.
Insert – ejecuta el InsertCommand de DataSource y activa el comando Item. Añade un
botón Save o Insert a la plantilla InsertItem con el valor insert o Insert en su propiedad CommandName.
263
VisualBasic2005_07.qxp
02/08/2007
16:29
PÆgina 264
Bases de datos con Visual Basic
Q
Delete – ejecuta el DeleteCommand de DataSource. Añade un botón Delete o Remove a
la plantilla Item por defecto con el valor delete o Delete en su propiedad
CommandName.
La figura siguiente muestra la página FormView.aspx con la plantilla InsertItem activada
y la entrada de datos parcialmente completada. Los controles de paginación quedan
ocultos en el modo Insert.
7.5 El control GridView
El control GridView, que substituye el DataGrid de ASP.NET 1.x, simula el control de formulario Windows DataGridView hasta cierto punto, si se considera las limitaciones respecto al navegador de los controles del servidor HTML. El proceso de añadir un
GridView a un formulario es similar al de un DataList o FormView. Arrastre el control
GridView hasta una página y seleccione una fuente de datos existente o especifique una
nueva. La figura siguiente muestra un control GridView paginado, de sólo lectura,
poblado por dsOrders SqlDataSource y con un campo Select Command autogenerado.
Para añadir un campo Select Command para un control GridViews de sólo lectura se ha
de seleccionar la casilla de verificación Habilitar paginación de la etiqueta inteligente
GridView. Al seleccionar Habilitar paginación se añade una paginación numérica por
defecto para el formulario. El cuadro de verificación Habilitar ordenación subraya y cambia el color de las cabeceras de columna para indicar el tipo de clasificación. Puede desactivar la clasificación de los campos seleccionados borrando el valor de su propiedad
SortExpression en el cuadro de diálogo Campos. Los GridViews con DataSources actualizables añaden casillas de verificación Habilitar edición y Habilitar eliminación como
muestra la figura posterior. Una limitación seria de los GridViews es que no permiten
264
VisualBasic2005_07.qxp
02/08/2007
16:29
PÆgina 265
Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0
añadir nuevos elementos. Para ésto se ha de utilizar o bien un DetailsView o un
FormView, que pueden estar en la misma página o en otra diferente.
Los controles GridView soportan estos siete tipos de campo:
Q
CommandFields – corresponden a los modos de FormView. Los CommandFields existentes son: Select, Edit, Cancel, Update y Delete, que disparan los eventos
ItemCommand, SelectedIndexChanging, SelectedIndexChanged, RowEditing, RowCancelingEdit, RowUpdating, RowUpdated, RowDeleting y RowDeleted. El control por
265
VisualBasic2005_07.qxp
02/08/2007
16:29
PÆgina 266
Bases de datos con Visual Basic
defecto para CommandFields es un botón de texto Link. Los botones o imágenes convencionales se pueden sustituir definiendo el valor Button o Image para la propiedad ButtonType del campo.
Q
BoundFields – muestran valores en controles Label por defecto. Si se pulsa el botón
Editar de una fila, los controles Label de columnas editables cambian a Cuadros de
texto. La anchura de los cuadros de texto es fija, para cambiarla hay que cambiar el
BoundField por un TemplateField.
Q
CheckBoxFields – muestran y editan valores binarios, como 0 y 1 o False y True.
Q
ButtonFields – muestran controles Button convencionales.
Q
Q
Q
HyperlinkFields – muestran texto y proporcionan un campo adicional oculto para
navegar por la página. Los campos Select command se pueden sustituir por campos
de hipervínculo para cargar y editar páginas.
ImageFields – muestran gráficos de las columnas image o varbinary del SQL Server,
o archivos XML de imágenes codificadas.
TemplateFields – permiten personalizar el formateo de los cuadros de texto o substituir otros controles, como DropDownLists, para la edición.
7.5.1 Convertir campos BoundFields en campos EditItemTemplate
Los cuadros de texto con un ancho automático son suficientes para los tests iniciales,
pero normalmente habrá que ajustar la anchura para que quepa un GridView, necesario
para la edición de los datos. La figura siguiente muestra la página EditableGridView.aspx
con una fila en el modo edición. Todas las columnas de esta página, excepto Order ID,
que es de sólo lectura, son TemplateFields. Las plantillas Empl. ID y Ship Via especifican
DropDownLists vinculados para definir los valores de las columnas numéricas. El cuadro de texto Cust. ID es de sólo lectura porque no es habitual reasignar un pedido a un
cliente diferente.
Para convertir un BoundField en un TemplateField, abra la etiqueta inteligente GridView y
pulse el vínculo Editar columnas para abrir el cuadro de diálogo Campos. Seleccione en
la lista Campos seleccionados el campo vinculado que quiere convertir, pulse el vínculo
Convertir este informe en Template Field y pulse después Aceptar. El proceso de conversión
añade un ItemTemplate con un control Label y un EditItemTemplate con un control de cuadro de texto e ítems vacíos AlternatingItemTemplate, HeaderTemplate y FooterTemplate,
bajo una cabeceras ColumnName para cada una de las columnas convertidas (ver figura siguiente).
A continuación vemos el código fuente reformateado para las columnas de sólo lectura Order ID y Customer ID:
<Columns>
<asp:BoundField ReadOnly="True" HeaderText="Order ID"
InsertVisible="False" DataField="OrderID"
SortExpression="OrderID">
<ItemStyle HorizontalAlign="Right"></ItemStyle>
</asp:BoundField>
266
VisualBasic2005_07.qxp
02/08/2007
16:29
PÆgina 267
Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0
<asp:TemplateField SortExpression="CustomerID" HeaderText="Cust.
ID"><EditItemTemplate>
<asp:TextBox ID="txtCustomerID" Runat="server" Width="46px" %
Text='<%# Bind("CustomerID") %>' ReadOnly="True"></asp:TextBox>
</EditItemTemplate>
<ItemStyle HorizontalAlign="Left"></ItemStyle>
<ItemTemplate>
<asp:Label Runat="server" Text='<%# Bind("CustomerID") %>'
ID="Label3"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
(ver figura siguiente)
7.5.2 Remplazar cuadros de texto por listas desplegables para la edición
Una buena práctica de diseño es proporcionar listas desplegables vinculadas para definir valores de clave foránea con un número limitado de opciones. Para sustituir un cuadro de texto por una lista desplegable, cree una fuente de datos para la lista y borre el
cuadro de texto. Arrastre un control DropDownList desde el cuadro de herramientas,
defina su DataSource, sus campos de muestra y de valor, y después vincule la propiedad SelectedValue a la columna de clave foránea escribiendo Bind("DataColumnName")
en el cuadro de texto para la expresión de código del cuadro de diálogo ListName-
267
VisualBasic2005_07.qxp
02/08/2007
16:29
PÆgina 268
Bases de datos con Visual Basic
DataBindings (ver la figura siguiente). El método Bind del GridView remplaza al método
Eval de los controles DataList y FormView.
Veamos el código fuente reformateado de la plantilla para la columna Empl. ID:
<Columns>
<asp:TemplateField HeaderText="Empl. ID"><EditItemTemplate>
<asp:DropDownList ID="ddlEmployee" Runat="server" Height="22px"
Width="94px" DataSourceID="dsEmployees"
DataValueField="EmployeeID" DataTextField="LastName"
SelectedValue='<%# Bind("EmployeeID") %>'>
</asp:DropDownList>
</EditItemTemplate>
<ItemStyle HorizontalAlign="Center"></ItemStyle>
<ItemTemplate>
<asp:Label Runat="server" Text='<%# Bind("EmployeeID") %>'
ID="Label2"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
268
VisualBasic2005_07.qxp
02/08/2007
16:29
PÆgina 269
Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0
269
VisualBasic2005_08.qxp
02/08/2007
16:30
PÆgina 271
Capítulo 8
Aplicar técnicas avanzadas
con ASP.NET 2.0
Este capítulo expande el horizonte de desarrollo con VB.NET VB 2005 más allá de las
sencillas páginas Web que sólo contienen datos y algunos controles Web vinculados.
Este capítulo trata aspectos más avanzados de ASP.NET 2.0, que le enseñarán a sacar el
mejor partido de los controles Web y las funciones de VS 2005, algunos nuevos y otros
actualizados, que vemos a continuación:
Y
Y
Data validation: validación de datos con los controles RequiredFieldValidator, RangeValidator, RegularExpressionValidator, CompareValidator, CustomValidator y ValidationSummary.
ObjectDataSources: fuentes de datos de objeto, basadas en tablas de juegos de datos tipificados, definidos en los archivos DataSet.xsd o referencias a bibliotecas de
clase y objetos de negocios habituales con campos Nullable(OfDataType).
No conseguirá las habilidades necesarias para diseñar sitios Webs escalables y funcionales, con fuentes de datos de ejemplo, si se limita a unos cuadros de texto y cinco o
diez filas o grupos de elementos. Con las tablas Orders y Order Details como fuentes de
datos para la mayoría de los proyectos de ejemplo expuestos en este capítulo, podrá
abordar muchos de los aspectos a los que tendrá que enfrentarse en el desarrollo de
páginas Web de producción con VS 2005.
8.1 Validar entradas en controles vinculados a datos
Validar las entradas del usuario antes de enviar los valores editados al servidor de la
base de datos evita acceder innecesariamente al servidor, reduce la carga del mismo e
incrementa la escalabilidad de la aplicación. Si sus controles vinculados a datos conectan con un componente lógico de acceso a datos que refuerza las reglas de negocios, la
validación por parte del cliente de los campos requeridos y los formatos de datos, reduce el tráfico en la red y el consumo de recursos. Todos los formularios Web y de producción de Windows deberían permitir la validación de los datos entrados por el usuario desde el cliente, independientemente de la arquitectura de acceso de datos que se
adopte.
271
VisualBasic2005_08.qxp
02/08/2007
16:30
PÆgina 272
Bases de datos con Visual Basic
ASP.NET cuenta con dos métodos para validar las entradas del usuario mediante controles vinculados: los controles de validación del servidor o el código añadido a los
manejadores de evento ControlId_Updating o ControlId_Inserting. Los controles de validación desde el servidor muestran mensajes de error de validación cuando el usuario
escribe o selecciona un valor que no supera el test de validación y pasa al siguiente control. El código del manejador de evento puede mostrar uno o más mensajes de error de
validación en un cuadro de texto, pero los mensajes de error no aparecen hasta que el
usuario finaliza el proceso de edición y pulsa un botón de actualización o de entrada
de datos. Retrasar la valiadación hasta el momento de enviar los datos puede ser frustrante para los usuarios, especialmente después de una larga sesión de introducción de
datos.
8.2 Los controles de validación de ASP.NET 2.0
ASP.NET 2.0 cuenta con los mismos controles de validación por parte del servidor que
ASP.NET 1.1. Los controles de validación no se limitan a los campos vinculados, también se puede asisgnar un validador a cualquier control de servidor que acepte la entrada de datos por parte del usuario. Para validar columnas GridView o campos DetailsView
se necesita una plantilla EditItem por cada ítem que se quiere validar.
A continuación damos una descripción breve de los seis controles de validación de
ASP.NET:
Y
Y
Y
272
RequiredFieldValidator: comprueba si el control especificado por su propiedad Id
contiene algún valor que no concuerde con el de la propiedad InitialValue, que tiene
un string vacío por defecto. Dando uno de los valores de una DropDownList con
[SelectanItem] como primer miembro de la colección de Items y definiendo True
para AppendDataBoundItems, el valor inicial InitialValue queda especificado como
[SelectanItem]. Si el valor entrado no concuerda con InitialValue, el validador muestra el valor de su propiedad Text o ErrorMessage en letras rojas, a la derecha o por
debajo del control.
RangeValidator: comprueba si el valor de un control específico queda dentro del
rango de valores definidos para las propiedades MinValue y MaxValue, cuyo tipo se
especifica en la propiedad DataType. Esos dos valores pueden ser constantes String,
Integer, Double, Date o Currency. El mensaje de error aparece cuando los valores
introducidos o seleccionados quedan fuera del margen especificado. El control
RangeValidator no comprueba los controles vacíos, por lo que hay que añadir un
RequiredFieldValidator al control que se especifique.
RegularExpressionValidator: comprueba que el texto del control especificado sea
conforme a una expresión regular que usted debe escribir como valor de la propiedad ValidationExpression. Por ejemplo, la RegularExpression [A-Z]{5} valida una
entrada CustomerID si contiene cinco letras mayúsculas. Otra alternativa, es pulsar
el botón builder de ValidationExpression para seleccionar una de las expresiones
regulares estándar, con formato de dirección de e-mail, URL, número de teléfono,
código postal o número de la seguridad social o del carnet de identidad. Hay que
añadir también un RequiredFieldValidator para comprobar los valores vacíos.
VisualBasic2005_08.qxp
02/08/2007
16:30
PÆgina 273
Aplicar técnicas avanzadas con ASP.NET 2.0
Y
Y
Y
CompareValidator: comprueba si el valor del control especificado es mayor,
menor, igual, menor o igual, mayor o igual que el de otro control cuyo valor Id se
especifica como valor de la propiedad ControlToCompare. CompareValidator comprueba el mismo tipo de datos que RangeValidator. Hay que añadir un RequiredFieldValidator para comprobar los valores vacíos.
CustomValidator: permite comprobar el control especificado con una función de
JScript o VBScript, la función ClientValidationFunction y un manejador VB.NET similar que hay que escribir para el evento OnServerValidate. La función ClientValidationFunction proporciona validación por parte del cliente y el manejador de
evento OnServerValidate se ejecuta cuando el usuario envía datos a la página.
ValidationSummary: proporciona la herramienta para mostrar los valores de la
propiedad ErrorMessage de todos los controles de validación actuales en un solo
cuadro de texto o un cuadro de lista. Otra alternativa, u opción adicional, es mostrar los errores en un cuadro de mensaje para usuarios con IE 4.0 o posteriores. El
resumen de los mensajes de error no aparece hasta que el usuario envía el formulario.
La propiedad CausesValidation de los controles Edit y New LinkButton, tiene por defecto el
valor True, lo que activa todos los controles de la plantilla EditItem y, en el caso de DetailsView,
en la plantilla InsertItem.
8.2.1 La nueva propiedad ValidationGroup
ASP.NET 2.0 incorpora una nueva propiedad, ValidationGroup, con la que se pueden
validar datos selectivamente mediante grupos de controles de validación en los formularios de datos que no utilizan los controles preintegrados. Por ejemplo, tal vez no quiera aplicar todos los validadores a una entrada nueva de la tabla Orders. En ese caso,
defina un nombre de grupo, como EditGroup1, en la propiedad ValidationGroup de un
botón de envío EditGroup1 y los controles de validación de los cuadros de texto y otros
controles vinculados del formulario. Otros controles de entrada de datos con validadores en EditGroup2 actualizarán los campos restantes.
Aplicar grupos de validación a controles vinculados GridView es más problemático. Los
CommandFields autoinsertados no proporcionan acceso directo a sus propiedades, por lo
que no se puede especifiar el nombre del ValidationGroup sin añadir un CommandField
obligatorio. Si añade una plantilla InsertItem a un control FormView o DetailsView, debe
añadir los controles de validación requeridos a las dos plantillas EditItem e InsertItem. El
proceso es similar al de agrupar controles de validación en la edición y entrada de datos.
8.3 Otras propiedades de validación compartidas
A continuación, ofrecemos una breve descripción de las propiedades de control más
importantes compartidas por la mayoría de controles de validación:
Y
ControlToValidate es un valor necesario de la propiedad ID para todos los controles
de validación, excepto CustomValidator.
273
VisualBasic2005_08.qxp
02/08/2007
16:30
PÆgina 274
Bases de datos con Visual Basic
Y
Y
Y
Y
ErrorMessage aparece junto al control asociado si no se especifica un valor para
Text. Especifique siempre un valor para Text y añada el texto que quiere mostrar
como ErrorMessage en los cuadros de texto o de mensaje de SummaryValidator.
DisplayMode especifica el modo en que el control de validación muestra la propiedad Text. El valor por defecto, Static, guarda espacio para el mensaje bajo o junto
al control, según la disponibilidad. Dynamic sólo ocupa espacio en el formulario
cuando se muestra un error de validación y suele ser la opción preferida. None
impide que se muestre el mensaje, excepto con el control asociado ValidationSummary, si existe.
ToolTip: su texto ayuda al usuario ya que permite una descripción larga del error
de validación. Por ejemplo, se puede copiar el valor de ErrorMessage en ToolTip y
añadir información para ayudar al usuario a corregir el error.
EnableClientScript determina si hay validación por parte del cliente o no; el valor
por defecto es True. Si se define el valor False, la validación no tendrá lugar hasta
que el usuario no envíe el formualrio.
A continuación, mostramos un ejemplo del código fuente reformateado para un RequiredFieldValidator:
<asp:TemplateField SortExpression= OrderDate HeaderText= Order Date >
<EditItemTemplate>
<asp:TextBox ID= txtOrderDate Runat= server Width= 76px
Text= <%# Bind( OrderDate , {0:d} ) %> ></asp:TextBox>
<asp:RequiredFieldValidator ID= rfvOrderDate Runat= server
ControlToValidate= txtOrderDate ErrorMessage= OrderDate is required.
Display= Dynamic ToolTip= OrderDate is a required field.Required!
</asp:RequiredFieldValidator>
</EditItemTemplate>
<ItemStyle HorizontalAlign= Right VerticalAlign= Top ></ItemStyle>
<ItemTemplate>
<asp:Label Runat= server Text= <%# Bind( OrderDate , {0:d} ) %>
ID= lblOrderDate ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
La siguiente figura muestra el valor Required para la propiedad Text bajo una entrada
vacía de OrderDate.
8.4 Validar ediciones en GridView
En los siguientes apartados veremos cómo pedir a los usuarios que introduzcan datos
en un campo específico, así cómo aplicar expresiones regulares para verificar el formato de los datos, o limitar las entradas a una serie de valores, validar datos comparando
valores con los datos de otra columna o un valor calculado, y sacar el mejor partido del
control ValidationSummary. Si bien un GridView vinculado a un SqlDataSource proporciona los elementos fijos de un test de control de validación, las técnicas que aprenderá a
274
VisualBasic2005_08.qxp
02/08/2007
16:30
PÆgina 275
Aplicar técnicas avanzadas con ASP.NET 2.0
continuación se aplican en cualquier control editable, independientemente del tipo de
fuente de datos.
8.4.1 Añadir un campo necesario de validación a un control GridView
A continuación veremos el proceso básico para añadir un control de validación a la
plantilla EditItem de un GridView en modo Diseño:
1. Abra la etiqueta inteligente de GridView y pulse Editar plantillas. Pulse con el botón
derecho la etiqueta inteligente ItemTemplate y seleccione la opción Editar plantillas
y la columna plantilla para su validación.
2. Ajuste la anchura del control TextBox en el panel EditItemTemplate para colocar el
texto de entrada, borre el valor por defecto de la propiedad Height y cambie el
valor de ID por un nombre descriptivo, txtCustomerID en nuestro ejemplo.
3. Arrastre uno de los controles de validación –en nuestro ejemplo, RequiredFieldValidator– desde la sección Validation del Cuadro de herramientas hasta la derecha del
cuadro de texto, el control mostrará el mensaje de error RequiredFieldValidator, en
rojo por defecto.
4. Abra la ventana Propiedades del validator, asigne un nombre relacionado –como
rfvCustomerID–al valor de la propiedad ID y el nombre del cuadro de texto asocia-
275
VisualBasic2005_08.qxp
02/08/2007
16:30
PÆgina 276
Bases de datos con Visual Basic
do a la propiedad ControlToValidate. Cambie el valor Static de la propiedad Display
por Dynamic, substituya el ErrorMessage por defecto por una descripción breve de
la regla de validación, añada un mensaje corto para que aparezca bajo el cuadro de
texto como valor de la propiedad Text y añada un texto opcional para ToolTip, tal
como muestra la siguiente figura.
Al validar los GridViews, defina el valor Top para la propiedad ItemStyle.VerticalAlign en el
cuadro de diálogo Fields. Ese ajuste alineará horizontalmente todos los cuadros de texto cada vez
que se muestre un mensaje de error.
8.5 Validar entradas CustomerID con un control
RegularExpressionValidator
El campo CustomerID de la tabla Order requiere cinco letras mayúsculas, por lo que es
un buen candidato para comprobar la validación mediante una expresión regular. La
sencilla expresión [A-Z]{5} es suficiente para este test; [A-Z] especifica las letras mayúsculas de la A hasta la Z y {5} indica el número de veces que ha de aparecer la letra en el
texto relacionado.
Escribir expresiones regulares está más allá del alcance de este libro. El sitio Regular Expressions Library, en la dirección http://www.regexlib.com/, tiene unas 800 expresiones indexadas, con una amplia variedad de formatos de texto estándar y semi-estándar. La entrada de la
ayuda online: acerca de las expresines regulares (About Regular Expressions) contiene apartados dónde se explica el funcionamiento de estas expresiones y se describe las clases del espacionombre System.Text.RegularExpressions.
276
VisualBasic2005_08.qxp
02/08/2007
16:31
PÆgina 277
Aplicar técnicas avanzadas con ASP.NET 2.0
Para añadir un RegularExpressionValidator a la plantilla CustomerID del GridView, siga los
pasos descritos en el apartado anterior, pero arrastrando un control RegularExpressionValidator hasta la derecha del RequiredFieldValidator. Cambie adecuadamente los valores
de las propiedades del RequiredFieldValidator, y escriba [A-Z]{5} como valor de ValidationExpression. Pulse el botón de construcción (builder button) en el cuadro de texto
ValidationExpression y se abrirá el cuadro de diálogo Editor de expresiones regulares, con
una serie de expresiones prefabricadas para europeos, norteamericanos y asiáticos (ver
la siguiente figura).
A continuación vemos el código fuente reformado para el TemplateField CustomerID con
los controles RequiredValueValidator y RegularExpressionValidator añadidos:
<asp:TemplateField SortExpression= CustomerID HeaderText= Cust. ID >
<EditItemTemplate>
<asp:TextBox ID= txtCustomerID Runat= server Width= 52px
Text= <%# Bind( CustomerID ) %> ></asp:TextBox>
<asp:RequiredFieldValidator ID= rfvCustomerID Runat= server
ErrorMessage= CustomerID is required. Display= Dynamic
ControlToValidate= txtCustomerID
ToolTip= CustomerID is a required field. > Required!
</asp:RequiredFieldValidator> 
<asp:RegularExpressionValidator ID= revCustomerID Runat= server
ErrorMessage= CustomerID must be 5 capital letters.
Display= Dynamic ControlToValidate= txtCustomerID
ValidationExpression= [A-Z]{5}
ToolTip= CustomerID must be 5 capital letters. >[ABCDE]
277
VisualBasic2005_08.qxp
02/08/2007
16:31
PÆgina 278
Bases de datos con Visual Basic
</asp:RegularExpressionValidator>
</EditItemTemplate>
<ItemStyle HorizontalAlign= Left VerticalAlign= Top ></ItemStyle>
<ItemTemplate>
<asp:Label Runat= server Text= <%# Bind( CustomerID ) %>
ID= lblCustomerID ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
El ejemplo anterior ha sido elaborado para demostrar la validación de regex. En las aplicaciones de la vida real, lo mejor es definir los valores de CustomerID en una lista desplegable (DropDownList, parecida a las de las columnas EmployeeID o ShipVia del ValidatedGridView) y comprobarlos contrastando un Custom Validator con una tabla de datos
con valores CustomerID válidos.
8.5.1 Comprobar los valores de EmployeeID con un control
RangeValidator
Los valores de clave foránea de EmployeeID deben ser entre 1 y 9. La lista desplegable
ddlEmployee original, que permite a los usuarios seleccionar apellidos en una lista, evita
que los usuarios seleccionen un valor EmployeeID no válido. En este ejemplo se ha
incluido un item [LastName] no válido en la consulta SQL sobre dsEmployeesSqlDataSource. Veámoslo:
SELECT [EmployeeID], [LastName] FROM [Employees]
UNION SELECT 0, [Last Name] ORDER BY [LastName]
El control RangeValidator requiere que se seleccione un valor apropiado (Integer) para la
propiedad Type y se especifiquen valores en las propiedades MinimumValue(1) y MaximumValue(9) para los datos numéricos y de fecha.
8.5.2 Aplicar RangeValidator y RegularExpressionValidator a las
entradas de datos
Para evitar el acceso al servidor cuando los usuarios entran fechas inexistentes o en el
formato erróneo, hay que verificar la entrada con un RangeValidator que acepta fechas
dentro de unos ciertos límites. Los límites que se definan dependen de la fuente de
datos para ese campo, pero la mayoría de aplicaciones tendrán, probablemente,
1/1/1980 como MinimumValue y 12/31/2099 como MaximumValue. Si se especifica Date
como valor de la propiedad Type, el DateTime de .NET comprueba que la fecha sea válida. Como ejemplo, 2/29/2005 o 11/31/00 provocaría un error, pero 2/29/2004 o 02/29/00,
no. Por lo tanto, una buena práctica de programación es añadir un RangeValidator a
todas las columnas Datetime de los cuadros de texto vinculados. Por defecto, el DateTime acepta años con dos o cuatro dígitos, y barras o guiones como separadores.
Si quiere implantar un formato específico más corto, por ejemplo M/D/YYYY, deberá
añadir un validador RegularExpression. La siguiente regex requiere vírgulas/comas y
años escritos con cuatro dígitos:
278
VisualBasic2005_08.qxp
02/08/2007
16:31
PÆgina 279
Aplicar técnicas avanzadas con ASP.NET 2.0
^((((0?[13578])|(1[02]))[\/]?((0?[1-9]|[0-2][0-9])|(3[01])))|(((0?[469])|(11))[\/]
?((0?[1-9]|[0-2][0-9])|(30)))|(0?[2][\/]?(0?[1-9]|[0-2][0-9])))[\/]?\d{4}$
La regex anterior es una modificación de una de las expresiones donadas por Cliff
Schneide al sitio Regular Expressions Library. Las modificaciones impiden los separadores con guiones de unión y exigen años de cuatro dígitos.
Veamos el código fuente reformateado para el OrderDate TemplateField con los controles RequiredFieldValidator, RangeValidator y RegularExpressionValidator:
<asp:TemplateField SortExpression= OrderDate HeaderText= Order Date >
<EditItemTemplate>
<asp:TextBox ID= txtOrderDate Runat= server Width= 76px
Text= <%# Bind( OrderDate , {0:d} ) %> ></asp:TextBox>
<asp:RequiredFieldValidator ID= rfvOrderDate Runat= server
ControlToValidate= txtOrderDate
ErrorMessage= OrderDate is required. Display= Dynamic
ToolTip= OrderDate is a required field. >Required!
</asp:RequiredFieldValidator>
<asp:RangeValidator ID= rvOrderDate Runat= server
ToolTip= Dates must be in ShortDate format (MM/DD/YYYY)
ControlToValidate= txtOrderDate
ErrorMessage= Dates must be in M/D/YYYY format.
MinimumValue= 1/1/1980 MaximumValue= 12/31/2099 Type= Date
Display= Dynamic >[M/D/YYYY]
</asp:RangeValidator>
<asp:RegularExpressionValidator ID= revOrderDate Runat= server
ToolTip= Date format must be M/D/YYYY and date must be valid.
Display= Dynamic ErrorMessage= Date format must be M/D/YYYY.
ControlToValidate= txtOrderDate
ValidationExpression= ^((((0?[13578])|(1[02]))[\/]?((0?[1-9]|[0-2]
[0-9])|(3[01])))|(((0?[469])|(11))[\/]?((0?[1-9]|[0-2][0-9])|
(30)))|(0?[2]\/?(0?[1-9]|[0-2][0-9])))[\/]?\d{4}$
>[M/D/YYYY]
</asp:RegularExpressionValidator>
</EditItemTemplate>
<ItemStyle HorizontalAlign= Right VerticalAlign= Top ></ItemStyle>
<ItemTemplate>
<asp:Label Runat= server Text= <%# Bind( OrderDate , {0:d} ) %>
ID= lblOrderDate ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
8.6 Impedir entradas ilógicas con un CompareValidator
Se puede utilizar un CompareValidator para impedir las entradas numéricas y las fechas
con valores que van contra las reglas de negocio (o el sentido común), por ejemplo un
RequiredDate igual o inferior a la fecha OrderDate. La propiedad ControlToCompare del
279
VisualBasic2005_08.qxp
02/08/2007
16:31
PÆgina 280
Bases de datos con Visual Basic
control CompareValidator requiere que el ID de un control tenga un tipo de datos compatibles con el del ControlToValidate especificado. Por ejemplo, para comparar un valor
Integer con otro que tenga una fracción decimal, hay que especificar Double como valor
de Type.
En este ejemplo vamos a substituir el control CompareValidator por el RangeValidator.
Especifique txtRequiredDate como valor de ControlToValidate, txtOrderDate como ControlToCompare, GreaterThan como Operator y Date como Type.
A continuación, el código fuente reformateado para el RequiredDate TemplateField:
<asp:TemplateField SortExpression= RequiredDate HeaderText= Required Date >
<EditItemTemplate>
<asp:TextBox ID= txtRequiredDate Runat= server Width= 76px
Text= <%# Bind( RequiredDate , {0:d} ) %> ></asp:TextBox>
<asp:RequiredFieldValidator ID= rfvRequiredDate Runat= server
ToolTip= RequiredDate is required and must be later than
OrderDate.
Display= Dynamic ErrorMessage= RequiredDate is required.
ControlToValidate= txtRequiredDate >Required!
</asp:RequiredFieldValidator>
<asp:CompareValidator ID= cvRequiredDate Runat= server
ToolTip= RequiredDate must be later than OrderDate. Display= Dynamic
ErrorMessage= RequiredDate must be later than OrderDate.
ControlToValidate= txtRequiredDate Operator= GreaterThan
ControlToCompare= txtOrderDate >Impossible!
</asp:CompareValidator>
<asp:RegularExpressionValidator ID= revRequiredDate Runat= server
ToolTip= Date format must be M/D/YYYY and date must be valid.
Display= Dynamic ErrorMessage= Date format must be M/D/YYYY.
ControlToValidate= txtRequiredDate
ValidationExpression= ^((((0?[13578])|(1[02]))[\/]?((0?[1-9]|[0-2]
[0-9])|(3[01])))|(((0?[469])|(11))[\/]?((0?[1-9]|[0-2][0-9])|
(30)))|(0?[2]\/?(0?[1-9]|[0-2][0-9])))[\/]?\d{4}$
>[M/D/YYYY]
</asp:RegularExpressionValidator>
</EditItemTemplate>
<ItemStyle HorizontalAlign= Right VerticalAlign= Top ></ItemStyle>
<ItemTemplate>
<asp:Label Runat= server Text= <%# Bind( RequiredDate , {0:d} ) %>
ID= lblRequiredDate ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
8.6.1 Añadir un control CustomValidator
Los controles CustomValidator requieren añadir un manejador de validación por parte
del servidor, para el evento ValidatorName_ServerValidate y una función opcional JScript
280
VisualBasic2005_08.qxp
02/08/2007
16:31
PÆgina 281
Aplicar técnicas avanzadas con ASP.NET 2.0
o VBScript para la validación por parte del cliente. Este ejemplo valida las ediciones de
la columna Freight y requiere una entrada de 5 o más si la columna ShippedDate contiene una fecha. El validador utiliza la "política comercial de envío mínimo de $ 5.00 y
cargo adicional" de los comerciantes de Northwind.
Veamos el código fuente reformateado para el Freight TemplateField, que especifica el
manejador de evento cvFreight_ServerValidate por parte del servidor, y el valor de la propiedad ClientValidationFunction de VBScript por parte del cliente:
<asp:TemplateField SortExpression= Freight HeaderText= Freight >
<EditItemTemplate>
<asp:TextBox ID= txtFreight Runat= server Width= 52px
Text= <%# Bind( Freight ) %> ></asp:TextBox>
<asp:RequiredFieldValidator ID= rfvFreight Runat= server
ErrorMessage= Freight is required; enter 0 if not known.
Display= Dynamic ControlToValidate= txtFreight >Required!
</asp:RequiredFieldValidator>
<asp:CustomValidator ID= cvFreight Runat= server
ToolTip= Freight for shipped order cannot be less than $5.00
ControlToValidate= txtFreight Display= Dynamic
ErrorMessage= Freight for shipped order is less than $5.00
OnServerValidate= cvFreight_ServerValidate
ClientValidationFunction= ValidateFreight >
<5=Bad!
</asp:CustomValidator>
</EditItemTemplate>
<ItemStyle HorizontalAlign= Right VerticalAlign= Top ></ItemStyle>
<ItemTemplate>
<asp:Label Runat= server Text= <%# Bind( Freight , {0:C2} ) %>
ID= lblFreight ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
El siguiente manejador de evento cvFreight_ServerValidate contiene código para obtener
el valor de otra columna GridView de la fila editada. El código también define el valor
False para la propiedad args.IsValid siempre que haya una fecha en la columna
ShippedDate y el valor de Freight sea menor que $5.00.
Sub cvFreight_ServerValidate(ByVal source As Object,
ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs)
args.IsValid = True
If Val(args.Value) < 5 Then
With gvOrdersEditable
Dim gvrRow As GridViewRow = .Rows(.EditIndex)
Dim txtShipped As TextBox =
CType(gvrRow.FindControl("txtShippedDate"), TextBox)
If txtShipped IsNot Nothing Then
If Len(txtShipped.Text) > 4 Then
281
VisualBasic2005_08.qxp
02/08/2007
16:31
PÆgina 282
Bases de datos con Visual Basic
args.IsValid = False
End If
End If
End With
End If
End Sub
Escribir el código para la función de validación por parte del cliente es un poco más
complicado. Hay que inferir el nombre del campo a verificar del valor de Document.activeElement.id, el cual devuelve gvOrdersEditable_ctl14_txtFreight del siguiente
elemento <input> activo:
<input name= gvOrdersEditable$ctl14$txtFreight type= text value= 0
id= gvOrdersEditable_ctl14_txtFreight style= width:52px; />
Substituya txtFreight por txtShippedDate para crear el valor del atributo id para la misma
fila y aplique el método Document.getElementById(ShipDateId).outerHTML para devolver el elemento ShippedDate <input>:
<input name= gvOrdersEditable$ctl14$txtShippedDate type= text value= 5/10/1998
id= gvOrdersEditable_ctl14_txtShippedDate style= width:76px; />
Finalmente, extraiga el texto del atributo value para determinar si existe algún valor
ShippedDate.
A continuación, vemos la función VBScript en la sección <head> que implementa la validación por parte del cliente:
<script language= vbscript >
Function ValidateFreight(source, args)
If args.Value < 5 Then
FreightID = Document.activeElement.id
ShipDateID = Left(FreightID, InStrRev(FreightID,
_ )) &
txtShippedDate
ShipDate = Document.getElementById(ShipDateID).outerHTML
ShipDate = Mid(ShipDate, Instr(ShipDate, value= ) + 6)
ShipDate = Left(ShipDate, Instr(ShipDate,
name= ) -1)
If Len(ShipDate) > 4 Then
args.IsValid = False
Else
args.IsValid = True
End If
End If
End Function
</script>
Puede escribir código similar para realizar cálculos de validación de fechas, como substituir el control CompareValidator por el RequiredDate con un CustomValidator que requiera un mínimo de siete días de diferencia entre los valores de OrderDate RequiredDate.
282
Descargar