GridView

in namespace DotVVM.Framework.Controls

A multi-purpose grid control with advanced binding and templating options and sorting support.

Usage & Scenarios

A multi-purpose grid control with advanced binding and templating options and sorting support.

Sample 1: Basic GridView

The GridView has the DataSource property which expects either IEnumerable or GridViewDataSet objects.

Columns are defined by placing in the Columns collection.

<dot:GridView DataSource="{value: Customers}">
  <Columns>
    <dot:GridViewTextColumn ValueBinding="{value: Id}" HeaderText="ID"/>
    <dot:GridViewTextColumn ValueBinding="{value: Name}" HeaderText="Name"/>
  </Columns>
</dot:GridView>
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;

namespace DotvvmWeb.Views.Docs.Controls.builtin.GridView.sample1
{
    public class ViewModel : DotvvmViewModelBase
    {
        private static IQueryable<Customer> GetData()
        {
            return new[]
            {
                new Customer(0, "Dani Michele"), new Customer(1, "Elissa Malone"), new Customer(2, "Raine Damian"),
                new Customer(3, "Gerrard Petra"), new Customer(4, "Clement Ernie"), new Customer(5, "Rod Fred"),
                new Customer(6, "Oliver Carr"), new Customer(7, "Jackson James"), new Customer(8, "Dexter Nicholson"),
                new Customer(9, "Jamie Rees"), new Customer(10, "Jackson Ross"), new Customer(11, "Alonso Sims"),
                new Customer(12, "Zander Britt"), new Customer(13, "Isaias Ford"), new Customer(14, "Braden Huffman"),
                new Customer(15, "Frederick Simpson"), new Customer(16, "Charlie Andrews"), new Customer(17, "Reuben Byrne")
            }.AsQueryable();
        }

        public GridViewDataSet<Customer> Customers { get; set; }

        public override Task PreRender()
        {
            // fill data set from IQueryable
            Customers.LoadFromQueryable(GetData());

            // NOTE: You can also fill the DataSet manually.
            // Just set the Items, PageSize, PageIndex 
            // and TotalItemsCount properties

            return base.PreRender();
        }

        public ViewModel()
        {
            // creates new GridViewDataSet and sets PageSize
            Customers = new GridViewDataSet<Customer>() { PageSize = 4 };
        }

    }


    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public Customer()
        {
            // NOTE: This default constructor is required. 
            // Remember that the viewmodel is JSON-serialized
            // which requires all objects to have a public 
            // parameterless constructor
        }

        public Customer(int id, string name)
        {
            Id = id;
            Name = name;
        }
    }
}

Sample 2: GridViewTextColumn

Each column in the grid must be declared in the <Columns></Columns> collection. GridViewTextColumn displays the field as plain text.

 

Required Properties

The most important property is the ValueBinding which contains a binding which selects the property to display from the object.

You can customize the header cell using the HeaderText property, or the HeaderTemplate template.

 

Sorting

There is also a property AllowSorting which can be used to sort the column. If it is set to true, you can also use the SortExpression property to specify which column should be used for sorting. It is useful when the values in the column are e.g. 'lowest', 'normal' and 'highest' and you don't need to order them alphabetically, but you have another column with numeric representation of those values. In that case, you can use the name of such column as a SortExpression.

 

Styling

The Width property allows to set the width of the column. It is rendered as style="width: XXX" attribute on the <th> element in the table header.

You can specify CssClass to be applied on each table cell <td>. This property supports data-binding.

There is also the HeaderCssClass property that adds the specified CSS class to the <th> element in the table header.

 

Formatting

Use the FormatString property to specify the format of numbers or date-time values. Most of the .NET Framework format strings is supported.

