Reports in DotVVM with GridView, CheckBox, and TextBox controls
Tags: webdev, html, dotnet, dotvvm
Published: 2020-06-15 22:17:48

A table is a set of organized cells within which we can host different contents. This type of element is quite useful when making a report to display some specific information. 

In previous articles on ASP.NET Core and DotVVM, we could generally see how to use predefined controls of these tools for data visualization as a report. Here are some of those articles:

+ [DotVVM and ASP.NET Core: Implementing CRUD operations](https://dev.to/dotvvm/dotvvm-and-asp-net-core-implementing-crud-operations-l2e).

+ [Working with ASP.NET Core and DotVVM on Visual Studio Code](https://dev.to/dotvvm/working-with-asp-net-core-and-dotvvm-on-visual-studio-code-3h7b).

Also, when we manage forms to manage information, we need to create tables before we can view the processed data. Here are some previous articles in case you want to learn how to design HTML forms:

+ [Web forms with DotVVM controls](https://dev.to/dotvvm/web-forms-with-dotvvm-controls-6bk).

+ [Web forms with DotVVM Business Pack](https://dev.to/dotvvm/web-forms-with-dotvvm-business-pack-gl1).

This time, we will learn the basics of visualizing certain data and establishing some search criteria with C# and HTML, through DotVVM's controls in ASP.NET Core. 

Note: The project source code that we'll discuss in this article can be found in this GitHub repository: [DotVVM Reports](https://github.com/esdanielgomez/DotVVMReports).

####Design Pattern: Model, View, ViewModel - MVVM

An important aspect to mention is on the basis of DotVVM. This framework is based on the Model, View, View model over .NET design pattern for communication between HTML (web pages) and C- (source code). The purpose of these parts are as follows:

+ **The model**. — is responsible for all application data and related business logic.

+ **The view**. — Representations for the end user of the application model. The view is responsible for displaying the data to the user and allowing manipulation of the application data.

+ **Model-View or View-Model**. — one or more per view; the model-view is responsible for implementing view behavior to respond to user actions and for easily exposing model data.

####Report with ASP.NET Core and DotVVM

To exemplify the use of some DotVVM controls for reporting, we have a small application like this:

![](https://dev-to-uploads.s3.amazonaws.com/i/2o6qmhfjukd8saikm1rl.png)

Considering the design pattern MVVM – Model, View, ViewModel, we will analyze in general each of these parts for this project.

**Model**

Considering that the application data and related business logic is handled in this section, then we'll see how the corresponding data and services are handled. 

The database consists of two tables: `Person` and `PersonType`.

![](https://dev-to-uploads.s3.amazonaws.com/i/mkyuk0nqianq04z5v6cr.png)

The SQL statements for creating these tables, their attributes, and inserting some records are as follows:

```sql
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');
```

With the database set, the data access layer part refers to the definition of classes to work with the database features and the context to establish communication between ASP.NET Core and the database, which in this case MySQL is the one being used. 

For this purpose, we need to install three NuGet packages:

+ `Microsoft.EntityFrameworkCore.Design`
+ `Microsoft.EntityFrameworkCore.Tools`
+ `MySql.Data.EntityFrameworkCore`

Now, we need to use the package management console to scaffold from the database (automatically generate the context and feature classes) using the following command: 

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

With this first part, the connection to the database is ready. What follows is the definition of models with which the website will be worked. These models are:

```csharp
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; }
}
```

```csharp
public class PersonTypeModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}
```

For each of these models there is a service, which has the following operations:

*PersonService*:

+ `GetAllPersonsAsync()`
+ `GetPersonByIdAsync(int personId)`
+ `GetPersonByIdAndTypeAsync(int personId, int personTypeId)`
+ `GetAllPersonsByTypeAsync(int personTypeId)`

*PersonTypeService*:

+ `GetAllPersonTypesAsync()`
+ `GetPersonTypeByIdAsync(int personTypeId)`

In Visual Studio 2019 we'll have something like this: 

![](https://dev-to-uploads.s3.amazonaws.com/i/nmobwig7nrjcfg4etc10.png)

**Vistamodel**

```csharp
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);
            }
        }
    }
}
```

**View**

```html
<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>
```

####Web application analysis

In the following GIF we can see in a general way the interaction with this small web page. 

The first element we will analyze is the `GridView`, a DotVVM control that allows us tables to represent specific data. This component allows us to specify the data source through the `DataSource` property, in this case, the data source is defined as follows: 

```html
public GridViewDataSet<PersonModel> Persons { get; set; } = new GridViewDataSet<PersonModel>();
```

The data source, in addition to a list of type `GridViewDataSet`, can also be defined through another collection of type `List`. The `GridViewTextColumn` tag is used for column definition. In this case, we can find the columns `Id`, `FirstName`, `LastName` and `Type`. These names come from the data type of the data source, in this case, from the `PersonModel` model.

```html
<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>
```

Another gridview sub-tags is `EmptyDataTemplate`. This tag allows us to display some HTML content in case the list of elements is empty. In the end, with the `GridView` we will visualize something like this:

![](https://dev-to-uploads.s3.amazonaws.com/i/u13zu1rc9dacnlfnhg8s.png)

Learn more about the `GridView` control here:[https://www.dotvvm.com/docs/controls/builtin/GridView/2.0](https://www.dotvvm.com/docs/controls/builtin/GridView/2.0).

However, from this table there are several operations that can be performed, for example, to set additional components to create search criteria and update this table based on the search. 

The first case is using a DotVVM `CheckBox`. As in HTML or any other design environment, the `CheckBox` has the role as a check box for selecting items in an option set. For this example, the goal is to have two check boxes, which correspond to the types of people. Depending on the selection, either Type A, Type B, or both, the table of records will be updated in accordance with this decision. 

In the view part, we find the `CheckedItems` property that stores the value of the selected items. We also find the Changed property, which allows us to specify the method that will perform the actions when this element is activated or disabled.

```html
<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" />
```

In the update method, for example, if we select one of the two types, then we will query the database according to the defined service: `PersonService`, to get the list of people according to the selected id. With this list retrieved, we will update the database by re-setting the items in the `GridView` data source.

```csharp
int IdPersonType = PersonTypes.FirstOrDefault();
Persons.Items = await personService.GetAllPersonsByTypeAsync(IdPersonType);
SearchByTextVisible = true;
```

Something similar will happen if we don't select any of the checkboxes. In this case we will only clean the items of the `GridView`.

```csharp
Persons.Items.Clear();
```

As we saw in the GIF, the result of using the `CheckBox` control is as follows:

![](https://dev-to-uploads.s3.amazonaws.com/i/5axb2uz102qlgbom29k3.png)

Learn more about the `CheckBox` control here:[https://www.dotvvm.com/docs/controls/builtin/CheckBox/2.0](https://www.dotvvm.com/docs/controls/builtin/CheckBox/2.0).

Another of the controls that allow us to continue adding functionality to the `GridView` to set search criteria to this report are the `TextBox` and 'Button' elements. In this case, these components can be used to search for something specific to the report through a text entry. To exemplify, in this application, controls are used to find a specific person according to their `Id`.

```html
<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}" />
``` 
Updating the elements of the `GridView` is similar to the `CheckBox` case. The result is as follows:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pglq4x83cpt87782txse.png)

All the information about the `TextBox` control can be found in: [https://www.dotvvm.com/docs/controls/builtin/TextBox/2.0](https://www.dotvvm.com/docs/controls/builtin/TextBox/2.0). And the button control in: [https://www.dotvvm.com/docs/controls/builtin/Button/2.0](https://www.dotvvm.com/docs/controls/builtin/Button/2.0). 

####What's next?

With this article, we learned certain features of the `GridView`, `CheckBox`, `TextBox`, and `Button` components to display a list of data and set search criteria through the Model, View, ViewModel design pattern in ASP.NET Core and DotVVM. 

The source code for this implementation is available in this repository: [DotVVM Reports](https://github.com/esdanielgomez/DotVVMReports).

**Additional resources**

Want to continue to acquire new knowledge about ASP.NET Core and DotVVM?, these resources might be of interest to you:

+ [DotVVM and ASP.NET Core: Implementing CRUD operations](https://dev.to/dotvvm/dotvvm-and-asp-net-core-implementing-crud-operations-l2e).

+ [Developing web applications with ASP.NET Core, DotVVM and MongoDB](https://dev.to/dotvvm/developing-web-applications-with-net-core-dotvvm-and-mongodb-286l).

**Thank you!**:

If you have any concerns or need help in something particular, it will be a pleasure to be able to help.

See you in [Twitter](https://twitter.com/esDanielGomez)!! :)