¡Esta es una revisión vieja del documento!
Desde VS2008 podemos crear controles enlazados a datos simplemente arrastrando tablas desde el administrador de servidores al editor de ficheros .dbml y utilizar este como fuente de datos.
Entre los siguiente posteriormente nombrados también existe el LinqDataSource.
Podemos crear también una base de datos propia de nuestro proyecto, para ello agregaríamos el fichero .MDF y el .LDF (si tratamos con DB SqlServer) a la carpeta App_Data de la aplicación web. Este directorio es una ruta segura ya que su contenido no se hace público, puede sernos útil también para almacenar ficheros XML. A las cadenas de conexión para DB locales agregaremos la propiedad AttachDbFileName, que especifica la ubicación del fichoer de DB. Si a la ruta |DataDirectory| esto se sustituirá por el path del directorio App_Data en tiempo de ejecución. La propiedad User Instance=true indica que cada usuario ejecutará un nuevo proceso para atacar a la DB.
"server=(local)\SQLExpress;AttachDbFileName=|DataDirectory|MyDatabase.mdf;Integrated Security=true;User Instance=true"
El control SqlDataSource representa una conexión a DB que puede ser utilizada por los demás controles en la página.
Por ejemplo, en el siguiente código, un GridView sse enlaza a un SqlDataSource:
<form runat="server"> <asp:GridView ID="GridView1" DataSourceID="SqlDataSource1" runat="server"/> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> </form>
Propiedades útiles:
UpdateCommand o DeleteCommand deben contener parámetros de substitución para cada valor que pasarán otros controles enlazados a él, podemos especificar también una colección de UpdateParameters o DeleteParameters para establecer las propiedades de cada parámetro, tales como el tipo de parámetro, la dirección de entrada/salida o el valor por defecto.
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:Pubs %>"
SelectCommand="SELECT [au_id], [au_lname], [au_fname], [state] FROM [authors]"
UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [state] = @state WHERE [au_id] = @au_id"
DeleteCommand="DELETE FROM [authors] WHERE [au_id] = @au_id"/>
Para realizar un filtrado de datos necesitamos agregar objetos DataParameter, estos permiten asociar valores externos a operaciones, variables o porpiedades.
<asp:DropDownList ID="DropDownList1" ... runat="server"/> ... <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:Pubs %>" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [state] FROM [authors] WHERE [state] = @state"> <SelectParameters> <asp:ControlParameter Name="state" ControlID="DropDownList1" PropertyName="SelectedValue" /> </SelectParameters> </asp:SqlDataSource>
Los tipos que podemos asignar como parámetros son:
Parameter: Clase base.QueryStringParameter: Parámetro de la query string.ControlParameter: Parámetro en un control.SessionParameter: Parámetro en una variable de sesión.FormParameter: Parámetro en un control HTML.CookieParameter: Parámetro en una cookie.ProfileParameter: Parámetro en el perfil.
El ObjectDataSource enlaza objetos de forma similar a que el SqlDataSource, tiene una propiedad TypeName que indica el tipo de objeto que realizará las operaciones y a la vez tiene propiedades como el SelectMethod, el UpdateMethod, el InsertMethod y el DeteMethod para realizar las tareas que describen. Es decir, una clase como la siguiente:
public class MyProductsLayer { public DataView GetProducts(); public DataView GetProductsByCategory(String categoryName); public DataView GetProductsByID(int recordID); public int UpdateProduct(int recordID, String recordData); public int DeleteProduct(int recordID); public int InsertProduct(int recordID, String recordData); public UpdateProduct (Product p); }
Puede enlazarse con un ObjectDataSource de la siguiente forma:
<asp:ObjectDataSource TypeName="MyProductLayer" SelectMethod="GetProductss" UpdateMethod="UpdateProduct" DeleteMethod="DeleteProduct" InsertMethod="InsertProduct" runat="server"/>
Podemos utilizar los <%# %> para enlazar datos en una página .aspx, todas las expresiones de enlace de datos deben ir incluidas entro de estos carácteres. Ejemplos:
<%# custID %><asp:ListBox id=“List1” datasource='<%# myArray %>' runat=“server”><%# ( customer.First Name + “ ” + customer.LastName ) %><%# GetBalance(custID) %>
Eval es una función estática de System.Web.UI.DataBinder que puede ser utilizada en archivos de code-inline dentro de un entorno de enlace de datos. Por ejemplo en un GridView, en un TemplateField añadimos el nombre completo de una persona concatenando distintos campos de un registro:
<asp:TemplateField HeaderText="Name"> <ItemTemplate> <%# Eval("TitleOfCourtesy") %> <%# Eval("FirstName") %> <%# Eval("LastName") %> </ItemTemplate> </asp:TemplateField>
Eval también permite formatear el resultado que va a mostrar:
<%# Eval("BirthDate", "{0:MM/dd/yy}") %> ... <ItemTemplate> <br /> <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%# Eval("PhotoID", "PhotoFormViewPlain.aspx?ID={0}") %>'> <asp:Image ID="Image1" Runat="server" ImageUrl='<%# Eval("FileName", "images/thumbs/{0}") %>' /></asp:HyperLink> <br /> <asp:Label ID="CaptionLabel" runat="server" Text='<%# Eval("Caption") %>' /> </ItemTemplate> ... <%# Eval("Price", "Special Offer {0:C} for Today Only!") %>
Eval equivale a utilizar:
<%# DataBinder.Eval(Container.DataItem, "field_name") %>
Bind realiza la misma función que Eval, pero se diferencia con este en que no solo es de lectura sino también de actualización, es decir, muestra los datos y si es necesario también los actualiza en el servidor. Si sólo queremos mostrar los datos utilizaremos Eval pero si también queremos que se actualicen Bind:
<asp:TemplateField HeaderText="Name"> <EditItemTemplate> <asp:TextBox ID="txtName" Text='<%# Bind("Name")%>' runat="server"></asp:TextBox> </EditItemTemplate> </asp: TemplateField> <asp:TemplateField HeaderText="User Id"> <ItemTemplate> <asp:Label ID="lblUserId" Text='<%# Eval("UserId") %>' runat="server"> </ItemTemplate> </asp: TemplateField>
Sólo puede utilizarse con los controles GridView, DetailsView y FormView.
La táctica del master-detail consiste en selección de un control como “master” que indicará qué detalles se mostrarán en el\los details.
El GridView contiene la propiedad SelectedValue que indica la fila seleccionada, está contiene el primer valor del campo especificado en la propiedad DataKeyNames. Para permitir la selección la propiedad AutoGenerateSelectButton ha de estar a true o la ShowSelectButton del CommandField también como true. Una vez hecho esto la propiedad SelectedValue puede ser asociada a un ControlParameter y mostar los detalles en el control Details View, que presenta los valores de un registro de forma tabulada.
El control DetailsView también soporta la edición, para ello se utilizan las propiedades AutoGenerateEditButton o CommandField.ShowEditButton y la fuente de datos tendrá que soportar la actualización.
Para que, por ejemplo, el DetailsView se enlace a un hipervínculo (QueryStringParameter) añadiremos un objeto HyperLinkField al grupo de columnas del GridView, la propiedad Text de este será el texto a mostrar y la NavigateUrl la dirección a la que se irá tras clickar en el enlace. Esto generaría una url estática comú para todos los campos, por lo que mejor sería especificar un NavigateUrlFields, su propiedad NavigateUrlFormatString espcifica el formato de la url donde {0} y {1} se sustituyen por los valores del campo.
<asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" Runat="server" DataSourceID="SqlDataSource1" DataKeyNames="au_id" AutoGenerateColumns="False"> <Columns> <asp:BoundField ReadOnly="true" HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:HyperLinkField HeaderText="View Details..." Text="View Details..." DataNavigateUrlFields="au_id" DataNavigateUrlFormatString="DetailsView_cs.aspx?ID={0}" /> </Columns> ...
Una propiedad que tiene el DetailsView que no tiene el GridView es que puede insertar, para ello el DataSource enlazado debe permitir la inserción, la propiedad AutoGenerateInsertButton a true o añadir al grupo de campos del DetailsView un CommandField con el ShowInsertButton establecido a true. Para excluir un campo en el modo de Inserción, tendremos que establecer la propiedad InsertVisible del campo a false.
AutoGenerateColumns si se pone a false impedirá que se agreguen columnas automáticamente.AllowSorting a true. Ésto provoca que el control GridView cree botones de enlazado para las cabeceras de sus columnas. El control GridView pasa la expresión SortExpression asociada con el campo de la columna al control de la fuente de datos para ello.AllowPaging a true. PagerStyle y PagerSettings respectivamente. PagerStyle determina el aspecto del paginador, mientras que PagerSettings determina el tipo de paginación a usar (numérica o con botones Siguiente/anterior), la posición y otras opciones. AutoGenerateEditButton y AutoGenerateDeleteButton a true, o añadir un CommandField al control GridView y habilitar sus propiedades ShowEditButton y ShowDeleteButton. ReadOnly de una columna a true estamos indicando que ese campo no podrá ser editable.DataControlField):BoundField, columna enlazada a datos.CheckBoxField, columna enlazada a datos true\false.ImageField, columna enlazada a imágen.HyperLinkField, mediante la cual aparece un link. Podemos indicar:DataTextField.DataNavigateUrlFormaString y si esta dependerá de un cambo de la DB también con la propiedad DataNavigateUrlFields.<asp:hyperlinkfield datatextfield="lang2" datanavigateurlfields="id" datanavigateurlformatstring="AddElement.aspx?id={0}" />
CommandField. ButtonField. TemplateField, columna configurable.
Ejemplo de GridView enlazado a datos:
<asp:GridView ID="GridView1" DataSourceID="SqlDataSource1" AutoGenerateColumns="False" runat="server"> <Columns> <asp:BoundField HeaderText="First Name" DataField="au_fname" /> <asp:BoundField HeaderText="Address" DataField="address" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" /> <asp:CheckBoxField HeaderText="Contract" DataField="contract" /> </Columns> </asp:GridView>
Ejemplo de GridView que se enlazará a una lista de objetos con una propiedad nombre y que mostrará también un combo. Este DropDownList no cambia, pero podría hacerlo si se escribe el evento OnRowCreated y cada vez que se ejecute se coge este control DropDownList y se cambia en código.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"> <Columns> <asp:BoundField DataField="nombre" HeaderText="nombre" /> <asp:TemplateField HeaderText="apellido"> <ItemTemplate> <asp:DropDownList runat="server"> <asp:ListItem>Activo</asp:ListItem> <asp:ListItem>Inactivo</asp:ListItem> </asp:DropDownList> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView>
Es decir, teniendo un código del estilo:
GridView1.DataSource = from c in customers, o in c.Orders, total = o.Total where total >= 2000 select new {id = c.CustomerID, order = o.OrderID, total = total}; GridView1.DataBind();
En el RowCreated no podremos hacer algo así:
object element = e.Row.DataItem; int id = element.id;
Lo que deberíamos hacer sería crear una clase, aunque sea interna:
public class GridType { public int Id {get; set;} ... }
Al agregarlo, en este caso con Linq:
... select new GridType {id = ...}
Y en el RowCreated:
GridType element = e.Row.DataItem as GridType; int id = element.Id;
El siguiente grid tiene:
hyperlinkfields, mediante ControlStyle-CssClass.HeaderStyle-CssClass.ItemStyle-CssClass.gridHeader a { color: white; text-decoration: none; } .<asp:GridView id="grid" runat="server" Width="100%" AutoGenerateColumns="false" BorderColor="#8FA2B7" AllowSorting="true"> <Columns> <asp:hyperlinkfield datatextfield="lang1" datanavigateurlfields="id" datanavigateurlformatstring="AddElement.aspx?id={0}" ControlStyle-CssClass="gridElement" HeaderStyle-CssClass="gridHeader"/> <asp:hyperlinkfield datatextfield="lang2" datanavigateurlfields="id" datanavigateurlformatstring="AddElement.aspx?id={0}" ControlStyle-CssClass="gridElement" HeaderStyle-CssClass="gridHeader"/> <asp:BoundField HeaderText="errors" DataField="errors" ItemStyle-CssClass="gridElement" HeaderStyle-CssClass="gridHeader" SortExpression="errors"/> <asp:BoundField HeaderText="rights" DataField="rights" ItemStyle-CssClass="gridElement" HeaderStyle-CssClass="gridHeader"/> </Columns> </asp:GridView>
this.grid.Columns[3].ItemStyle.HorizontalAlign = System.Web.UI.WebControls.HorizontalAlign.Right;THEAD y TBODY: this.GridView1.HeaderRow.TableSection = TableRowSection.TableHeader;
Es un control al cual se le pasa como DataSource una lista de elementos y este las muestra, no en formato tabla como el grid sino en el formato que elija el programador. Para ello hay que rellenarlo con objetos Template siguientes:
ItemTemplate, para cada línea.AlternatingItemTemplate, como el ItemTemplate pero alternando las líneas.HeaderTemplate, antes de la lista de ItemTemplate.FooterTemplate, después de la lista de ItemTemplate.SeperatorTemplate, elementos entre cada línea (entre ItemTemplates y AlternatingItemTemplate).Por ejemplo un repeater que muestra en una tabla los elementos de una lista asignada como DataBound:
<asp:Repeater runat="server" ID="myRepeater"> <HeaderTemplate> <table> </HeaderTemplate> <ItemTemplate> <tr> <td> <%#DataBinder.Eval(Container.DataItem, "nombre") %> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:Repeater>
Para crear Repeaters anidados, es decir, uno dentro del ItemTemplate de otro. En el primero definiríamos el evento OnItemDataBound o el OnItemCreated y en su método buscaríamos el Repeater anidado dentro del objeto creado:
private void rCanciones_ItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e) { if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) { string disco = (string)e.Item.DataItem; string[] canciones = new string[]{"canción 1","canción 2","canción 3"}; Repeater rCanciones = (Repeater)e.Item.FindControl("rCanciones"); rCanciones.DataSource = canciones; rCanciones.DataBind(); } }
Es la propiedad que permite al control lanzar eventos mediante PostBack (recargando la página).
Podemos enviar un comando desde un control anidadado y que después será interceptado por el método OnCommand; por ejemplo en un Repeater, desde un LinkButton anidado que en vez de cargar una página utilizando sus propiedades CommandName y la CommandArgument se indicará que se ha elegido, la primera propiedad es para indicar un string identificador del comando y la segunda para el argumento.
En el siguiente ejemplo se envia el comando LineEdition con el identificador del DataItem cargado dentro del Repeater .
<asp:Repeater ID="linesRepeater" runat="server" OnItemCommand="Repeater1_ItemCommand" OnItemCreated="Repeater2_ItemCreated"> ... <ItemTemplate> <tr> <td class="littleTextCell"><%# DataBinder.Eval(Container.DataItem, "linia") %></td> <td><asp:LinkButton ID="LinkButton1" runat="server" CssClass="textButtonCell" CommandName="LineEdition" CommandArgument="<%# (codegest.panelgest.show_panel_temp.innerGridItem)Container.DataItem).id %>">Editar linia</asp:LinkButton> </td> </tr> </ItemTemplate>
Luego, desde el método Repeater1_ItemCommand del code-behind:
if (e.CommandName == "LineEdition") { int codi = Int32.Parse(e.CommandArgument.ToString()); ...
Si vamos a agregar elementos de la base de datos a nuestro control DropDownList, a parte de los introducidos manualmente, tendremos que utilizar la propiedad AppendDataBoundItems, sino estos se eliminarán.
<asp:DropDownList runat="server" Width="50px" ID="tipus" AppendDataBoundItems="true"> <asp:ListItem Value="0" Text="Todos" /> </asp:DropDownList></td>
Un Web User Control es un control que crea el programador y que se puede reutilzar en las páginas asp.net, son clases que heredan de System.Web.UI.UserControl que a su vez hereda de System.Web.UI.TemplateParser y se guardan en archivos .ascx.
Para utilizar el control en nuestro formulario web de usuario primero tendremos que registrarlo a partir de la tag Register. La propiedad TagPrefix de esta indica un espacio de nombres único para el control dentro del .aspx, la TagName es el nombre por el cual nos referiremos a él y la Src es la página donde se encuentre el fichero.
<%@ Register TagPrefix="Acme" TagName="Message" Src="pagelet1.ascx" %>
Luego podremos utilizar el control haciendo: <namespace:nombre_control runat=“server” />:
<Acme:Message runat="server" />
Al igual que los web forms los user controls pueden contener code-behind. Si en este ponemos propiedades públicas podremos acceder a ellas a partir de las tags en el .aspx:
Código en el .ascx:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs" Inherits="WebApplication7.WebUserControl1" %> <asp:Label ID="lbl" runat="server"></asp:Label>
public partial class WebUserControl1 : System.Web.UI.UserControl { public String texto = ""; public String Text { set { this.text = value; } get { return this.text; } } protected void Page_Load(object sender, EventArgs e) { this.lbl.Text = this.texto; } }
Código en el .aspx:
... %@ Register TagPrefix="ctrl" TagName="webcontrol" Src="WebUserControl1.ascx" %> ... <ctrl:webcontrol runat="server" texto="hasodfasdf" /> ...
Luego también podremos agregarlo a partir del código:
Control c1 = LoadControl("userctrl7.ascx"); ((UserCtrl7)c1).Category = "business"; Page.Controls.Add(c1);
El tipo El nombre de la clase generada por el control lo podemos definir a partir de la propiedad ClassName de la tag Control:
<%@ Control ClassName="UserCtrl7" %>
Crear url relativa correctamente:
<script type="text/javascript" src="<%= ResolveClientUrl("~/jscripts/libs/jquery.js") %>"></script>
Aunque ASP.NET permite el uso de HTML standard, utilizarlo no aprovecha al máximo las capacidades de la tecnología de MS pero sin él nos es más complejo agregar código JavaScript.
Tenemos la siguiente función JavaScript que valida si el campo firtName tiene algún valor introducido. Si es así retornará true si no mostrará un mensaje y retornará false.
<script language="javascript" type="text/javascript"> function validate() { var doc = document.forms[0]; if (doc.firstName.value == "") { alert("No pasarás!"); return false; } return true; } </script> ... <asp:TextBox ID="firstName" runat="server"></asp:TextBox> <asp:Button ID="Button1" runat="server" Text="Button" />
El siguiente código agrega código a la función OnClick que devuelve lo que la función validate que acabamos de ver retorna:
protected void Page_Load(object sender, EventArgs e) { this.Button1.OnClientClick = "return validate()"; }
Otra forma de hacer lo mismo desde el code behind:
this.Button1.Attributes.Add("onClick", "return validate()");
Ejemplo parecido al anterior. Tenemos una función JavaScript que copia el contenido de un textbox a otro:
function copy() { var doc = document.forms[0]; doc.lastName.value = doc.firstName.value; }
El código html\asp:
<asp:TextBox ID="firstName" runat="server"></asp:TextBox> <asp:TextBox ID="lastName" runat="server"></asp:TextBox> <asp:Button ID="Button1" runat="server" Text="Button" />
Y el código que agrega el keypress:
this.firstName.Attributes.Add("onkeyup", "copy()");
<body onload="load_body()">
Y esa función sería:
function load_body() { var doc = document.forms[0]; doc.firstName.onkeypress = copy; }
O…
function load_body() { var doc = document.forms[0]; doc.firstName.onkeypress = function copy2() { var doc = document.forms[0]; doc.lastName.value = doc.firstName.value; } }
<script src="jquery.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function() { $('#firstName').keypress(function() { var doc = document.forms[0]; doc.lastName.value = doc.firstName.value; }); }); </script>
ASP.NET crea código en JavaScript que realiza la acción de PostBack, de esta forma los controles web pueden llamarlo. Desde código no gestionado por ASP.NET podemos llamarlo de la siguiente forma: el nombre de la función que hace el PostBack es __doPostBack y se le pasan dos argumentos: quien hace el PostBack y con qué argumento:
__doPostBack('__Page', 'MyCustomArgument');
Aún así no es recomendable llamar a este método directamente, lo mejor es hacer que ASP.NET genere su llamada, para ello podríamos crear en el code behind una variable protegida:
protected string strPostBack;
Y en el mismo método PageLoad podremos crear la llamada dinámicamente a partir del método: Page.ClientScript.GetPostBackEventReference.
this.strPostBack = Page.ClientScript.GetPostBackEventReference(this, "argumentoTest");
Y en el código JavaScript\jQuery:
<script type="text/javascript"> $(document).ready(function() { $('#clickmeupdate').click(function() { <%= strPostBack %>; }); }); </script>
Luego podremos capturar este argumento de la siguiente forma:
if ((Page.IsPostBack) && (Request["__EVENTARGUMENT"] == "argumentoTest")) this.clickmeupdate.InnerText = "Se ha hecho PostBack";
Para saber la id de un control posicionado en una página que utiliza master pages usaremos la propiedad ClientID del control:
var edited = $('#<%= fieldEddited.ClientID %>').val();