<dot:GridView DataSource="{value: Customers}">
  <Columns>
    <dot:GridViewTextColumn ValueBinding="{value: Id}" 
                            HeaderText="ID" 
                            CssClass="{value: Id % 2 == 0 ? 'alternate' : ''}"
                            HeaderCssClass="header"
                            Width="50px" />
    
    <dot:GridViewTextColumn ValueBinding="{value: Name}" 
                            CssClass="{value: Id % 2 == 0 ? 'alternate' : ''}" 
                            HeaderCssClass="header" 
                            AllowSorting="false">
      <HeaderTemplate>
        <img src="~/images/person.png"/> Person
      </HeaderTemplate>
    </dot:GridViewTextColumn>

    <dot:GridViewTextColumn ValueBinding="{value: Date}"
                        HeaderText="Date"
                        CssClass="{value: Id % 2 == 0 ? 'alternate' : ''}"
                        HeaderCssClass="header"
                        FormatString="d.M.yyyy"
                        Width="50px" />
    
  </Columns>
</dot:GridView>
using System;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;

namespace DotvvmWeb.Views.Docs.Controls.builtin.GridView.sample2
{
    public class ViewModel : DotvvmViewModelBase
    {
        private static IQueryable<Customer> GetData()
        {
            return new[]
            {
                new Customer(0, "Dani Michele"), new Customer(1, "Elissa Malone"), new Customer(2, "Raine Damian"),
                new Customer(3, "Gerrard Petra"), new Customer(4, "Clement Ernie"), new Customer(5, "Rod Fred"),
                new Customer(6, "Oliver Carr"), new Customer(7, "Jackson James"), new Customer(8, "Dexter Nicholson"),
                new Customer(9, "Jamie Rees"), new Customer(10, "Jackson Ross"), new Customer(11, "Alonso Sims"),
                new Customer(12, "Zander Britt"), new Customer(13, "Isaias Ford"), new Customer(14, "Braden Huffman"),
                new Customer(15, "Frederick Simpson"), new Customer(16, "Charlie Andrews"), new Customer(17, "Reuben Byrne")
            }.AsQueryable();
        }

        public GridViewDataSet<Customer> Customers { get; set; }

        public override Task PreRender()
        {
            // fill data set from IQueryable
            Customers.LoadFromQueryable(GetData());

            // NOTE: You can also fill the DataSet manually.
            // Just set the Items, PageSize, PageIndex 
            // and TotalItemsCount properties

            return base.PreRender();
        }

        public ViewModel()
        {
            // creates new GridViewDataSet and sets PageSize
            Customers = new GridViewDataSet<Customer>() { PageSize = 4 };
        }

    }


    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime Date { get; set; }

        public Customer()
        {
            // NOTE: This default constructor is required. 
            // Remember that the viewmodel is JSON-serialized
            // which requires all objects to have a public 
            // parameterless constructor
        }

        public Customer(int id, string name)
        {
            Id = id;
            Name = name;
            Date = new DateTime(2000, 1, 1).AddDays(id);
        }
    }
}

Sample 3: GridViewTemplateColumn

GridViewTemplateColumn allows to render custom content inside the table cell.

 

Required Properties

The most important property is the ContentTemplate which defines the content of each table cell.

You can also customize the header cell using the HeaderText property, or the HeaderTemplate template.

 

The sorting and styling properties are the same as in the GridViewTextColumn.

<dot:GridView DataSource="{value: Customers}">
  <Columns>
    <dot:GridViewTextColumn ValueBinding="{value: Id}" HeaderText="ID" />
    <dot:GridViewTemplateColumn HeaderText="Avatar">
      <ContentTemplate>
        <img src="{value: '../images/' + Id + '.png'}" 
             alt="{value: Name}" style="height: 40px"/>
      </ContentTemplate>
    </dot:GridViewTemplateColumn>
  </Columns>
</dot:GridView>
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;

