Cómo modificar las plantillas del control ListView desde el code-behind

Como ya seguro que todos sabréis, el control ListView fue una de las novedades de Visual Studio 2008 en lo que se refiere al desarrollo web.

Es un control que me gusta especialmente porque te deja control total sobre el HTML que genera.

El control se basa en plantillas y a través de estas se puede especificar el layout que tendrá; si se genera un tabla, una lista….todo depende de HTML que incluyas en las plantillas.

En el ejemplo que se ve a continuación el ListView renderiza una tabla con única columna y tantas filas como elementos devuelva el DataSource MenuListOds. ( sí, un ejemplo un poco tonto pero suficiente para lo que necesitamos para el ejemplo ).

MenuListOds es un ObjectDataSource que tiene un método GetList que devuelve una colección de elementos que tienen la propiedad Name. Este ObjectDataSource es el que se usa para rellenar el ListView.

<asp:ListView ID="MyListView" runat="server" DataSourceID="MenuListOds"> <LayoutTemplate> <table id="ListViewTable"> <tbody> <asp:PlaceHolder id="itemPlaceHolder" runat="server"></asp:PlaceHolder> </tbody> </table> </LayoutTemplate> <ItemTemplate> <tr> <td> <% Eval (“Name”) %> </td> </tr> </ItemTemplate> </asp:ListView>

Como veis, a través de LayoutTemplate e ItemTemplate estamos definiendo cómo queremos que se renderice, especificando el HTML concreto que se va a generar.

Pero en algunos casos no es suficiente con poder definir las plantillas de forma declarativa y necesitamos establecer las plantillas desde el código.

Para crear una plantilla desde código sólo tenemos que crear una clase que implemente  la interfaz ITemplate; una para LayoutTemplate y otra para ItemTemplate.

La plantilla LayoutTemplate para el generar el mismo HTML que en el ejemplo superior sería la siguiente:

public class LayoutTemplate : ITemplate
{
    public void InstantiateIn(Control container)
    {
        var table = new HtmlGenericControl("table") { ID = "ListViewTable" };            
        var tbody = new HtmlGenericControl("tbody");
        table.Controls.Add(tbody);

        var placeHolder = new HtmlGenericControl("PlaceHolder") { ID = "itemPlaceHolder" }; ;
        tbody.Controls.Add(placeHolder);

        container.Controls.Add(table);
    }
}

Y la plantilla para ItemTemplate:

public class ItemTemplate : ITemplate
    {
        public void InstantiateIn(Control container)
        {
            var row = new HtmlGenericControl("tr");
            var col = new HtmlGenericControl("td");
            
            row.Controls.Add(col);

            col.DataBinding += DataBinding;
            container.Controls.Add(row);
        }

        public void DataBinding(object sender, EventArgs e)
        {
            var container = (HtmlGenericControl)sender;
            var dataItem = (Entity)((ListViewDataItem)container.NamingContainer).DataItem;

            container.Controls.Add(new Literal() { Text = dataItem.Name });
        }

    }

Fijaros que esta segunda plantilla usamos el evento DataBinding, para pintar la información que nos interesa en cada columna de la fila.

Una vez creadas sólo tendremos que decir al ListView que use las plantillas que hemos creado:

LayoutTemplate template = new LayoutTemplate();
MyListView.LayoutTemplate = template;

ItemTemplate itemTemplate = new ItemTemplate();
MyListView.ItemTemplate = itemTemplate;

Espero que os sea de utilidad!

[Artalde.NET] 10 razones para considerar WPF en tu próxima aplicación

¿Sabes lo que es WPF? ¿Sí lo sabes pero no te convence? ¿Estás valorando crear aplicaciones WPF? ¿Quieres saber si realmente merece la pena usar esta tecnología?

Oskar Alvarez, responsable del área .NET del Instituto Ibermática de Innovación, aportará sus 10 razones para considerar WPF en tu próxima aplicación.

La charla será el 6 de mayo, miércoles, en el lugar y hora habitual; de 19:00 a 21:00h en la universidad de Deusto.

Si estáis interesados en acudir no olvidéis registraros.

Agenda:

19:00 – 19:15 Registro.
19:15 – 20:15 10 razones para considerar WPF para hacer tu próxima aplicación

  • Rich Content Model
  • Databinding
  • DataTemplates
  • Triggers
  • Styles
  • Layout
  • ListView
  • Interop
  • Printing
  • Validación
  • Futuro

[Evento-Santander] Mejora la calidad y productividad realizando pruebas unitarias

Seguro que desarrollar aplicaciones de alta calidad y de forma productiva siempre es uno de los objetivos que todos nos marcamos en todos los desarrollos que comenzamos.

Pero la realidad suele ser otra, y en más ocasión las cosas se complican, y se generan aplicaciones de no tan buena calidad y/o con una baja productividad que disparan los costes del proyecto.

