miércoles, 29 de septiembre de 2010

Configuración de VS2010 para trabajar con Azure mediante entorno simulado.

Hola!

Este es mi primer post, y he decidido escribir sobre algo con lo que estamos ahora mismo trabajando/investigando: Windows Azure.

¿y qué es eso? pues copieteando a la wikipedia: “Windows Azure Platform de Microsoft  es una plataforma de servicios que ofrece computación en nube, entró en producción el 1 de enero de 2010. "Ofrece una amplia gama de servicios de internet que se pueden consumir tanto desde entornos locales o en entornos de internet" (aunque la plataforma en sí no está disponible para implementar en los entornos locales). Es significativo que es el primer paso de Microsoft en la computación en nube después del lanzamiento de Microsoft Online Services.”

Vamos, a mi modo de ver, un megahosting de Microsoft, perfectamente integrado con todas sus herramientas de desarrollo y que nos permite desplegar aplicaciones en la nube de una manera muy rápida y aparentemente, sencilla… Pero claro, primero tendremos que configurar nuestro entorno de trabajo ¿no?.

Microsoft nos da (que buenos son) la posibilidad de montar un entorno de simulación localmente, gracias a las herramientas de desarrollo de Azure y a su SDK. vamos a ver como montarlo y tener configuradito nuestro querido VS2010.