namespace DotvvmWeb.Views.Docs.Controls.builtin.GridView.sample3
{
    public class ViewModel : DotvvmViewModelBase
    {
        private static IQueryable<Customer> GetData()
        {
            return new[]
            {
                new Customer(0, "Dani Michele"), new Customer(1, "Elissa Malone"), new Customer(2, "Raine Damian"),
                new Customer(3, "Gerrard Petra"), new Customer(4, "Clement Ernie"), new Customer(5, "Rod Fred"),
                new Customer(6, "Oliver Carr"), new Customer(7, "Jackson James"), new Customer(8, "Dexter Nicholson"),
                new Customer(9, "Jamie Rees"), new Customer(10, "Jackson Ross"), new Customer(11, "Alonso Sims"),
                new Customer(12, "Zander Britt"), new Customer(13, "Isaias Ford"), new Customer(14, "Braden Huffman"),
                new Customer(15, "Frederick Simpson"), new Customer(16, "Charlie Andrews"), new Customer(17, "Reuben Byrne")
            }.AsQueryable();
        }

        public GridViewDataSet<Customer> Customers { get; set; }

        public override Task PreRender()
        {
            // fill data set from IQueryable
            Customers.LoadFromQueryable(GetData());

            // NOTE: You can also fill the DataSet manually.
            // Just set the Items, PageSize, PageIndex 
            // and TotalItemsCount properties

            return base.PreRender();
        }

        public ViewModel()
        {
            // creates new GridViewDataSet and sets PageSize
            Customers = new GridViewDataSet<Customer>() { PageSize = 4 };
        }

    }


    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public Customer()
        {
            // NOTE: This default constructor is required. 
            // Remember that the viewmodel is JSON-serialized
            // which requires all objects to have a public 
            // parameterless constructor
        }

        public Customer(int id, string name)
        {
            Id = id;
            Name = name;
        }
    }
}

Sample 4: Binding to a Collection

You don't have to use GridViewDataSets if you don't want. Use a normal .NET collection as the DataSource.

If the user wants to sort, there is the SortChanged command which fires when the user clicks the column header.

Notice that the method is on the main viewmodel object has parameters, however the command doesn't specify them, it is just {command: Sort}. That's because the SortChanged event expects a delegate to a command, not a command itself. You can distinguish between standard events and event delegates by the type in the Events table.

If the type is Command, it is a standard command. If the type is Command Delegate, it is a delegate command.

The Sort method in the viewmodel accepts one parameter of string.

<dot:GridView DataSource="{value: Customers}" SortChanged="{command: Sort}">
  <Columns>
    <dot:GridViewTextColumn ValueBinding="{value: Id}" 
                            HeaderText="ID" AllowSorting="true" />
    
    <dot:GridViewTextColumn ValueBinding="{value: Name}" 
                            HeaderText="Name" AllowSorting="true"/>
  </Columns>
</dot:GridView>
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.ViewModel;

namespace DotvvmWeb.Views.Docs.Controls.builtin.GridView.sample4
{
    public class ViewModel : DotvvmViewModelBase
    {
        public Customer[] Customers { get; set; } = {
            new Customer(0, "Dani Michele"), new Customer(1, "Elissa Malone"),new Customer(2,"Raine Damian"),
            new Customer(3, "Gerrard Petra"), new Customer(4, "Clement Ernie"), new Customer(5, "Rod Fred")
        };

        public string SelectedSortColumn { get; set; }

        public void Sort(string column)
        {
            SelectedSortColumn = column;
        }

        public override Task PreRender()
        {
            switch (SelectedSortColumn)
            {
                case "Name":
                    Customers = Customers.OrderBy(c => c.Name).ToArray();
                    break;
                case "Id":
                    Customers = Customers.OrderBy(c => c.Id).ToArray();
                    break;
            }
            return base.PreRender();
        }
    }

    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public Customer()
        {
            // NOTE: This default constructor is required. 
            // Remember that the viewmodel is JSON-serialized
            // which requires all objects to have a public 
            // parameterless constructor
        }

        public Customer(int id, string name)
        {
            Id = id;
            Name = name;
        }
    }
}

Sample 5: RowDecorators

Sometimes you need the rows in the grid to be clickable, or to have some specific color. That's why GridView can apply decorators to each table row. A decorator can add various attributes to the element it decorates.