Las pruebas unitarias son uno de los recursos con lo que contamos los desarrolladores para intentar paliar esta situación.

Para demostrarlo, el día 7 de mayo realizaré una sesión en Santander sobre esta temática en colaboración con el CIIN, el grupo de usuarios .NET de Cantabria (Nuberos.NET), MSDN y la empresa AvanGroup, en la que trabajo.

A lo largo de esta sesión veremos diversos aspectos relacionados con esta temática que puedan ayudar al asistente a iniciarse en el empleo de pruebas unitarias.

En una primera parte repasaremos, y discutiremos si es necesario, sobre las características y beneficios de realizar pruebas unitarias para pasar rápidamente a aspectos más prácticos y ver cómo sería posible incluirlas en nuestros desarrollos haciendo uso de Visual Studio.

Si estáis interesados podéis registraros.

Datos de Interés:

· Fecha: Jueves, 7 de mayo.

· Hora: 15:30 a 18:30.

· Precio: Gratuito.

· Lugar: CIIN, Edificio Simeón, Pasaje de Peña 4, 2º, local 15.

· Ponente: Ibon Landa Martín (AvanGroup).

· Duración aproximada: 3 horas.

Pruebas unitarias: Mocks

Los mocks son objetos falsos que simulan el comportamiento de un objeto real. Los objetos falsos son los que se usarán durante la ejecución de la prueba unitaria, lo que posibilitará que no necesitemos el objeto real y que no dependamos de él para poder probar correctamente y de manera completa el módulo.

El concepto de mock es sencillo; si tanto el objeto real como el objeto falso implementan la misma interfaz y el módulo que estamos probando trabaja contra interfaces en lugar de contra objetos, podremos hacer uso indistintamente de objeto falso o del objeto real sin que esto afecte al módulo, siempre y cuando ambos objetos tengan el mismo comportamiento.

El uso de Mocks debería ser recurso constante dentro de nuestras pruebas. Podría serlo, pero la generación de mocks puede resultar un poco pesada, lo que provoca que no siempre se empleen.

Al menos deberíamos usar mocks en los casos de dependencias externas con otros equipos de desarrollo o con módulos con lo que tengamos que integrarnos.

Aunque existen varios framework, como RhinoMock o NMock, que nos va a permitir generar estos objetos falsos, no debemos olvidar que cualquier objeto falso que creemos puede considerarse un mocks, aunque no se haga uso de un framework.

En el ejemplo que se describe a continuación supondremos que el módulo que estamos probando debe hacer uso de un Helper de envío de correos electrónicos que no es desarrollado por nuestro equipo de desarrollo. En este caso, es conveniente generar un mock para simular esta dependencia y poder probar nuestros desarrollos sin disponer del módulo de envío de correos.

Para simular esta dependencia implementaremos un mock haciendo uso de RhinoMock. La clase de envío de correos implementa la interfaz IMail.

public interface IMail
{
bool SendMail(string subject, string body);
bool SendMail(string subject, string body, string to, string from);
}

La clase que implementa la lógica de negocio, dónde se hace uso del módulo de envío de correos, debe implementar dos constructores; uno sin parámetros, que será el que se utilice en el mundo real y un constructor que recibe como parámetro un objeto de tipo IMail que será el que se emplee en las pruebas unitarias.

 

public class CustomerBL : ICustomerBL
{
private IMail mailHelper;

        public ERPServiceClient service;

        public CustomerBL()
        {
            service = new ERPServiceClient();
            this.mailHelper = new Mail();
        }

        public CustomerBL(IMail mail)
        {
            service = new ERPServiceClient();
            this.mailHelper = mail;
}

A continuación podéis ver el código fuente de la prueba unitaria que emplea un mock.

 

[TestClass()]
public class CustomerBLTest
{
        private MockRepository _mocks;

        private IMail mailMock;        

        private CustomerBL customerBL;

        private TestContext testContextInstance;

        [TestInitialize()]
        public void MyTestInitialize()
        {
            // Se crea un repositorio de mocks
            _mocks = new MockRepository();

            // Creamos un mock que implemente IMail.
            mailMock = _mocks.CreateMock<IMail>();

            // Inicializamos el uso de los objetos mocks    
            InitializeMockObject();
            _mocks.ReplayAll();

            // Creamos una instancia de objeto pasándole el objeto Mock
            customerBL = new CustomerBL(mailMock);

        }

        private void InitializeMockObject()
        {
            Expect.On(mailMock).Call(mailMock.SendMail("subject", "body", 
                null, "admin@admin.com")).Throw(new ArgumentException()); 
            Expect.On(mailMock).Call(mailMock.SendMail("subject", "body", 
                "mail@mail.com", "admin@admin.com")).Return(true);
        }
        
    