Vayamos por partes, como dijo no se quien:

  • Descarga e instalación de herramientas y SDK de Azure para VS 2010. (http://www.microsoft.com/windowsazure/). Estas herramientas también se pueden descargar directamente desde el IDE de VS 2010.
  • Si es necesario, instalar los HotFix que Microsoft recomienda.
  • Instalación de SQL Express 2008 en la máquina de desarrollo. Es necesario para que Azure simule su almacenamiento Blob, Queue y Table.

Para comprobar que el entorno de desarrollo y la simulación local de Azure funcionan correctamente, realizaremos los siguientes pasos:

Ejecutaremos el entorno de desarrollo como administrador:

image

Crearemos un proyecto de prueba desde VS 2010. El tipo de proyecto Windows Azure Cloud Service estará disponible después de instalar las herramientas de desarrollo y el SDK.

 

image

Añadiremos al proyecto un WebRole de VB o C#.

 

image

Una vez hecho esto, tendremos (o deberíamos tener) los siguientes elementos en nuestra nueva solución

 

image

A continuación podemos ejecutar el proyecto. El entorno de simulación de Azure se inicializará y tendremos en nuestra área de notificaciones un icono que nos permite comprobar el estado de los componentes de dicho entorno de simulación.

image

¡Nuestro entorno está correctamente configurado!

En lo siguientes post (si el tiempo, las ganas y demás factores alienantes me lo permiten), ampliaré conceptos sobre Azure y la manera de trabajar con él. De momento, palabras como Blob, Qeue, Table y otros conceptos “azurescos” los dejaremos para otro día.

Life is code!!

jueves, 23 de septiembre de 2010

¿Qué control enlazado a datos y cuándo?

Control

Paginación

Empty

CRUD

Seleccionar

Registros

Html

Repeater

No

No

No

No

1

No

DetailsView

No

1

Sí (tabla)

FormView

No

1

No

DataList

No

Update, Delete.

Varios

No

ListView

Varios

No

 

Repeater

  • Ventajas
    • Salida html totalmente personalizada.
    • Plantilla para cada elemento (header, footer, separator, etc.)
  • Desventajas
    • No tiene una plantilla de no hay registros, pero esto se soluciona aquí http://www.flixon.com/Articles/18.aspx
    • No admite paginación
    • Su SmarTag no genera automáticamente nada
    • Es one-way data binding, es decir, no admite Bind
  • Escenarios
    • Mostrar 1 registro en sólo-lectura (se aconseja mejor que DetailsView y FormView porque Repeater es más ligero)
    • Mostrar n registros en sólo-lectura siempre que no sean muchos ya que no pagina
    • Mostrar 1 o n registros en sólo-lectura con un alto grado de personalización

DetailsView

  • Ventajas
    • Salida html predeterminada
    • Admite paginación
    • Es two-way data binding
    • Su SmarTag genera automáticamente los BoundField necesarios
    • CRUD completo
  • Desventajas
    • No tiene plantilla para el elemento activo (sólo tiene para header, footer, etc.), se rige por BoundFields
    • CRUD automático según el control origen de datos
  • Escenarios
    • Mostrar 1 registro, con independencia del CRUD requerido
    • Mostrar n registros, con independencia del CRUD requerido, ya que permite paginación
    • Maestro-detalle en conjunción con GridView o similar

FormView

  • Ventajas
    • Salida html totalmente personalizada
    • Admite paginación
    • Es two-way data binding
    • Su SmarTag genera automáticamente las plantillas necesarias
    • CRUD completo
  • Desventajas
    • CRUD automático según el control origen de datos
  • Escenarios
    • Mostrar 1 registro, con independencia del CRUD requerido
    • Mostrar n registros, con independencia del CRUD requerido, ya que permite paginación
    • Mostrar 1 o n registros, , con independencia del CRUD requerido, ya que permite paginación y en los que es necesario un alto grado de personalización
    • Maestro-detalle en conjunción con GridView o similar

DataList

  • Ventajas
    • Salida html totalmente personalizada
    • Es two-way data binding
    • Su SmarTag genera automáticamente las plantillas necesarias
    • Orientación vertical u horizontal
  • Desventajas
    • No admite paginación
    • CRUD parcial (no admite inserción)
  • Escenarios
    • Mostrar n registros, con CRUD limitado y cuidado ya que no permite la paginación

ListView

  • Ventajas
    • Salida html totalmente personalizada
    • Es two-way data binding
    • Su SmarTag genera automáticamente las plantillas necesarias
    • Soporte agrupación
    • Admite paginación
    • CRUD completo
  • Desventajas
    • CRUD automático según el control origen de datos
  • Escenarios
    • Mostrar n registros, con CRUD completo, con paginación y con un alto grado de personalización.

Como curiosidad, se puede ver como Telerik y su control RadGrid intentan emular el comportamiento de un ListView http://demos.telerik.com/aspnet-ajax/grid/examples/programming/listview/defaultcs.aspx

Si quieres ampliar información sobre el control ListView, he escrito este otro post donde cuento porqué es a mi juicio, el mejor y más configurable de los controles enlazados a datos.

Un saludo!

Controles enlazados a datos, lidiando con el CRUD automático

Hay algunos controles enlazados a datos que son muy buenos, pero lo que a priori sería algo bueno después se convierte en un obstáculo a vencer. Estoy hablando de las inserciones, actualizaciones y eliminaciones automáticas.

Esto quiere decir que controles como DetailsView, FormView o ListView, esperan que sus respectivos controles de origen de datos tengan comandos de inserción, actualización o eliminación. En caso de no ser así tendremos un bonito error que indica que sin estos comandos no pueden brindarnos esta funcionalidad automática de manipulación del registro activo.

Por ejemplo, en el caso de querer actualizar un registro en un ListView y asumiendo que no queremos actualización automática y por ende nuestro control de origen de datos no tiene un UpdateCommand, obtenemos el siguiente error:

clip_image002

Querer utilizar estos controles (DetailsView, FormView o ListView) y no querer inserciones, actualizaciones y eliminaciones automáticas es un problema pero no es imposible. Para solucionarlo lo que tenemos que hacer es:

  • Interceptar el evento previo (acabado en –ing) adecuado a la operación solicitada
  • Llevar a cabo nuestra lógica de manipulación propia
  •  Cancelar el evento para que el evento asociado posterior (acababo en –ed) no salte
  • Dejar el control en la misma situación que lo hubiera dejado el evento posterior (acabado en –ed) para que ni el usuario ni ASP.NET (nuestro querido amigo) se quejen de nada y no noten el cambiazo sutil que hemos dato.

Para implementar nuestra propia lógica de actualización en un control DetailsView:

    Protected Sub DetailsView1_ItemUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdateEventArgs) Handles DetailsView1.ItemUpdating

        Dim cnn As New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings.Item("WebSiteJBellidoConnectionString").ConnectionString)

        cnn.Open()

        Dim sql As String = _

            "UPDATE Municipios SET Municipio = 'MODIFICADO' WHERE CodigoMunicipio = '" & e.Keys.Item("CodigoMunicipio") & "'"

        Dim cmd As New System.Data.SqlClient.SqlCommand(sql, cnn)

        cmd.ExecuteNonQuery()

        cmd.Dispose()

        cnn.Close()

        e.Cancel = True

        DetailsView1.ChangeMode(DetailsViewMode.ReadOnly)

        DetailsView1.DataBind()

    End Sub