<dot:GridView DataSource="{value: Customers}">
  <RowDecorators>
    <dot:Decorator Events.Click="{command: _parent.RowClicked(Id)}"
                   class="clickable"/>
  </RowDecorators>
  <Columns>
    <dot:GridViewTextColumn ValueBinding="{value: Id}" 
                            HeaderText="ID" />
    <dot:GridViewTextColumn ValueBinding="{value: Name}" 
                            HeaderText="Name" />
  </Columns>
</dot:GridView>

<p>Last clicked row: {{value: ClickedRowId}}</p>
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.ViewModel;

namespace DotvvmWeb.Views.Docs.Controls.builtin.GridView.Sample5
{
    public class ViewModel : DotvvmViewModelBase
    {
        public Customer[] Customers { get; set; } = {
            new Customer(0, "Dani Michele"), new Customer(1, "Elissa Malone"),new Customer(2,"Raine Damian"),
            new Customer(3, "Gerrard Petra"), new Customer(4, "Clement Ernie"), new Customer(5, "Rod Fred")
        };

        public string ClickedRowId { get; set; }

        public void RowClicked(int id)
        {
            ClickedRowId = id.ToString();
        }

    }
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public Customer()
        {
            // NOTE: This default constructor is required. 
            // Remember that the viewmodel is JSON-serialized
            // which requires all objects to have a public 
            // parameterless constructor
        }

        public Customer(int id, string name)
        {
            Id = id;
            Name = name;
        }
    }
}

Sample 6: Inline Editing

The InlineEditing property enables the row editing mode in the GridView control.

You have to do the following things to make the inline editing work:

  • Bind the GridView control to the GridViewDataSet<T>, binding to simple collections is not supported in the inline-editing mode.

  • Set the PrimaryKeyPropertyName on the data set to a name of the column having unique values in each row. Typically you need to place the primary key column name in this property (Id, CustomerId etc.). It should be a value that works with the === operator in Javascript, so we recommend to use integer, string or Guid values.

  • If you want to edit some row, set the EditedRowId on the GridViewDataSet to the value of the primary key of the row. The row will become editable. If you want to exit from the edit mode, set the EditedRowId to null.

  • If you want to make some column read-only, set its IsEditable property to false.

  • If you don't want to use the default GridViewTextColumn, which renders a Literal in the read-only mode and the TextBox in the edit mode, use the GridViewTemplateColumn and use its EditTemplate to specify how the cell will look like when in the edit mode.

If you use the RowDecorators property (see Sample 5), they are applied only to normal rows. If you need to apply a decorator to edit-mode rows, use the EditRowDecorators property.

<dot:GridView DataSource="{value: Customers}" InlineEditing="true">
  <Columns>
    <dot:GridViewTextColumn ValueBinding="{value: Id}" 
                            HeaderText="ID" 
                            IsEditable="false" />
    
    <dot:GridViewTextColumn ValueBinding="{value: Name}" 
                            HeaderText="Name" />

    <dot:GridViewTemplateColumn AllowSorting="false">
      <ContentTemplate>
        <dot:Button Text="Edit" Click="{command: _parent.Edit(_this)}" />
      </ContentTemplate>
      <EditTemplate>
        <dot:Button Text="Save" Click="{command: _parent.Update(_this)}" />
        <dot:Button Text="Cancel" Click="{command: _parent.CancelEdit()}" />
      </EditTemplate>
    </dot:GridViewTemplateColumn>
  
  </Columns>
</dot:GridView>
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Configuration;
using System.Web.UI.WebControls;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;

namespace DotvvmWeb.Views.Docs.Controls.builtin.GridView.Sample6
{
    public class ViewModel : DotvvmViewModelBase
    {

        public GridViewDataSet<Customer> Customers { get; set; } = new GridViewDataSet<Customer>()
        {
            PrimaryKeyPropertyName = "Id"
        };