        [TestMethod()]
        public void AddUserTest()
        {
            CustomerEntity customer = new CustomerEntity();
            customer.Name = "MyName";
            customer.Address = "YYY";
            customer.Mail = "mail@mail.com";
            string actual;
            actual = customerBL.AddUser(customer);
            Assert.IsNotNull(actual);

            bool actualExists = customerBL.ExistCustomer(actual);
            Assert.AreEqual(true, actualExists);
        }

        [TestMethod()]
        [ExpectedException(typeof(ArgumentException))]
        public void AddUserTestException()
        {
            CustomerEntity customer = new CustomerEntity();
            customer.Name = "MyName";
            customer.Address = "YYY";
            customer.Mail = null;
            string actual;
            actual = customerBL.AddUser(customer);
        }

El método “MyTestInitialize” se utiliza para inicializar los objetos mocks que se emplearán en las pruebas que se incluyen dentro de la clase.

En este método crearemos el repositorio de mocks, inicializaremos los mocks que se utilizarán y crearemos el objeto sobre el que realizaremos las pruebas ( CustomerBL ), pasándolo como parámetro el objeto mock que queremos se utilice. Pasándole como parámetro el objeto mock conseguiremos que el objeto que se está probando use el objeto falso en lugar de objeto real.

En el método InitializeMockObject es dónde se describe el comportamiento que tendrá el objeto falso ante determinados parámetros de entrada.

En el código se describen dos comportamientos para el método “SendMail”; en uno de ellos se devuelve “true” mientras que en el otro se genera una excepción como resultado. Lógicamente, el comportamiento debe ser el mismo que tendría que el objeto real ante los mismos parámetros de entrada.

El último paso sería generar los métodos de prueba que cubren la funcionalidad de nuestra aplicación, haciendo uso de los objetos que hemos creado anteriormente.

Ya para terminar, en algún comentario, en un post anterior, se hacían referencia a los stubs y las diferencias entre stubs y mocks. Para los que estéis interesados en este tema os dejo un enlace dónde se habla de este tema, aunque lo realmente importante es que cogais la idea, que a veces, para hacer nuestras pruebas unitarias, necesitaremos objetos falsos que simulen ser los reales y así poder hacer pruebas de manera independiente al resto y de una manera más rápida.

Especificar múltiples directorios para los ensamblados de la aplicación

Generalmente una aplicación no se compone de un único ensamblado, sino que contiene múltiples ensamblados, cada uno con una funcionalidad determinada.

Si suponemos una aplicación de consola o WinForm, lo más habitual es que los ensamblados que necesita la aplicación de consola se encuentren en el mismo directorio que la aplicación principal, para que el motor de ejecución pueda encontrar las dependencias de la aplicación al ejecutarla. En un aplicación ASP.NET todos los ensamblados estarían en el directorio bin.

  • MiAplicacion.exe
  • AccesoDatos.dll
  • Logica.dll
  • Utilidades.dll

En ciertas situaciones puede ser que no nos interese que todas los ensamblados se encuentren dentro del mismo directorio. Nos puede interesar tener múltiples directorios con ensamblados y que cuando se ejecute la aplicación el CLR busque y cargue las dependencias de la aplicación desde cualquiera de los directorios que definamos.

  • MiAplicacion.exe
    • MiDirectorioAccesoDatos.dll
    • MiOtroDirectorioLogica.dll
    • MiTercerDirectorioUtilidades.dll

Cierto es que también podríamos cargar los ensamblados en la GAC pero yo al menos soy partidario de usar los menos posible este recurso y cargar los ensamblados desde los directorios de la aplicación.

En estas situaciones podremos usar la característica de probing, que nos permite especificar, a través del fichero de configuración subdirectorios de la aplicación en los que el CLR busque cuando se cargan los ensamblados.

Digo subdirectorios, porque los directorios “extras” a definir deben ser subdirectorios del directorio base ( del directorio bin en aplicaciones ASP.NET ).

En el fichero de configuración ( app.config o web.config ) dentro de la sección runtime>assemblyBinding podemos especificar los path privados dónde el CLR buscará las dependencias de la aplicación. Podemos definir tantos como consideremos.

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="MiDirectorio"/>
    </assemblyBinding>
  </runtime>    
</configuration>

Ya para terminar me parece interesante, para aquellos que no lo conozcáis, que leáis los pasos que el motor en tiempo de ejecución lleva a cabo para resolver una referencia a un ensamblado;Cómo el motor en tiempo de ejecución ubica ensamblados.

Pruebas unitarias: Una parada en el camino.

Aunque todavía queda un buen trozo para terminar el camino, es momento de hacer una parada y hacer un repaso de lo visto hasta ahora.

Otros post relacionados:

Más post interesantes de otros compañeros de geeks:

Y alguno de el Bruno sobre VStudio 2010: