VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 241 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 en Default.aspx en el Explorador de Soluciones y seleccione la opción Ver código para generar el archivo. Default.aspx.vb que contiene las declaraciones vacías PartialClassDefault_aspx e InheritsSystem.Web.UI.Page para el código oculto tras la página Default.aspx. Default.aspx se abre en el editor XHTML1.1 de fuentes con la directiva de página por defecto, la declaración DOCTYPE y los elementos <html>, <head>, <body>, <form> y <div>, tal como se muestran, reformateados, en la siguiente figura. Sustituya Página sin título por un nombre más significativo y pulse el botón Ver diseñador para mostrar una página vacía en el diseñador, que sólo soporta el modo convencional HTML. La nueva versión ASP.NET 2.0 no soporta el modo de posicionamiento de elementos fijos en una parrilla, por defecto, de ASP.NET 1.x. La explicación de que falte el modo diseño de posición fija es que las ventanas flotantes soportan una gama más amplia de navegadores y controladores. Sitúe los controles en celdas de tabla para controlar el posicionamiento relativo, añada hojas de estilo en cascada (en inglés, cascading style sheet, CSS) para el posicionamiento fijo. Para definir métodos alternativos de posicionamiento de los controles Web, seleccione Herramientas/Opciones//Diseñador HTML/Posición CSS, active la casilla de verificación Cambiar la siguiente posición… y el método de posicionamiento en la lista desplegable. Seleccione Diseño/Insertar tabla para abrir el cuadro de diálogo del mismo nombre, seleccione la opción Plantilla y acepte el estilo por defecto Encabezado y, por último, pulse el botón aceptar para añadir una tabla de página completa con una cabecera y sin bordes. Escriba un título para la tabla y déle formato; seleccione la tabla entera pulsando el ángulo superior izquierdo, abra la ventana Propiedades y asigne un valor Id a la tabla (por ejemplo tblmain) y un color Web a la propiedad BgColor; el color definido cambia a su valor RGB (ver siguiente figura). 241 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 242 Bases de datos con Visual Basic Finalmente, pulse <F5> para construir y ejecutar la parte realizada del trabajo. Pulse Aceptar en el cuadro de diálogo Depuración no habilitada para añadir un archivo Web.config al proyecto. El servidor Visual Web Developer se inicia y muestra Default.aspx en Internet Explorer. Pulse con el botón secundario el icono del servidor Web en la barra de tareas y seleccione mostrar detalles para abrir el cuadro de diálogo con las propiedades del servidor que le mostrará el puerto TCP elegido, de forma aleatoria, para la página (ver la siguiente figura). 7.1.1 El modelo de compilación de ASP.NET Una directiva de página en ASP.NET 1.1 especifica el nombre del archivo de código oculto y el nombre de la clase base del formulario, tal como vemos aquí: <%@ Page Language= vb AutoEventWireup= false Inherits= DataWebSite.Form1 %> 242 Codebehind= Default.aspx.vb VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 243 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 Los archivos PageName.aspx.vb de ASP.NET 1.x contienen una zona de inicialización y un código de inicialización para cada control de la página. La primera vez que se abre el sitio Web de la dirección http://www.company.com/datawebsite/default.aspx, ASP.NET 1.x compila el código oculto tras la página en tiempo de ejecución y genera un juego de archivos temporales, incluyendo un archivo para la definición PublicClassDefault_aspx derivada de la clase base de WebSiteName.Form1. A continuación vemos la directiva de página de ASP.NET 2.0 para la página Default.aspx que se añadió en el apartado anterior: <%@ Page Language= VB AutoEventWireup= false Inherits= _Default %> CodeFile= Default.aspx.vb Con las clases parciales para la etiqueta HTML y el código oculto tras la página ya no es necesaria una clase derivada. La instrucción CodeFile especifica qué etiqueta y código en Default.aspx y qué código en Default.aspx.vb se han de compilar en una sola clase single _Default. La carpeta de proyecto no incluye la subcarpeta tradicional \bin. Construir y ejecutar una solución ASP.NET 2.0 con el servidor Web integrado genera una serie de archivos temporales en la carpeta \WINDOWS\Microsoft.NET\Framework\v2.0.BuildNumber\Temporary ASP.NET Files\websitename\random1\random2; websitename es el nombre de la carpeta en minúsculas, en este ejemplo datawebsite, y random1\random2 son dos nombres de carpeta de 8 caracteres, elegidos al azar, al igual que e7ae7f95\aa3fd637 (ver la siguiente figura). ASP.NET 1.1 genera archivos temporales con una jerarquía de carpetas similar. La tabla siguiente describe los archivos temporales mostrados en la figura anterior. Los nombres en negrita corresponden a los archivos temporales similares generados por ASP.NET 1.1. 243 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 244 Bases de datos con Visual Basic Nombre del archivo Descripción App_Web_bmzetgsw.dll Unión de archivos 0.vb, 1.vb, y 2.vb. App_Web_bmzetgsw.pdb Archivo de símbolos (debugging) para bmzetgsw.dll. bmzetgsw.0.vb PartialClassDefault_aspx para el HTML, controles del servidor y código en línea de la página (autogenerado desde Default.aspx). bmzetgsw.1.vb PartialClassDefault_aspx contiene código oculto (copia de Default.aspx.vb). bmzetgsw.2.vb PublicClassFastObjectFactory con una función no utilizada (dummy) SharedFunctionCreate_Default_aspx()AsObject. bmzetgsw.cmdline Parámetros Vbc.exe para compilar el conjunto. bmzetgsw.err Errores de compilación (vacío si la compilación tiene éxito). bmzetgsw.outFull Comando completo Vbc.exe (incluye línea bmzetgsw.cmd). bmzetgsw.res Archivo de recursos compilado que contiene el código en línea de la tabla principal. default.aspx.cdcab7d2.compiled Dependencias del archivo y lista de valores hash para la página (XML). default.aspx.cdcab7d2_ CBMResult.ccu CodeCompileUnit (contenedor para programa gráfico CodeDOM para la página). default.aspx.cdcab7d2_ CBMResult.compiled Lista de dependencias de archivo y valores hash de la CodeCompileUnit (XML). default.aspx.vb.cdcab7d2.compiled Dependencias de archivo y lista de valores hash para el código oculto tras la página (XML). hash.web Valor hash hexadecimal de 16 Bytes. Compilar el código y las etiquetas HTML para cada página mejora la productividad mientras se están desarrollando páginas individuales o un sitio completo con el servidor Web integrado. Sólo las páginas modificadas se recompilan mientras se está ejecutando el proyecto. En el apartado dedicado a la publicación de sitios Web precompilados del capítulo 8, se explica cómo realizar un proyecto de formularios Web completo en un directorio virtual IIS 5.0 o IIS 6.0. Publicar un formulario Web precompilado genera un único archivo DLL en la carpeta \bin, elimina el código fuente y el retraso de compilación cuando el primer usuario abre el archivo del proyecto Default.aspx o cualquier otra página de inicio que se haya especificado. 7.1.2 Los nuevos controles (Data Controls) de ASP.NET 2.0 ASP.NET 2.0 añade unos 40 nuevos controles Web al repertorio de ASP.NET 1.1. Muchos de estos nuevos controles soportan la conectividad de datos declarativa y la vinculación de datos con poco o nada de código online o código oculto tras la página requerida. La vinculación de datos automatiza, además, las operaciones opcionales de actualización, inserción y borrado en las tablas de la base de datos y los habituales objetos y componentes de acceso a datos. Q 244 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 245 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 A continuación, una breve descripción de los nuevos controles de servidor en ASP.NET 2.0 que soportan la vinculación de datos y las actualizaciones: Q Q Q Q Q Los controles DataSource conectan con las bases de datos, los objetos de acceso a datos y los documentos XML tabulares y jerárquicos, incluyendo los juegos de datos tipificados serializados. Los controles DataSource proporcionan la fuente vinculante para controles bidireccionales de datos vinculados y otros controles de servidor, como las listas desplegables y los cuadros de lista, que soportan la vinculación de datos de sólo lectura. Los controles DataSource sustituyen a los controles de datos relacionados de ADO.NET 1.1, como Connections y DataAdapters. Los controles DataList muestran y editan filas DataSource de forma secuencial en una o más columnas. Los controles FormView muestran y editan una sola fila DataSource en un formulario XML convencional. Los controles GridView muestran y editan múltiples filas DataSource en una parrilla similar a los DataGridView de los formularios Windows. GridView sustituye al DataGrid de ASP.NET 1.x. Los controles DetailsView muestran y editan una sola fila DataSource en una tabla de dos columnas. Además, soportan las páginas de edición de datos maestro/hijo. El resto de este capítulo está dedicado a estos nuevos controles que acabamos de mencionar. 7.2 Los controles DataSource La sección Datos del Cuadro de herramientas de VS 2005 sustituye las herramientas de VS 2002 y 2003 de ADO.NET 1.x: DataSet, DataView, Connection, Command y Adapter por un juego de herramientas DataSource predefinidas. Un DataSource de ASP.NET 2.0 combina los elementos requeridos para el tipo de fuente de datos que se especifique en una componente nombrada que aparece en el modo Diseño de página como DataSourceType -DataSourceName. En el modo código, un elemento <asp:DataSourceType> guarda la definición de la fuente de datos. Para añadir un control DataSource a una página en modo diseño sólo hay que arrastrar el control desde la sección Datos del Cuadro de herramientas hasta la página en cuestión. VS 2005 proporciona los siguientes controles DataSource integrados: Q SqlDataSource – para bases de datos cliente/servidor. El elemento <asp:SqlDataSource> incluye los atributos ConnectionString y SelectCommand que se añaden con los cuadros de diálogo Configurar origen de datos. Las fuentes de datos actualizables permiten añadir los atributos DeleteCommand, InsertCommand y UpdateCommand. A diferencia de los formularios de Windows, que limitan SqlConnection, SqlCommand y los objetos relacionados a las bases de datos del SQL Server, SqlDataSource le permite utilizar cualquier conexión que haya definido en el Explorador de servidores, o definir una conexión nueva. Q 245 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 246 Bases de datos con Visual Basic Q Q Q Q AccessDataSource – para los archivos Access. El elemento <asp:AccessDataSource> sustituye un atributo de ruta relativa datafile= ~/App_Data/FileName.mdb por el atributo string Connection de SqlDataSource. Hay que usar el comando Agregar/Nuevo elemento para añadir el archivo FileName.mdb a la carpeta ...\ProjectName\App_Data para hacer el archivo accesible al cuadro de diálogo Configurar origen de datos del asistente del mismo nombre. AccessDataSources utiliza el proveedor de datos OLE DB Jet, por lo que se puede especificar un nombre de usuario y contraseña para hacer las bases de datos más seguras modificando la conexión en el Explorador de servidores. ObjectDataSource – para los objetos de negocios habituales, servicios Web, componentes de datos o DataSets que retornan y, opcionalmente, actualizar datos. El objeto debe soportar la interfaz IEnumerable y proporcionar al menos un método público para posibilitar la selección; los métodos para borrar, insertar y actualizar son opcionales. El archivo de definición de la clase de objeto se ha de incluir en la carpeta App_Code, o bien se han de copiar los ensambladores de objetos en la carpeta App_Assemblies. Otra alternativa es añadir una referencia a la librería de la clase compilada de objetos con el cuadro de diálogo Añadir referencia o una referencia Web para el servicio Web con el cuadro de diálogo Añadir referencia web. XmlDataSource – para datos de fuente XML, tabular o jerárquica. En ese caso, debe almacenar el archivo del documento fuente XML y, opcionalmente, su esquema XML, en la carpeta App_Data. XmlDataSource no usará el esquema, pero algunos controles vinculados podrían beneficiarse de los tipos de datos asignados a los elementos del documento fuente. Puede actualizar los datos de la fuente XML invocando el método GetXmlDocument o creando un objeto en memoria XmlDataDocument que contenga objetos editables XmlNode. Otra alternativa es utilizar expresiones XPath para actualizar los datos. SiteMapDataSource – conecta con el mapa del sitio del proyecto, el cual se crea con el objeto XmlSiteMapProvider. Los controles de servidor integrados DataSource amplían la clase base DataSourceControl, que es a su vez la base de la interfaz IDataSource. Los controles DataSource contienen objetos nombrados DataSourceView; los controles Web vinculados a datos conectan con el DataSourceView por defecto. Se pueden crear controles habituales DataSource de servidor añadiendo código para ampliar la clase DataSourceControl. La entrada de ayuda online DataSourceControlClass incluye el código fuente para un control de servidor CsvDataSource que restablece datos de un archivo de valores separados por comas. Cuando se arrastra a una página un control de servidor derivado de la clase base abstracta DataBoundControl –como pueden ser DataList, DetailsView, GridView, FormView o TreeView– o un control Repeater, la etiqueta inteligente de Common ControlType Tasks se abre con la lista desplegable Configurar origen de datos activada. Puede seleccionar (Ninguna), un DataSource ya existente para la página o <Nuevo origen de datos> para iniciar el asistente. Otra alternativa es arrastrar uno de los controles DataSource desde el Cuadro de herramientas y utilizarlo como fuente de datos. 246 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 247 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 Otros controles de servidor derivados de la clase base ListControl, como DropDownList, ListBox, RadioButtonList y BulletedList, soportan la vinculación de datos simple (sólo lectura). Las etiquetas inteligentes de estos controles ofrecen una opción Configurar origen de datos que abre un cuadro de diálogo del mismo nombre. El cuadro de diálogo Configurar origen de datos tiene las mismas opciones que la etiqueta inteligente de DataBoundControl, pero el cuadro de diálogo incluye también listas desplegables para seleccionar los datos y los campos de valores de la lista. 7.3 El control DataList El control de servidor DataList es el más sencillo de los controles integrados derivados de DataBoundControl. Por defecto, DataList muestra nombres de columnas y valores para todas las filas devueltas por la sentencia SQL SelectCommand en una columna individual de etiquetas. Se pueden especificar múltiples columnas y el orden en que han de aparecer las filas en las columnas, además de otras muchas opciones de formateo. La figura siguiente muestra la página DataList.aspx de DataWebSite, con pedidos del país que seleccione en la lista desplegable, de izquierda a derecha, de arriba hacia abajo, en secuencia descendente de los valores OrderID. La primera lista define la cláusula WHERE como criterio para el país de envío (ShipCountry). La segunda lista permite seleccionar cualquier pedido en la lista del país actual; al seleccionar una fila de pedidos se muestra el valor CustomerID en un cuadro de texto no vinculado. 7.3.1 SqlDataSources para controles vinculados Un SqlDataSource para controles vinculados se crea arrastrando un control DataList, FormView, GridView, DetailsView o Repeater, desde la sección Datos del Cuadro de herramientas hasta una página Web. En este ejemplo, se empieza con la página Default.aspx 247 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 248 Bases de datos con Visual Basic 1. Copie y pegue Default.aspx; renombre la copia de Default.aspx con DataList.aspx. Abra DataList.aspx en modo código y cambie CodeFile= "Default.aspx.vb" Inherits="_Default" en la página directriz por CodeFile="DataList.aspx.vb" Inherits= "DataList". Abra DataList.aspx.vb y cambie Partial Class _Default por Partial Class DataList. Cierre la ventana del editor. 2. Pulse con el botón secundario en DataList.aspx en el Explorador de soluciones y seleccione Establecer como página de inicio. Pulse <F5> para verificar que se han añadido los datos a las página e inicie la configuración de la página. 3. Cierre IE, cambie DataList.aspx a modo diseño y arrastre un control DataList desde el Cuadro de herramientas hasta una celda vacía de la tabla DataList.aspx. Un contenedor DataList1 se añade al formulario y se abre la etiqueta inteligente DataLists Tasks. 4. Seleccione <Nuevo origen de datos> en la lista Elegir origen de datos para iniciar el Asistente para la configuración de orígenes de datos. Seleccione Base de datos en la lista Elija un tipo de origen de datos. 5. Pulse Aceptar para abrir el cuadro de diálogo Elegir la conexión de datos, seleccione una conexión ya existente a la base de datos de ejemplo Northwind o cree una nueva conección. Si quiere que el sitio se pueda extender a un servidor Web IIS que soporte conexiones anónimas, seleccione o añada una conexión que utilice seguridad SQL Server. Pulse el botón Siguiente. 6. Deje seleccionado el cuadro de verificación Sí, guardar esta conexión como, y edite el nombre de la cadena de conexión como desee. Pulse Siguiente para abrir el cuadro de diálogo Configurar la instrucción Select. 7. Seleccione la tabla Orders en la lista Nombres y marque los nueve primeros cuadros de verificación, desde OrderID hasta ShipName (ver siguiente figura). 8. Pulse el botón ORDER BY para abrir el cuadro de diálogo Agregar clausula ORDER BY, seleccione OrderID en la lista Ordenar por y, a continuación, la opción Descendente. Pulse Aceptar. 248 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 249 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 9. Pulse el botón Avanzadas para abrir el cuadro de diálogo Opciones de generación SQL avanzadas; seleccione las casillas de verificación Generar instrucciones Insert, Update y Delete. En este ejemplo, no seleccione el cuadro Usar concurrencia optimista. Pulse Aceptar y Siguiente para abrir el cuadro de diálogo Consulta de prueba. 10. Pulse el botón Consulta de prueba para mostrar los resultados de la consulta en un DataGridView (ver siguiente figura). Pulse el botón Finalizar para mostrar el formato de diseño por defecto de una DataList, el cual consiste en cinco instancias simuladas de los datos de las columnas seleccionadas en el paso 7. Pulse <F5> para construir y mostrar la página, que aparecerá tal como se muestra en la siguiente figura. La fuente de datos dsOrders con las casillas de verificación Generate Insert, Update y Delete Statements seleccionados, añade el siguiente código fuente a la página: 249 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 250 Bases de datos con Visual Basic <asp:SqlDataSource ID=”dsOrders” Runat=”server” DeleteCommand=”DELETE FROM [Orders] WHERE [OrderID] = @original_OrderID” InsertCommand=”INSERT INTO [Orders] ([CustomerID], [EmployeeID], [OrderDate], [RequiredDate], [ShippedDate], [ShipVia], [Freight], [ShipName]) VALUES (@CustomerID, @EmployeeID, @OrderDate, @RequiredDate, @ShippedDate, @ShipVia, @Freight, @ShipName)” SelectCommand=”SELECT [OrderID], [CustomerID], [EmployeeID], [OrderDate], [RequiredDate], [ShippedDate], [ShipVia], [Freight], [ShipName] FROM [Orders] ORDER BY [OrderID] DESC” UpdateCommand=”UPDATE [Orders] SET [CustomerID] = @CustomerID, [EmployeeID] = @EmployeeID, [OrderDate] = @OrderDate, [RequiredDate] = @RequiredDate, [ShippedDate] = @ShippedDate, [ShipVia] = @ShipVia, [Freight] = @Freight, [ShipName] = @ShipName WHERE [OrderID] = @original_OrderID” ConnectionString=”<%$ ConnectionStrings:NorthwindConnection %>”> <DeleteParameters> <asp:Parameter Type=”Int32” Name=”OrderID”></asp:Parameter> </DeleteParameters> <UpdateParameters> <asp:Parameter Type=”String” Name=”CustomerID”></asp:Parameter> <asp:Parameter Type=”Int32” Name=”EmployeeID”></asp:Parameter> <asp:Parameter Type=”DateTime” Name=”OrderDate”></asp:Parameter> <asp:Parameter Type=”DateTime” Name=”RequiredDate”></asp:Parameter> <asp:Parameter Type=”DateTime” Name=”ShippedDate”></asp:Parameter> <asp:Parameter Type=”Int32” Name=”ShipVia”></asp:Parameter> <asp:Parameter Type=”Decimal” Name=”Freight”></asp:Parameter> <asp:Parameter Type=”String” Name=”ShipName”></asp:Parameter> <asp:Parameter Type=”Int32” Name=”OrderID”></asp:Parameter> </UpdateParameters> <InsertParameters> <asp:Parameter Type=”String” Name=”CustomerID”></asp:Parameter> 250 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 251 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 <asp:Parameter Type=”Int32” Name=”EmployeeID”></asp:Parameter> <asp:Parameter Type=”DateTime” Name=”OrderDate”></asp:Parameter> <asp:Parameter Type=”DateTime” Name=”RequiredDate”></asp:Parameter> <asp:Parameter Type=”DateTime” Name=”ShippedDate”></asp:Parameter> <asp:Parameter Type=”Int32” Name=”ShipVia”></asp:Parameter> <asp:Parameter Type=”Decimal” Name=”Freight”></asp:Parameter> <asp:Parameter Type=”String” Name=”ShipName”></asp:Parameter> </InsertParameters> </asp:SqlDataSource> 7.3.2 Propiedades de control La ventana Propiedades para los controles vinculados permite especificar la fuente y otras propiedades aplicables al control. Además de las propiedades que comparten todos los controles de servidor, DataList tiene propiedades que especifican el número de columnas de lista y el flujo de datos en las columnas. Para simular el diseño de FinalDataList.aspx, pulse el control con el botón derecho y seleccione Propiedades para abrir la ventana del mismo nombre con DataList1 seleccionada y definir los valores de las propiedades que se indican en la tabla siguiente. Propiedad Valor Id Font\Name Font\Size RepeatColumns RepeatDirection dlOrders Verdana 10pt 2 Horizontal 251 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 252 Bases de datos con Visual Basic A continuación, arrastre el borde derecho de dlOrders DataList hasta el borde derecho de la tabla. Los valores de propiedad anteriores generan una página con datos para pedidos en la secuencia descendiente, de arriba a abajo, de izquierda a derecha, que se muestra en la siguiente figura. 7.3.3 Plantilla de datos vinculados y formateo de datos Los DataLists introducen el concepto de plantilla para los campos de los DataBoundControls. Pulse con el botón secundario el control DataList en modo diseño, seleccione Mostrar etiqueta inteligente para abrir el panel de etiquetas ingeligentes del control y pulse Editar plantillas para abrir un formulario de edición con la plantilla Item por defecto. Las plantillas Item contienen texto HTML para los nombres de columna y controles ColumnNameLabel para mostrar los valores de columna. Reformatear la plantilla Item Para tener espacio verticalmente, puede modificar la plantilla de modo que muestre varios nombres de columnas y valores en una sola línea. Dé a la plantilla un ancho de hasta unos 500 píxeles, sitúe el cursor detrás del item OrderIDLabel, pulse Eliminar para eliminar el elemento <br/> y sustitúyalo por dos espacios (&nbsp;). Haga lo mismo con EmployeeIDLabel, RequiredDateLabel y ShipViaLabel (ver siguiente figura). Revisar el código fuente XHTML generado Cada definición de plantilla Item añade texto HTML en ColumnName, seguido de una instrucción Label de control del servidor, con el valor de la propiedad Text especificado 252 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 253 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 en una instrucción Eval("ColumnName") o Eval("ColumnName","FormatString"), incluida entre etiquetas de vinculación de datos (<%#...%>). Al seleccionar Finalizar edición en la plantilla, o al construir el proyecto, el código fuente se añade a la página. A continuación vemos el código fuente –modificado para una mayor legibilidad– generado por la plantilla Item de la figura anterior: <ItemTemplate> OrderID: <asp:Label ID="OrderIDLabel" runat="server" Text='<%# Eval("OrderID") %>'></asp:Label><br /> CustomerID: <asp:Label ID="CustomerIDLabel" runat="server" Text='<%# Eval("CustomerID") %>'> </asp:Label><br /> EmployeeID: <asp:Label ID="EmployeeIDLabel" runat="server" Text='<%# Eval("EmployeeID") %>'> </asp:Label><br /> OrderDate: <asp:Label ID="OrderDateLabel" runat="server" Text='<%# Eval("OrderDate", “{0:d}”) %>'></asp:Label><br /> RequiredDate: <asp:Label ID="RequiredDateLabel" runat="server" Text='<%# Eval("RequiredDate", “{0:d}”) %>'> </asp:Label><br /> ShippedDate: <asp:Label ID="ShippedDateLabel" runat="server" Text='<%# Eval("ShippedDate", “{0:d}”) %>'> </asp:Label><br /> ShipVia: <asp:Label ID="ShipViaLabel" runat="server" Text='<%# Eval("ShipVia") %>'></asp:Label><br /> Freight: <asp:Label ID="FreightLabel" runat="server" Text='<%# Eval("Freight", “{0:C}”) %>'></asp:Label><br /> ShipName: <asp:Label ID="ShipNameLabel" runat="server" Text='<%# Eval("ShipName") %>'></asp:Label><br /> <br /> </ItemTemplate> 253 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 254 Bases de datos con Visual Basic La expresión {0:d} es una cadena de formato estándar para fecha breve; {0:C} especifica el formato de la moneda. 0: representa el valor; las letras corresponden a las cadenas de formato numérico o DateTime que se aplican como argumentos del método ToString, como por ejemplo en NumericValue.ToString("C") o DateTimeValue.ToString("d"). 7.3.4 Restricciones WHERE en el código fuente en los valores de controles vinculados Los elementos SqlDataSource de dsOrders devuelven todos los registros de Orders, algo no demasiado conveniente para los usuarios y que, además, consume recursos considerables de red y del servidor de la base de datos sólo en la operación de abrir la página. Una manera de limitar el número de registros devueltos por el servidor es añadir un control DropDownList con una cláusula WHERE de restricción para el DataSource de la DataList. En este ejemplo, la restricción se aplica a la columna ShipCountry de la tabla Orders; otras alternativas pueden ser EmployeeID o rangos de valores de OrderDate, como año y mes. Añadir una lista desplegable (DropDownList) poblada por una nueva fuente de datos Para añadir una lista desplegable poblada únicamente con valores de la columna ShipCountry, siga los pasos siguientes: 1. Arrastre un control DropDownList hasta la derecha del título de la celda superior de la tabla y añada unos espacios entre el titulo y el control. 2. Pulse la flecha de etiqueta inteligente para abrir el la etiqueta DropDownList, marque la casilla de verificación Habilitar AutoPostBack y pulse el vínculo Elegir origen de datos para abrir el cuadro de diálogo del mismo nombre. 3. Seleccione <Nuevo origen de datos> en la lista Seleccionar un origen de datos para abrir el Asistente para la configuración de origen de datos. Seleccione Base de datos, nombre la fuente de datos dsCountries y pulse Aceptar. En el cuadro de diálogo Elegir la conexión de datos, seleccione la cadena NorthwindConnectionString que guardó al crear la fuente de datos primaria y pulse Siguiente. 4. En el cuadro de diálogo Configurar la instrucción Select, seleccione la tabla Orders, marque la columna ShipCountry y la casilla de verificación Devolver sólo filas únicas, pulse el botón ORDER BY, aplique un orden ascendente para ShipCountry y pulse Aceptar. 5. Pulse el botón Siguiente, compruebe la consulta y pulse Finalizar para volver al cuadro de diálogo Elegir un origen de datos, que mostrará ShipCountry como campo de valores y de muestra (ver la figura siguiente). Pulse Aceptar para cerrar el cuadro de diálogo. 6. Abra la ventana Propiedades de DropDownList1 y cambie el valor de la propiedad Id por ddlCountry o algo similar. 7. Pulse <F5> y verifique que la lista desplegable muestra los países por orden alfabético. Seleccionando un país distinto de Argentina, el servidor refrescará la página con la operación de postback que se especificó en el paso 2. 254 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 255 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 Añadir una cláusula de restricción WHERE basada en el índice seleccionado de la lista Para conectar la selección de DropDownList a una cláusula WHERE de restricción añadida a dsOrders, haga lo siguiente: 1. Pulse la flecha de la etiqueta inteligente variable dsOrders para abrir la etiqueta inteligente SqlDataSource, pulse la opción Configurar origen de datos para iniciar el Asistente para la configuración de origen de datos y pulse el botón Siguiente. 2. Seleccione NorthwindConnectionString, pulse Siguiente y repita la selección de campo de la tabla Orders y la cláusula ORDER BY para SelectCommand. 3. Pulse el botón WHERE para abrir el cuadro de diálogo Agregar claúsula WHERE, seleccione ShipCountry en la lista Columna, acepte default = Operator, y seleccione Control en la lista Origen, que mostrará el cuadro de grupo Propiedades del parámetro. 255 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 256 Bases de datos con Visual Basic 4. Seleccione ddlCountry en la lista ID de Control y, opcionalmente, añada un país como valor por defecto. 5. Pulse el botón Agregar para añadir el criterio [ShipCountry]=@ShipCountry y ddlCountry.SelectedValue como el valor de @ShipCountry. 6. Pulse Aceptar para cerrar el cuadro de diálogo, pulse Siguiente y después el botón Consulta de prueba. Revise el resultado de la consulta y pulse el botón Finalizar. 7. Pulse <F5> y compruebe que al seleccionar un país distinto de Argentina en ddlCountry, la lista se refresca con los registros apropiados. Si prefiere que sean los usuarios quienes seleccionen un país, en lugar de mostrarles registros del primer país de la lista, puede utilizar una nueva propiedad de lista en ASP.NET 2.0: AppendDataBoundItems. Abra la ventana de propiedades de ddlCountry y defina el valor True para la propiedad AppendDataBoundItems. Pulse la flecha de la etiqueta inteligente ddlCountries. Seleccione Editar elementos para abrir el cuadro de diálogo Editor de la colección ListItem, pulse Agregar y escriba [Select a Country] como valor de Text, y verá que también aparece en el cuadro de texto Value (ver figura siguiente). Pulse Aceptar y la página se reabrirá con una celda de tabla inicialmente vacía. Si cambia los paréntesis en ángulo (<>) por los cuadrados ([]), la página arrojará una excepción de seguridad cuando seleccione [Select a Country]. A continuación vemos el código fuente para los elementos ddlCountry y dsCountries de la página: <asp:DropDownList ID=”ddlCountry” Runat=”server” DataSourceID=”dsCountries” Width=”115px” Height=”22px” AutoPostBack=”True” DataTextField=”ShipCountry” DataValueField=”ShipCountry” AppendDataBoundItems=”True”> <asp:ListItem>[Select a Country]</asp:ListItem> </asp:DropDownList> <asp:SqlDataSource ID=”dsCountries” Runat=”server” SelectCommand=”SELECT DISTINCT [ShipCountry] FROM [Orders] ORDER BY [ShipCountry]” ConnectionString=”<%$ ConnectionStrings:NorthwindConnection %>”> </asp:SqlDataSource> 256 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 257 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 Al añadir la restricción de cláusula WHERE se inserta la siguiente definición de ControlParameter en el código fuente de dsOrders<asp:SQLDataSource...>: <SelectParameters> <asp:ControlParameter Name=”ShipCountry” DefaultValue=”USA” Type=”String” ControlID=”ddlCountry” PropertyName=”SelectedValue”></asp:ControlParameter> </SelectParameters> 7.3.5 Editar ítems en listas de datos Editar elementos en una lista puede ser algo pesado para los usuarios, especialmente si la lista tiene un largo número de ellos. Con el control GridView o DetailsView los datos se pueden editar mucho más rápidamente y de manera más simple, ya que es el diseñador quien crea las plantillas necesarias para editar, insertar y borrar datos. En los apartados posteriores de este capítulo se describen las propiedades de los nuevos controles GridView y DetailsView. Con ellos también habrá que escribir código para obtener los valores originales y actualizados en el manejador de evento DataList_UpdateCommand y asignarlos como valores (miembros) de (la colección) DataSource.Command.Parameters en el manejador de evento DataSource_Updating. El siguiente código oculto del archivo EditableDataList.aspx.vb del proyecto de ejemplo DataWebSite, obtiene y asigna los valores de los parámetros para actualizar un elemento seleccionado: Public Sub dlOrders_UpdateCommand(ByVal source As Object, _ ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) _ Handles dlOrders.UpdateCommand 'Read-only OrderID value Dim strOrderID As String = dlOrders.DataKeys(e.Item.ItemIndex).ToString Dim strCustomerID As String = Nothing Dim txtBox As TextBox Dim strTextBox As String = Nothing Dim intParam As Integer alParamValues = New ArrayList For intParam = 0 To dsOrders.UpdateParameters.Count - 1 strTextBox = "TextBox" + (intParam + 2).ToString txtBox = CType(e.Item.FindControl(strTextBox), TextBox) If intParam = dsOrders.UpdateParameters.Count - 1 Then '@original_OrderID alParamValues.Add(strOrderID) Else If txtBox Is Nothing Then alParamValues.Add(Nothing) Else 'Other parameter values If txtBox.Text.Contains("$") Then 'Remove currency symbol for freight alParamValues.Add(Mid(Trim(txtBox.Text), 2)) 257 VisualBasic2005_07.qxp 02/08/2007 16:28 PÆgina 258 Bases de datos con Visual Basic Else alParamValues.Add(Trim(txtBox.Text)) End If End If End If Next 'Execute the Update method dsOrders.Update() 'Return to Item mode dlOrders.EditItemIndex = -1 dlOrders.DataBind() End Sub Protected Sub dsOrders_Updating(ByVal sender As Object, _ ByVal e As System.Web.UI.WebControls.SqlDataSourceCommandEventArgs) _ Handles dsOrders.Updating Try Dim strUpdateCmd As String = e.Command.CommandText Dim intCtr As Integer For intCtr = 0 To e.Command.Parameters.Count - 1 Dim strName As String = e.Command.Parameters(intCtr).ParameterName If alParamValues(intCtr).ToString = "" Or alParamValues(intCtr) Is Nothing Then e.Command.Parameters(intCtr).Value = DBNull.Value Else e.Command.Parameters(intCtr).Value = alParamValues(intCtr) End If Next Catch exc As Exception 'Ignore End Try End Sub Si decide ampliar la capacidad de edición de una lista de datos, puede añadir una plantilla EditItem a la lista copiando la plantilla Item en la plantilla EditItems y substituyendo las etiquetas por cuadros de texto. Deberá añadir botones para activar la plantilla EditItem, actualizar la DataSource, o cancelar la operación de actualización. A diferencia de los botones que se añadirán a los controles FormView en el apartado siguiente, ahora debe añadir manejadores para los eventos EditCommand, UpdateCommand, y CancelCommand en la página o en el código oculto del archivo. La siguiente figura muestra la página EditableDataList.aspx del proyecto de ejemplo con un elemento en modo edición. Para este y otros muchos ejemplos de este capítulo, todos los manejadores de evento se encuentran en el código oculto del archivo. 258 VisualBasic2005_07.qxp 02/08/2007 16:29 PÆgina 259 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 7.4 El control FormView El control FormView permite diseñar libremente la plantilla Item. Por ejemplo, le permite añadir una tabla multicolumna a la plantilla y después cortar y pegar el texto por defecto de ColumnName y los controles ColumnNameLabel en las celdas de la tabla. Y puede especificar el estilo de los bordes de celda, el ancho y el color, así como colores de fondo para etiquetas. FormView es una alternativa mucho más flexible que los controles GridView o DetailsView para actualizar y añadir registros a las tablas base. El proceso de añadir un control FormView y su SqlDataSource a una página es casi idéntico al de GridView. Cuando se utiliza FormView para editar datos de una tabla base, es una buena práctica añadir todas las columnas de la tabla a la fuente de datos. 7.4.1 Paginar la fuente de datos El control FormView soporta la paginacion, lo que permite seleccionar un registro específico y mostrarlo o editarlo. Para hacer posible la paginación, abra la ventana Propiedades para FormView y asigne el valor True a la propiedad AllowPaging. PagerSettings tiene por defecto un juego de diez valores númericos secuenciales y botones para seleccionar los diez valores anteriores o siguientes, pero puede darle a la propieadad Mode del paginador el valor NumericFirstList y después escribir First y Last como valores de las propiedades FirstPageText y LastPageText. Finalmente, amplíe el nodo PagerStyle y defina los valores del nodo Font para resaltar el paginador en la parte inferior del formulario (ver la siguiente figura). 259 VisualBasic2005_07.qxp 02/08/2007 16:29 PÆgina 260 Bases de datos con Visual Basic Paginar es una operación que consume muchos recursos, sobre todo en tablas con muchos registros de datos. Al pulsar cualquier botón del paginador se ejecuta SelectCommand y se restablecen todas las filas de la base de datos en el servidor que cumplen el criterio de la cláusula WHERE, si existe. Filtrar registros con una cláusula WHERE generada por las listas desplegables, normalmente es el método más efectivo para reducir el tamaño de los resultados devueltos por la consulta SelectCommand. Con los registros en orden secuencial, se puede minimizar el consumo de recursos añadiendo un modificador TOP n y una cláusula ORDER BY a la sentencia SQL del SelectCommand. 7.4.2 Remplazar los valores Null por texto específico de la columna El siguiente código oculto de la página FormView.aspx añade los elementos Pending y <Empty> text que remplazan valores nulos por valores ShippedDate, ShipRegion y ShipPostalCode ausentes en la plantilla Item: Partial Class FormView Inherits System.Web.UI.Page Protected Sub fvOrders_DataBound(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles fvOrders.DataBound 'Add default values for null ShippedDate, ShipRegion, and ShipPostalCode 'Disable deletion of shipped orders Dim strUpdateCmd As String = dsFormView.UpdateCommand Try If IsDBNull(Me.fvOrders.DataItem("ShippedDate")) Then Dim lblDate As Label = CType(fvOrders.FindControl("ShippedDateLabel"), Label) If Not lblDate Is Nothing Then 260 VisualBasic2005_07.qxp 02/08/2007 16:29 PÆgina 261 Trabajar con las fuentes de datos y controles vinculados de ASP.NET 2.0 lblDate.Text = "Pending" End If 'Enable deletion of orders not shipped Dim btnDelete As Button = CType(fvOrders.FindControl("btnDelete"), Button) If Not btnDelete Is Nothing Then btnDelete.Enabled = True End If 'Temporary workaround for null date problem Dim txtDate As TextBox = CType(fvOrders.FindControl("ShippedDateTextBox"), TextBox) If Not txtDate Is Nothing Then txtDate.Text = "1/1/2099" End If Else 'Disable deletion of shipped orders Dim btnDelete As Button = CType(fvOrders.FindControl("btnDelete"), Button) If Not btnDelete Is Nothing Then 'Temporary for null date workaround Dim lblDate As Label = CType(fvOrders.FindControl("ShippedDateLabel"), Label) If lblDate.Text = "Pending" Then btnDelete.Enabled = True Else btnDelete.Enabled = False End If End If End If If IsDBNull(fvOrders.DataItem("ShipRegion")) Then Dim lblRegion As Label = CType(fvOrders.FindControl("ShipRegionLabel"), Label) If Not lblRegion Is Nothing Then lblRegion.Text = "&lt;Empty&gt;" End If End If If IsDBNull(fvOrders.DataItem("ShipPostalCode")) Then 'Applies to Ireland only Dim lblCode As Label = CType(fvOrders.FindControl("ShipPostalCodeLabel"), Label) If Not lblCode Is Nothing Then lblCode.Text = "&lt;Empty&gt;" End If End If Catch exc As Exception 'Ignore for now End Try 261