Para implementar nuestra propia lógica de actualización en un control FormView:

    Protected Sub FormView1_ItemUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.FormViewUpdateEventArgs) Handles FormView1.ItemUpdating

        Dim cnn As New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings.Item("WebSiteJBellidoConnectionString").ConnectionString)

        cnn.Open()

        Dim sql As String = _

            "UPDATE Municipios SET Municipio = 'MODIFICADO' WHERE CodigoMunicipio = '" & e.Keys.Item("CodigoMunicipio") & "'"

        Dim cmd As New System.Data.SqlClient.SqlCommand(sql, cnn)

        cmd.ExecuteNonQuery()

        cmd.Dispose()

        cnn.Close()

        e.Cancel = True

        FormView1.ChangeMode(FormViewMode.ReadOnly)

        FormView1.DataBind()

    End Sub

Para implementar nuestra propia lógica de actualización en un control ListView:

    Protected Sub ListView1_ItemUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewUpdateEventArgs) Handles ListView1.ItemUpdating

        Dim cnn As New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings.Item("WebSiteJBellidoConnectionString").ConnectionString)

        cnn.Open()

        Dim sql As String = _

            "UPDATE Municipios SET Municipio = 'MODIFICADO' WHERE CodigoMunicipio = '" & e.Keys.Item("CodigoMunicipio") & "'"

        Dim cmd As New System.Data.SqlClient.SqlCommand(sql, cnn)

        cmd.ExecuteNonQuery()

        cmd.Dispose()

        cnn.Close()

        e.Cancel = True

        ListView1.EditIndex = -1

        ListView1.DataBind()

    End Sub

Un saludo!

miércoles, 22 de septiembre de 2010

Gestión de errores en ASP.NET

Hola, este post es tanto de mi compañero de trabajo Antonio como mío. La realidad es que sólo queremos controlar los errores de ASP.NET ¿Es pedir tanto? ¿Es demasiado osado? Yo creo que no, pero para saber cómo manejarlos primero hay que saber cómo funcionan. Ese es el propósito de este post, entenderlos y después ya controlarlos.

CustomErrors

http://msdn.microsoft.com/es-es/library/h0hfz6fc(VS.80).aspx

mode = [On|Off|RemoteOnly], determina si los errores personalizados está o no activos, o si sólo ven para clientes remotos.

defaultRedirect = url (una página .aspx, .htm, etc., con una dirección absoluta, relativa al fichero web.config o relativa al proyecto)

A la dirección url especificada en defaultRedirect, la única información disponible del error es el parámetro aspxerrorpath que indica que página generó el error:

?aspxerrorpath=/ControlErrores/Default.aspx

Además, en la página defaultRedirect no está nunca disponible Server.GetLastError.

También se puede especificar páginas de errores personalizadas atendiendo a los códigos de estado Http que devuelve el servidor, por ejemplo, el siguiente código hace lo siguiente:

