GridView
in namespace DotVVM.Framework.Controls
A multi-purpose grid control with advanced binding, templating options and sorting support.
Usage & Scenarios
A multi-purpose grid control with advanced binding, 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.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> FakeDb()
{
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; } = new GridViewDataSet<Customer>() { PagingOptions = { PageSize = 4} };
public override Task PreRender()
{
if (Customers.IsRefreshRequired)
{
var queryable = FakeDb();
Customers.LoadFromQueryable(queryable);
}
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 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> FakeDb()
{
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; } = new GridViewDataSet<Customer>() { PagingOptions = { PageSize = 4} };
public override Task PreRender()
{
if (Customers.IsRefreshRequired)
{
var queryable = FakeDb();
Customers.LoadFromQueryable(queryable);
}
return base.PreRender();
}
}
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> FakeDb()
{
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; } = new GridViewDataSet<Customer>() { PagingOptions = { PageSize = 4} };
public override Task PreRender()
{
if (Customers.IsRefreshRequired)
{
var queryable = FakeDb();
Customers.LoadFromQueryable(queryable);
}
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 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.Controls;
using DotVVM.Framework.ViewModel;
namespace DotvvmWeb.Views.Docs.Controls.builtin.GridView.sample4
{
public class ViewModel : DotvvmViewModelBase
{
private static IQueryable<Customer> FakeDb()
{
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")
}.AsQueryable();
}
public GridViewDataSet<Customer> Customers { get; set; } = new GridViewDataSet<Customer>() { PagingOptions = { PageSize = 4 } };
public string SelectedSortColumn { get; set; }
public override Task PreRender()
{
if (Customers.IsRefreshRequired)
{
var queryable = FakeDb();
Customers.LoadFromQueryable(queryable);
}
return base.PreRender();
}
public void Sort(string column)
{
SelectedSortColumn = column;
}
}
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 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 theGridViewDataSet<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 theGridViewDataSet
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 theEditedRowId
tonull
.If you want to make some column read-only, set its
IsEditable
property tofalse
.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 theGridViewTemplateColumn
and use itsEditTemplate
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 & Reset" Click="{command: _parent.CancelEdit()}" />
</EditTemplate>
</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.Sample6
{
public class ViewModel : DotvvmViewModelBase
{
private static IQueryable<Customer> FakeDb()
{
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")
}.AsQueryable();
}
public GridViewDataSet<Customer> Customers { get; set; } = new GridViewDataSet<Customer>() { RowEditOptions = { PrimaryKeyPropertyName = "Id" } };
public void Edit(Customer customer)
{
Customers.RowEditOptions.EditRowId = customer.Id;
}
public override Task PreRender()
{
if (Customers.IsRefreshRequired)
{
var queryable = FakeDb();
Customers.LoadFromQueryable(queryable);
}
return base.PreRender();
}
public void Update(Customer customer)
{
// TODO: save changes to the database
Customers.RowEditOptions.EditRowId = null;
// uncomment this line - it's here only for the sample to work without database
//Customers.RequestRefresh();
}
public void CancelEdit()
{
Customers.RowEditOptions.EditRowId = null;
// Refresh GridView items
Customers.RequestRefresh();
}
}
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 | |
---|---|---|---|---|---|
Attributes | Dictionary<String,Object> |
attribute
static value
|
null | ||
ClientIDMode | ClientIDMode | Gets or sets the client ID generation algorithm. |
attribute
static value
|
Static | |
Columns | List<GridViewColumn> | Gets or sets a collection of columns that will be placed inside the grid. |
inner element
static value
default
|
null | |
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
static value
bindable
|
null | |
DataSource | Object | Gets or sets the source collection or a GridViewDataSet that contains data in the control. |
attribute
bindable
|
null | |
EditRowDecorators | List<Decorator> | Gets or sets a list of decorators that will be applied on each row in edit mode. |
inner element
static value
|
null | |
EmptyDataTemplate | ITemplate | Gets or sets the template which will be displayed when the DataSource is empty. |
inner element
static value
bindable
|
null | |
FilterPlacement | GridViewFilterPlacement | Gets or sets the place where the filters will be created. |
attribute
static value
bindable
|
HeaderRow | |
ID | String | Gets or sets the unique control ID. |
attribute
static value
bindable
|
null | |
IncludeInPage | Boolean | Gets or sets whether the control is included in the DOM of the page. |
attribute
bindable
|
True | |
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
static value
|
False | |
InnerText | String | Gets or sets the inner text of the HTML element. |
attribute
static value
bindable
|
null | |
RowDecorators | List<Decorator> | Gets or sets a list of decorators that will be applied on each row which is not in the edit mode. |
inner element
static value
|
null | |
ShowHeaderWhenNoData | Boolean | Gets or sets whether the header row should be displayed when the grid is empty. |
attribute
static value
|
False | |
SortChanged | Action<String> | Gets or sets the command that will be triggered when the user changed the sort order. |
attribute
bindable
|
null | |
Visible | Boolean | Gets or sets whether the control is visible. |
attribute
bindable
|
True |
HTML produced by the control
The control renders 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.