        public override Task PreRender()
        {
            if (!Context.IsPostBack)
            {
                // fill the dataset for the first time
                Refresh();
            }
            return base.PreRender();
        }

        private void Refresh()
        {
            // TODO: load data from the database
            Customers.Items = new List<Customer>()
            {
                new Customer(0, "Dani Michele"), new Customer(1, "Elissa Malone"), new Customer(2, "Raine Damian"),
                new Customer(3, "Gerrard Petra"), new Customer(4, "Clement Ernie"), new Customer(5, "Rod Fred")
            };
            Customers.TotalItemsCount = Customers.Items.Count;
        }

        public void Edit(Customer customer)
        {
            Customers.EditRowId = customer.Id;
        }

        public void Update(Customer customer)
        {
            // TODO: save changes to the database
            Customers.EditRowId = null;

            // uncomment this line - it's here only for the sample to work without database
            //Refresh();
        }

        public void CancelEdit()
        {
            Customers.EditRowId = null;

            // uncomment this line - it's here only for the sample to work without database
            //Refresh();
        }


    }

    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public Customer()
        {
            // NOTE: This default constructor is required. 
            // Remember that the viewmodel is JSON-serialized
            // which requires all objects to have a public 
            // parameterless constructor
        }

        public Customer(int id, string name)
        {
            Id = id;
            Name = name;
        }
    }
}

Properties

Name Type Description Notes Default Value
property icon ClientIDMode ClientIDMode Gets or sets the client ID generation algorithm.
attribute
inner element
static value
bindable
default
1
property icon Columns List<GridViewColumn> Gets or sets a collection of columns that will be placed inside the grid.
attribute
inner element
static value
bindable
default
null
property icon DataContext Object Gets or sets a data context for the control and its children. All value and command bindings are evaluated in context of this value.
attribute
inner element
static value
bindable
default
null
property icon DataSource Object Gets or sets the source collection or a GridViewDataSet that contains data in the control.
attribute
inner element
static value
bindable
default
null
property icon EditRowDecorators List<Decorator> Gets or sets a list of decorators that will be applied on each row which is in edit mode.
attribute
inner element
static value
bindable
default
null
property icon EmptyDataTemplate ITemplate Gets or sets the template which will be displayed when the DataSource is empty.
attribute
inner element
static value
bindable
default
null
property icon FilterPlacement GridViewFilterPlacement Gets or sets the place where the filters will be created.
attribute
inner element
static value
bindable
default
0
property icon ID String Gets or sets the unique control ID.
attribute
inner element
static value
bindable
default
null
property icon InlineEditing Boolean Gets or sets whether the inline editing is allowed in the Grid. If so, you have to use a GridViewDataSet as the DataSource.
attribute
inner element
static value
bindable
default
False
property icon InnerText String Gets or sets the inner text of the HTML element.
attribute
inner element
static value
bindable
default
null
property icon RowDecorators List<Decorator> Gets or sets a list of decorators that will be applied on each row which is not in the ediit mode.
attribute
inner element
static value
bindable
default
null
property icon ShowHeaderWhenNoData Boolean Gets or sets whether the header row should be displayed when the grid is empty.
attribute
inner element
static value
bindable
default
False
property icon SortChanged Action<String> Gets or sets the command that will be triggered when the user changed the sort order.
attribute
inner element
static value
bindable
default
null
property icon Visible Boolean Gets or sets whether the control is visible.
attribute
inner element
static value
bindable
default
True

HTML produced by the control

The control render a classic HTML table:

<table>
  <thead>
    <tr>
	  <th><a href="...">Id</a></th>
	  <th><a href="...">Customer Name</a></th>
	</tr>
  </thead>

  <tbody>
    <tr>
	  <td><span data-bind="..."></span></td>
	  <td><span data-bind="..."></span></td>
	</tr>
  </tbody>
</table>

In the Client rendering mode, only one row is rendered and the Knockout foreach binding is applied to the tbody element.

In the Server rendering mode, all rows are rendered on the server.