Todos los errores no controlados van a ser redirigidos a la página PaginaError.aspx, y en concreto los errores con código 404 (fichero no encontrado), van a ir a PaginaNoEncontrada.aspx .

    <customErrors mode="On" defaultRedirect="~/PaginaError.aspx">

      <error statusCode="404" redirect="~/PaginaNoEncontrada.aspx"/>

    </customErrors>

Recuerda: customErrors sólo gestiona errores a nivel de petición de página, no para recursos que solicita la página, esto es que una imagen que carga la página y que no se encuentra (404) no provocará que veamos el error personalizado por customErrors.

CustomErrors presenta las siguientes ventajas y desventajas:

  • Ventajas:
    • Configuración sencilla a través del web.config.
    • Páginas de error sencillas, incluso ficheros .htm, lo que facilita el diseño de las mismas por terceros, por ejemplo un diseñador web.
    • Alto grado de personalización de páginas en función de códigos de estado Http.
  • Desventajas:
    • No hay información disponible sobre el error sucedido, luego tareas de log y traza de errores no son válidas a través de las páginas de error personalizadas.

Otra cosa a tener en cuenta es como funciona CustomErrors en lo relativo a la entrega de la página personalizada de error en el cliente. Hay muy buen blog al respecto en http://geeks.ms/blogs/jalarcon/archive/2010/11/07/modo-de-redirecci-243-n-de-errores-personalizados-en-asp-net-y-su-impacto-en-seo-e-imagen.aspx


Page_Error

A través de este evento de la página, controlamos errores sucedidos en la misma página, tenemos disponible Server.GetLastError() y normalmente también deberíamos limpiar el error con Server.ClearError() del servidor para evitar que el error siga propagándose y por ejemplo entre en juego los errores personalizados de customErrors.

    Protected Sub Page_Error(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Error

        Dim ex As Exception = Server.GetLastError

        ' TODO do something...       

        ' La siguiente instrucción impide que la excepción se propague más allá de este método

        Server.ClearError()

    End Sub

Recuerda: Al igual que customErrors, Page_Error sólo gestiona errores a nivel de petición de página, no de recursos de la página.

Page_Error presenta las siguientes ventajas y desventajas:

  • Ventajas:
    • Está disponible la información de error a través de Server.GetLastError().
    • Posibilidad de detener o proseguir la propagación de manejo del error a través de Server.ClearError().
    • Compatible con customErrors (en caso de no llamar a Server.ClearError()).
  • Desventajas:
    • Cada página debería implementar su propio método Page_Error.

Application_Error

Finalmente, es posible gestionar las excepciones de forma global al proyecto a través del evento Application_Error del fichero global.asax.

    Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)

        Dim ex As Exception = Server.GetLastError.GetBaseException

        ' TODO do something...

        Server.ClearError()       

    End Sub

Application_Error presenta las siguientes ventajas y desventajas:

  • Ventajas
    • Está disponible la información de error a través de Server.GetLastError().
    • Compatible con Page_Error (si no se llama a Server.ClearError()).
    • Compatible con customErrors (si no se llama a Server.ClearError()).
    • Gestión unificada de errores en toda la aplicación.
  • Desventajas
    • Los errores de servicios web no pasan por este evento.

Como vemos el flujo de un error en el siguiente:

  • Si hay disponible un Page_Error se procesa.
    • Si se llama a Server.ClearError el error se detiene.
  • Si hay disponible Application_Error se procesa.
    • Si se llama a Server.ClearError el error se detiene
  • Si ha disponible una página de error personalizada a través de customErrors se muestra y el error se detiene.
  • Se muestra una página de error genérica.

Recuerda: Siempre que se quiere obtener la excepción a través del método Server.GetLastError(), asegúrate de llamar al método GetBaseException() para obtener la excepción original.

Dim ex As Exception = Server.GetLastError.GetBaseException

A diferencia de customErrors y Page_Error, en Application_Error podremos controlar absolutamente todos los errores sucedidos en la aplicación, esto significa que por ejemplo una solicitud de un recurso de imagen que no existe por parte de una página, también será interceptado por Application_Error.

PRB: ThreadAbortException Occurs If You Use Response.End, Response.Redirect, or Server.Transfer

http://support.microsoft.com/kb/312629/EN-US/

El error ThreadAbortException parece que sólo es interceptable dentro de un Try..Cath. Esto es que no se propaga a Page_Error, Application_Error o customErrors.

ASP.NET AJAX

Si está activado customErrors en nuestro fichero web.config y AllowCustomErrorsRedirect=”True” para nuestro control ScriptManager, Cuando el motor de renderización parcial de página AJAX produzca un error, es capaz de llevar a cabo una redirección de cliente con el siguiente código que devuelve al navegador:

HTTP/1.1 200 OK

75|pageRedirect||/ControlErrores/PaginaError.aspx?aspxerrorpath=/ControlErrores/default.aspx|

En caso de no estar activo cualquier de los anteriores valroes, lo que devuelve AJAX no es un redirección sino la excepción no controlada:

27|error|500|panicoenlaxbox.blogspot.com|

Que mostrara alguno de los siguientes mensajes (depende de si estamos depurando o no).

clip_image002

image

Para evitar este mensaje tenemos 2 posibles momentos donde interceptarlo. Primero de la forma más sencilla que es estableciendo una valor para la propiedad AsynPostBackErrorMessage del control ScriptManager desde el marcado o bien manejando el evento AsyncPostBackError desde el servidor, pero Ojo!!, porque esto no impide que aparezca igualmente una alerta en el navegador, sólo nos ayuda a “esconder” el error original y devolver nuestro propio mensaje de error. Por ejemplo si AsyncPostBackErrorMessage = “MI ERROR”, entonces…

image

Como es lógico, esto está bien pero no soluciona la alerta (y posible depuración, porque recordar que esto no es una alerta sino una “excepción de javascript”).

Para evitar cualquier alerta o excepción javascript y controlar un error de ASP.NET AJAX desde cliente (no confundir con servidor y ver que este control de errores que ponemos a continuación pasa exclusivamente en cliente y después de que el error ya ha pasado por tu ciclo de vida, esto es Page_Error, Application_Error, etc.):

            function pageLoad(sender, e) {

                var prm = Sys.WebForms.PageRequestManager.getInstance();

                prm.add_endRequest(function (sender, e) {

                    if (e.get_error()) {

                        alert(e.get_error().message); //Alerta personalizada.

                        e.set_errorHandled(true); //Evitar error predeterminado.

                    }

                });

            }

Si hablamos de servicios web, cabe mencionar lo siguiente:

  • El error no ha pasado por Application_Error.
  • customErrors no se tiene en cuenta.

Si no hay ningún control extra, un servicio web que falla devolverá una alerta predeterminada de javascript como la siguiente:

clip_image004

Una solicitud de error a un servicio web devolverá lo siguiente:

HTTP/1.1 500 Internal Server Error

{"Message":"panicoenlaxbox","StackTrace":"   en Servicio1.HelloWorld() en C:\\Users\\sleon\\Documents\\Visual Studio 2010\\WebSites\\ControlErrores\\App_Code\\Servicio1.vb:línea 15","ExceptionType":"System.Exception"}

Para controlar el error del servicio web desde cliente (exclusivamente javascript) hay que hacer lo siguiente:

            Servicio1.HelloWorld(exito, fracaso);

            function exito(result, context) {

                alert("éxito");

            }

            function fracaso(result, context) {

                alert(result.get_message());

            }


Conclusiones

Seguro que hay muchas formas y mejores de controlar las excepciones en ASP.NET, pero tras estudiar todas las posibilidades, yo personalmente recomiendo el siguiente escenario:

Todo código susceptible de lanzar una excepción debería ir acompañado de su propia gestión con Try..Cath. ¡¡Por favor, que el error no llegue nunca a Page_Error ni a Application_Error, debería estar controlado siempre!!.

