DEV Community

Cover image for Reportes de datos a través de los controles GridView, CheckBox y TextBox de DotVVM
Daniel Gomez for DotVVM

Posted on

Reportes de datos a través de los controles GridView, CheckBox y TextBox de DotVVM

Una tabla es un conjunto de celdas organizadas dentro de las cuales podemos alojar distintos contenidos. Este tipo de elemento es bastante útil al momento de realizar un reporte para visualizar alguna información en específico.

En artículos anteriores sobre ASP.NET Core y DotVVM, podíamos ver de manera general como utilizar controles predefinidos de estas herramientas para la visualización de datos a manera de reporte. Estos son algunos de esos artículos:

Asimismo, cuando se manejan formularios para administrar información, es necesario crear tablas para poder visualizar los datos tratados. Estos son algunos artículos previos por si deseas aprender como diseñar formularios con HTML:

En esta ocasión aprenderemos los fundamentos para visualizar determinados datos y establecer algunos criterios de búsqueda con C# y HTML, a través de los controles de DotVVM sobre ASP.NET Core.

Nota: el código fuente del proyecto que analizaremos en este articulo lo puedes encontrar en este repositorio de GitHub: DotVVM Reports.

El patrón de diseño Modelo, Vista, Vistamodelo - MVVM

Un aspecto importante por mencionar es sobre la base de DotVVM. Este marco de trabajo se fundamenta en el patrón de diseño Modelo, Vista, Vistamodelo sobre .NET para la comunicación entre HTML (páginas web) y C# (código fuente). La finalidad de estas partes son las siguientes:

  • El modelo. — es responsable de todos los datos de la aplicación y de la lógica de negocios relacionada.

  • La vista. — Representaciones para el usuario final del modelo de la aplicación. La vista es responsable de mostrar los datos al usuario y de permitir la manipulación de los datos de la aplicación.

  • El Modelo-Vista o Vista-Modelo. — uno o más por vista; el modelo-vista es responsable de implementar el comportamiento de la vista para responder a las acciones del usuario y de exponer los datos del modelo fácilmente.

Reporte de datos con ASP.NET Core y DotVVM

Para ejemplificar la utilización de algunos controles de DotVVM para la realización de un reporte, tendemos una pequeña aplicación como esta:

Teniendo en cuenta el patron MVVM – Modelo, Vista, Vistamodelo, analizaremos de forma general cada una de estas partes para este proyecto.

Modelo

Teniendo en cuenta que los datos de la aplicación y de la lógica de negocios relacionada se maneja en esta sección, a continuación, veremos cómo se manejan los datos y los servicios correspondientes.

La base de datos está conformada por dos tablas: Person y PersonType.

Las sentencias SQL para la creación de estas tablas, sus atributos y la inserción de algunos registros son las siguientes:

CREATE SCHEMA IF NOT EXISTS `db` DEFAULT CHARACTER SET utf8;
USE `db` ;

CREATE TABLE IF NOT EXISTS `db`.`PersonType` (
  `Id` INT NOT NULL,
  `Name` VARCHAR(45) NOT NULL,
  `Description` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`Id`))
;

CREATE TABLE IF NOT EXISTS `db`.`Person` (
  `Id` INT NOT NULL AUTO_INCREMENT,
  `FirstName` VARCHAR(45) NOT NULL,
  `LastName` VARCHAR(45) NOT NULL,
  `IdPersonType` INT NOT NULL,
  PRIMARY KEY (`Id`),
  FOREIGN KEY (`IdPersonType`) REFERENCES `db`.`PersonType` (`Id`))
;

INSERT INTO `persontype` (`Id`, `Name`, `Description`) VALUES ('1', 'Type A', '');
INSERT INTO `persontype` (`Id`, `Name`, `Description`) VALUES ('2', 'Type B', '');

INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('1', 'Sergey', 'Brin', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('2', 'Larry', 'Page', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('3', 'Tim', 'Barners', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('4', 'Linus', 'Torvalds', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('5', 'Larry', 'Ellison', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('6', 'Steve', 'Ballmer', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('7', 'Steve', 'Jobs', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('8', 'Marc', 'Benioff', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('9', 'Ray', 'Ozzie', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('10', 'Nicholas', 'Negroponte', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('11', 'Diane', 'Green', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('12', 'Sam', 'Palmisano', '1');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('13', 'Blake', 'Ross', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('14', 'Ralph', 'Szygenda', '2');
INSERT INTO `person` (`Id`, `FirstName`, `LastName`, `IdPersonType`) VALUES ('15', 'Rick', 'Dalzell', '2');
Enter fullscreen mode Exit fullscreen mode

Con la base de datos establecida, la parte correspondiente a la capa de acceso de datos hace referencia a la definición de las clases para trabajar con las entidades de la base de datos y al contexto para establecer la comunicación entre ASP.NET Core y la base de datos, que, en este caso, MySQL es la que se esta utilizando.

Para este propósito, es necesario instalar tres paquetes NuGet:

  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
  • MySql.Data.EntityFrameworkCore

Posteriormente, es necesario utilizar la consola de administración de paquetes para realizar scaffolding desde la base de datos (generar automáticamente el contexto y las clases de las entidades) a través del siguiente comando:

Scaffold-DbContext "server=servername;port=portnumber;user=username;password=pass;database=databasename" MySql.Data.EntityFrameworkCore -OutputDir Entities -f
Enter fullscreen mode Exit fullscreen mode

Con esta primera parte, la conexión a la base de datos esta lista. Lo que prosigue a continuación es la definición de modelos con los cuales se trabajará en la página web. Estos modelos son:

public class PersonModel
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int IdPersonType { get; set; }
    public string NamePersonType { get; set; }
}
Enter fullscreen mode Exit fullscreen mode
public class PersonTypeModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Para cada uno de estos modelos se cuenta con un servicio, los cuales tienen las siguientes operaciones:

PersonService:

  • GetAllPersonsAsync()
  • GetPersonByIdAsync(int personId)
  • GetPersonByIdAndTypeAsync(int personId, int personTypeId)
  • GetAllPersonsByTypeAsync(int personTypeId)

PersonTypeService:

  • GetAllPersonTypesAsync()
  • GetPersonTypeByIdAsync(int personTypeId)

En Visual Studio 2019 tendremos algo como esto:

Vistamodelo

public class DefaultViewModel : MasterPageViewModel
{
    private readonly PersonService personService;
    public GridViewDataSet<PersonModel> Persons { get; set; } = new GridViewDataSet<PersonModel>();
    public List<int> PersonTypes { get; set; } = new List<int>();
    public string IdSearch { get; set; }
    public bool SearchByTextVisible { get; set; } = false;

    public DefaultViewModel(PersonService personService)
    {
        this.personService = personService;
    }

    public override async Task PreRender() {}

    public async Task UpdatePersonList()
    {
        IdSearch = null;

        if (PersonTypes.Count == 2)
        {
            Persons.Items = await personService.GetAllPersonsAsync();
            SearchByTextVisible = true;
        }
        else if (PersonTypes.Count == 1)
        {
            int IdPersonType = PersonTypes.FirstOrDefault();
            Persons.Items = await personService.GetAllPersonsByTypeAsync(IdPersonType);
            SearchByTextVisible = true;
        }
        else
        {
            Persons.Items.Clear();
            SearchByTextVisible = false;
        }
    }

    public async Task SearchById()
    {
        if (PersonTypes.Count == 2)
        {
            if (!string.IsNullOrEmpty(IdSearch))
            {
                List<PersonModel> list = new List<PersonModel>(); ;
                list.Add(await personService.GetPersonByIdAsync(Int32.Parse(IdSearch)));
                Persons.Items = list;
            }
            else {
                Persons.Items = await personService.GetAllPersonsAsync();
            }
        }
        else if (PersonTypes.Count == 1)
        {
            if (!string.IsNullOrEmpty(IdSearch))
            {
                int IdPersonType = PersonTypes.FirstOrDefault();
                List<PersonModel> list = new List<PersonModel>(); ;
                list.Add(await personService.GetPersonByIdAndTypeAsync(Int32.Parse(IdSearch), IdPersonType));
                Persons.Items = list;
            }
            else
            {
                int IdPersonType = PersonTypes.FirstOrDefault();
                Persons.Items = await personService.GetAllPersonsByTypeAsync(IdPersonType);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Vista

<dot:Content ContentPlaceHolderID="MainContent">
    <div class="page-center">
        <div class="page-grid-top">
            <div class="student-image"></div>
            <h1>Person Report</h1>
        </div>

        <p>
            <h4>Search by type:</h4>
            <p />
            <dot:CheckBox CheckedItems="{value: PersonTypes}"
                      Changed="{command: UpdatePersonList()}"
                      CheckedValue="{value: 1}" Text="Type A" />
            <br />
            <dot:CheckBox CheckedItems="{value: PersonTypes}"
                      Changed="{command: UpdatePersonList()}"
                      CheckedValue="{value: 2}" Text="Type B" />
        </p>

        <p >
            <h4>Search by text:</h4>
            <p />
            ID Number:
            <dot:TextBox Text="{value: IdSearch}" Type="Number" class="page-input" Visible="{value: SearchByTextVisible}" />
            <dot:Button Text="Search" Click="{command: SearchById()}" class="page-button" Visible="{value: SearchByTextVisible}" />
        <p />

        <h4>Report:</h4>

        <dot:GridView DataSource="{value: Persons}" class="page-grid">
            <Columns>
                <dot:GridViewTextColumn ValueBinding="{value: Id}" HeaderText="Id" />
                <dot:GridViewTextColumn ValueBinding="{value: FirstName}" HeaderText="Firstname" />
                <dot:GridViewTextColumn ValueBinding="{value: LastName}" HeaderText="LastName" />
                <dot:GridViewTextColumn ValueBinding="{value: NamePersonType}" HeaderText="Type" />
            </Columns>
            <EmptyDataTemplate>
                There are no search results.
            </EmptyDataTemplate>
        </dot:GridView>

    </div>
</dot:Content>
Enter fullscreen mode Exit fullscreen mode

Análisis de la aplicación

En el siguiente GIF se puede visualizar de manera general la interacción con esta pequeña página web.

El primer elemento que analizaremos es el GridView, un control de DotVVM que nos permite tablas para representar datos en específico. Este componente nos permite especificar la fuente de datos a través de la propiedad DataSource, en este caso, la fuente de datos se define de la siguiente manera:

public GridViewDataSet<PersonModel> Persons { get; set; } = new GridViewDataSet<PersonModel>();
Enter fullscreen mode Exit fullscreen mode

La fuente de datos, adicional a un listado de tipo GridViewDataSet, tambien puede estar definido a través de otra colección de tipo List. Para la definición de las columnas se utiliza la etiqueta GridViewTextColumn. En este caso, podemos encontrar las columnas Id, FirstName, LastName y Type. Estos nombres vienen del tipo de dato de la fuente de datos, en este caso, del modelo PersonModel.

<dot:GridView DataSource="{value: Persons}" class="page-grid">
    <Columns>
        <dot:GridViewTextColumn ValueBinding="{value: Id}" HeaderText="Id" />
        <dot:GridViewTextColumn ValueBinding="{value: FirstName}" HeaderText="Firstname" />
        <dot:GridViewTextColumn ValueBinding="{value: LastName}" HeaderText="LastName" />
        <dot:GridViewTextColumn ValueBinding="{value: NamePersonType}" HeaderText="Type" />
    </Columns>
    <EmptyDataTemplate>
        There are no search results.
    </EmptyDataTemplate>
</dot:GridView>
Enter fullscreen mode Exit fullscreen mode

Otra de las sub-etiquetas de GridView es EmptyDataTemplate. Esta etiqueta permite mostrar algún contenido HTML en caso de que el listado de elementos se encuentre vacío. A la final, con el GridView visualizaremos algo como esto:

Más información sobre el componente GridView aquí: https://www.dotvvm.com/docs/controls/builtin/GridView/2.0.

Ahora bien, a partir de esta tabla son varias las operaciones que se pueden realizar, por ejemplo, establecer componentes adicionales para crear criterios de búsqueda y actualizar esta tabla según la búsqueda.

El primer caso es utilizando un CheckBox de DotVVM. Al igual que en HTML o cualquier otro entorno de diseño, el CheckBox tiene el rol como casilla de verificación para seleccionar elementos en un conjunto de opciones. Para este ejemplo, el objetivo es tener dos casillas de verificación, los cuales corresponden a los tipos de personas. Según la selección, ya sea del Tipo A, del Tipo B, o de los dos, la tabla de registros se actualizará de acuerdo con esta decisión.

En la parte de la vista, nos encontramos con la propiedad CheckedItems que almacenara el valor de los elementos que se encuentren seleccionados. Asimismo, nos encontramos con la propiedad Changed, la cual permite especificar el método que realizara las acciones al momento que este elemento sea activado o desactivado.

<dot:CheckBox CheckedItems="{value: PersonTypes}"
            Changed="{command: UpdatePersonList()}"
            CheckedValue="{value: 1}" Text="Type A" />
<br />
<dot:CheckBox CheckedItems="{value: PersonTypes}"
            Changed="{command: UpdatePersonList()}"
            CheckedValue="{value: 2}" Text="Type B" />
Enter fullscreen mode Exit fullscreen mode

En el método de actualización, por ejemplo, si seleccionados uno de los dos tipos, entonces realizaremos una consulta en la base de datos de acuerdo con el servicio definido: PersonService, para obtener el listado de personas según el id seleccionado. Con este listado recuperado, actualizaremos la base de datos al establecer nuevamente los ítems de la fuente de datos del GridView.

int IdPersonType = PersonTypes.FirstOrDefault();
Persons.Items = await personService.GetAllPersonsByTypeAsync(IdPersonType);
SearchByTextVisible = true;
Enter fullscreen mode Exit fullscreen mode

Algo parecido sucederá si no seleccionamos ninguna de las casillas de verificación. En este caso solo limpiaremos los ítems del GridView.

Persons.Items.Clear();
Enter fullscreen mode Exit fullscreen mode

Como vimos en el GIF, el resultado de utilizar el control CheckBox es el siguiente:

Más información sobre el componente CheckBox aquí: https://www.dotvvm.com/docs/controls/builtin/CheckBox/2.0.

Otro de los controles que nos permiten seguir agregando funcionalidades al GridView para establecer criterios de búsqueda a este reporte son los elementos TextBox y Button. En este caso, estos componentes pueden ser de utilizad para buscar algún elemento específico del reporte a través de una entrada de texto. Para ejemplificar, en esta aplicación, los controles sirven para encontrar a una persona especifica según su Id.

<dot:TextBox Text="{value: IdSearch}" Type="Number" class="page-input" Visible="{value: SearchByTextVisible}" />

<dot:Button Text="Search" Click="{command: SearchById()}" class="page-button" Visible="{value: SearchByTextVisible}" />
Enter fullscreen mode Exit fullscreen mode

La actualización de los elementos del GridView es similar al caso del CheckBox. El resultado es el siguiente:

Alt Text

Toda la información sobre el control TextBox la podemos encontrar en: https://www.dotvvm.com/docs/controls/builtin/TextBox/2.0. Y la del control Button en: https://www.dotvvm.com/docs/controls/builtin/Button/2.0.

¿Qué sigue?

Con este artículo, hemos aprendido ciertas características de los componentes GridView, CheckBox, TextBox y Button para visualizar un listado de datos y establecer criterios de búsqueda a través del patrón de diseño Modelo, Vista, Vistamodelo en ASP.NET Core y DotVVM.

El código fuente de esta implementación está disponible en este repositorio: DotVVM Reports.

Recursos adicionales

Deseas seguir adquiriendo nuevos conocimientos sobre ASP.NET Core y DotVVM, estos recursos podrían ser de tu interés:

Gracias:

Si tienes alguna inquietud o necesitas ayuda en algo particular, será un gusto poder ayudar.

Nos vemos en Twitter!! :)

¡Hasta pronto!

Top comments (0)