Si una página es propensa a errores no controlados (que la verdad es que dicho así suena mal y no se me ocurre ningún ejemplo válido), se podría utilizar puntualmente Page_Error, pero debería ser decisión del programador en cada página si utilizar esta rutina o no, yo creo que tampoco abusaré de la misma.

Siempre y sin excepción, se programará el evento Application_Error en el fichero global.asax. El único propósito de esta rutina será registrar el error en nuestro repositorio elegido (base de datos, log del sistema, etc.). Insisto, no hará nada más, solo registrar.

Siempre y sin excepción se utilizará customErrors al menos con una página de error (defaultRedirect) y si nos vemos con ganas y creativos, pues el 404 es buen candidato a tener su propia página de error, pero esto ya lo decide el programador.

Además customErrors parece una buena idea que esté activo con el modo RemoteOnly, para tener una vía de escape si el registro de Application_Error no nos convence ni nos ayuda a ver que pasó.

Un saludo!

jueves, 16 de septiembre de 2010

Controles enlazados a datos ASP.NET (I)

Repeater

Un repeater es un control enlazado a datos cuyo propósito principal es “sólo” mostrar información al usuario en forma de registros, esto es que pretende “repetir” una estructura determinada para n registros (aunque no hay problema en utilizarlo para orígenes de datos de 1 sólo registro). No permite la paginación ni ningún tipo de edición.

One-way data binding significa que solo permite expresiones de enlace a datos con Eval, Bind no está permitido y entonces no podemos utilizar este control para recuperar los cambios que haya realizado el usuario.

  • No permite la paginación de forma predeterminada.
  • No ofrece ninguna salida HTML predeterminada.
  • Al elegir un origen de datos desde su SmartTag no se genera ninguna plantilla predeterminada.
  • No incluye ningún enlace en su SmartTag.
  • No tiene ninguna plantilla de estilo.
  • Las plantillas disponibles son:
    • AlternatingItemTemplate
    • FooterTemplate
    • HeaderTemplate
    • ItemTemplate
    • SeparatorTemplate


DataList

Un DataList es un control enlazado a datos que permite visualizar todos los registros de una vez.
Permite la edición y selección, pero no la paginación e inserción.

Es un control de tipo Two-day data binding, luego se permite el uso de Bind.

Los eventos CRUD disponibles pueden ser personalizados en los eventos del control.

No permite la paginación de forma predeterminada.

Por defecto genera una salida predeterminada en HTML que se controla a través de la propiedad RepeatLayout:

Table (por defecto), <table>.

Flow, <span>.

Además si RepeatLayout = “Table”, entonces también se puede controla la orientación de la tabla y el número de columnas que se repiten con las propiedades RepeatDirection y RepeatColumns.

Al elegir un origen de datos desde su SmartTag se genera automáticamente la plantilla ItemTemplate con la siguiente estructura:

     FieldName:

     <asp:Label ID="FieldNameLabel" runat="server" Text='<%# Eval("FieldName") %>' />

     <br />

Los enlaces de su SmartTag  son los siguientes:

clip_image002

Incluye plantillas de estilo y además en el SmartTag  incorpora un generador de propiedades que nos ayuda a configurar la apariencia del control:

clip_image004

Las plantillas disponibles son:

  • AlternatingItemStyle
  • EditItemStyle
  • FooterStyle
  • HeaderStyle
  • ItemStyle
  • SelectedItemStyle
  • SeparatorStyle
  • AlternatingItemTemplate
  • EditItemTemplate
  • FooterTemplate
  • HeaderTemplate
  • ItemTemplate
  • SelectedItemTemplate
  • SeparatorTemplate

La propiedad DataKeyField indica el valor de que campo (sólo uno) será almacenado en la colección DataKeys, que luego nos permitirá recuperar este valor por un índice de fila, por ejemplo:

' CodigoBanco de la fila 1

Dim codigoBanco As String = DataList1.DataKeys(1)

En este control se permiten 2 acciones principales:

  • Edición/Actualización
    • Selección
  • Los valores válidos para el atributo CommandName son:
    • update
    • cancel
    • edit
    •  delete
    •  select

Para entrar un elemento en edición:

        <ItemTemplate>

<!--Resto Plantilla-->

            <asp:Button ID="btnEditar" runat="server" Text="Editar" CommandName="edit" />

        </ItemTemplate>

 

    Protected Sub DataList1_EditCommand( _

            ByVal source As Object, _

            ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) _

        Handles DataList1.EditCommand

 

        CType(source, DataList).EditItemIndex = e.Item.ItemIndex

        CType(source, DataList).DataBind()

    End Sub

Para cancelar una edición:

<EditItemTemplate>

            <!--Resto plantilla-->

            <asp:Button ID="btnCancelar" runat="server" Text="Cancelar" CommandName="cancel" />        </EditItemTemplate>

 

    Protected Sub DataList1_CancelCommand( _

        ByVal source As Object, _

        ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) _

    Handles DataList1.CancelCommand

 

        DataList1.EditItemIndex = -1

        DataList1.DataBind()

    End Sub

Para confirmar una edición:

<EditItemTemplate>

            <!--Resto plantilla-->

        <asp:Button ID="btnActualizar" runat="server" Text="Actualizar" CommandName="update" />        </EditItemTemplate>

 

    Protected Sub DataList1_UpdateCommand( _

        ByVal source As Object, _

        ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) _

    Handles DataList1.UpdateCommand

 

        Dim codigoBanco As String = DataList1.DataKeys(e.Item.ItemIndex).ToString

        Dim banco As String = CType(e.Item.FindControl("txtBanco"), TextBox).Text

        ' ejecutar sql

        DataList1.EditItemIndex = -1

        DataList1.DataBind()

    End Sub

Para eliminar un elemento:

      <asp:Button ID="btnEliminar" runat="server" Text="Eliminar" CommandName="delete" />

 

    Protected Sub DataList1_DeleteCommand( _

        ByVal source As Object, _

        ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) _

    Handles DataList1.DeleteCommand

 

        Dim codigoBanco As String = DataList1.DataKeys(e.Item.ItemIndex).ToString

        ' ejecutar sql

        DataList1.DataBind()

    End Sub

Para seleccionar un elemento:

      <asp:Button ID="btnSeleccionar" runat="server" Text="Eliminar" CommandName="select" />

 

    Protected Sub DataList1_SelectedIndexChanged( _

        ByVal sender As Object, _

        ByVal e As System.EventArgs) _

    Handles DataList1.SelectedIndexChanged

 

        DataList1.DataBind()

    End Sub

Todos estos comandos preestablecidos pasarán antes por el evento ItemCommand y además este evento también nos sirve para simular comandos que no existen y queramos controlar, por ejemplo “unselect”:

    Protected Sub DataList1_ItemCommand( _

        ByVal source As Object, _

        ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) _

    Handles DataList1.ItemCommand

 

        If e.CommandName = "unselect" Then

            DataList1.SelectedIndex = -1

        End If

        DataList1.DataBind()

    End Sub

 

DetailsView

Un control DetailsView muestra un solo registro cada vez. Normalmente se utilizar en escenarios maestro/detalle en conjunción con el control GridView. También se puede utilizar por si sólo como un mantenimiento de datos ya que permite la paginación, inserción, eliminación y actualización.

Aunque DetailsView utiliza el mecanismo de plantillas, sólo lo hace para ciertas secciones del control no relativas a datos del registro activo (Header, Footer, Pager y EmptyData). De este modo, para mostrar información del registro actual funciona a través de campos agregados a su colección Fields. Los tipos de campos admitidos son:

  • BoundField
  • ButtonField
  • CheckBoxField
  • CommandField
  • HyperLinkField
  • ImageField
  •  TemplateField
    • ItemTemplate
    • AlternativeItemTemplate
    • EditItemTemplate
    • InsertItemTemplate
    • HeaderTemplate

clip_image006

Es un control de tipo Two-way data binding.

Permite CRUD completo.

Los eventos CRUD disponibles son realizados automáticamente por el control de origen de datos que utiliza DetailsView, no se permite incluir código propio para insertar, actualizar o eliminar un registro.

Permite paginación.

Por defecto genera una salida predeterminada en una tabla.

Al elegir un origen de datos desde su SmartTag no se genera ninguna plantilla predeterminada, aunque en tiempo de ejecución sí genera un fila con todos los datos del registro al que está enlazado.

Los enlaces de su SmartTag son los siguientes:

clip_image008

En el caso de que el control de origen de datos tenga configurado métodos para la inserción, actualización o eliminación, aparecerá este otro SmartTag:

clip_image010

Incluye plantillas de estilo.

Las plantillas disponibles son:

  • AlternatingRowStyle
  • CommandRowStyle
  • EditRowStyle
  • EmptyDataRowStyle
  • FieldHeaderStyle
  • FooterStyle
  • HeaderStyle
  • InsertRowStyle
  • PagerStyle
  • RowStyle
  • EmptyDataTemplate
  • FooterTemplate
  • HeaderTemplate
  • PagerTemplate

La propiedad DataKeyNames indica los valores de que campos (uno o varios) serán almacenados como campos clave de un registro.

FormView

Un control FormView sirve al mismo propósito y es válido en los mismos escenarios que un control DetailsView. La principal diferencia entre ambos es que FormView no ofrece ninguna salida predeterminada HTML y sólo trabaja con plantillas.

Permite CRUD completo.

Los eventos CRUD disponibles son realizados automáticamente por el control de origen de datos que utiliza FormView.

Permite paginación.

Por defecto genera una salida predeterminada en una tabla.

Al elegir un origen de datos desde su SmartTag se genera automáticamente la siguiente plantilla de código:

<EditItemTemplate>

            FieldName:

            <asp:Label ID="FieldNameLabel1" runat="server"

                Text='<%# Eval("FieldName") %>' />

            <br />

            <asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True"

                CommandName="Update" Text="Actualizar" />

            &nbsp;<asp:LinkButton ID="UpdateCancelButton" runat="server"

                CausesValidation="False" CommandName="Cancel" Text="Cancelar" />

</EditItemTemplate>

<InsertItemTemplate>

            FieldName:

            <asp:TextBox ID="FieldNameTextBox" runat="server"

                Text='<%# Bind("FieldName") %>' />

            <br />

            <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True"

                CommandName="Insert" Text="Insertar" />

            &nbsp;<asp:LinkButton ID="InsertCancelButton" runat="server"

                CausesValidation="False" CommandName="Cancel" Text="Cancelar" />

</InsertItemTemplate>

<ItemTemplate>

            FieldName:

            <asp:Label ID="FieldNameLabel" runat="server"

                Text='<%# Eval("FieldName") %>' />

            <asp:LinkButton ID="EditButton" runat="server" CausesValidation="False"

                CommandName="Edit" Text="Editar" />

            &nbsp;<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"

                CommandName="Delete" Text="Eliminar" />

            &nbsp;<asp:LinkButton ID="NewButton" runat="server" CausesValidation="False"

                CommandName="New" Text="Nuevo" />

</ItemTemplate>

Los enlaces de su SmartTag son los siguientes:

clip_image012

Incluye plantillas de estilo.

Las plantillas disponibles son:

  • EditRowStyle
  • EmptyDataRowStyle
  • FooterStyle
  • HeaderStyle
  • InsertRowStyle
  • PagerStyle
  • RowStyle
  • EditItemTemplate
  • EmptyDataTemplate
  • FooterTemplate
  • HeaderTemplate
  • InsertItemTemplate
  • ItemTemplate
  • PagerTemplate

La propiedad DataKeyNames indica los valores de que campos (uno o varios) serán almacenados como campos clave de un registro.

Un saludo!