GridView

in namespace DotVVM.BusinessPack.Controls

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

Usage & Scenarios

This control is different from the built-in GridView and is not derived from it.

The Business Pack GridView control is a advanced grid control with many features.

The version 1.1 supports the following features (except of the features supported in the built-in GridView):

  • Inline Insert row
  • Column Hiding
  • Column Reordering
  • Column Resizing
  • Row Reordering

The following features are planned to be added in the following releases:

  • Customizable Filters
  • Grouping
  • Row Detail

Sample 1: Basic Usage

The DataSource property expects BusinessPackDataSet object and defines the data for the control.

The Columns collection specifies all columns in the control.

The HeaderTemplate property of the column defines the text displayed in the column header.

Column Types

The <bp:GridViewTextColumn> renders a text, numeric or date values in the cell. The ValueBinding expression specifies the property to be rendered. The FormatString property specifies the format of the value (for numeric and date columns).

The <bp:GridViewTemplateColumn> renders a specified template in the grid cell.

<bp:GridView DataSource="{value: Customers}">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}" HeaderText="ID" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}" HeaderText="Name" />
        <bp:GridViewTextColumn ValueBinding="{value: BirthDate}" HeaderText="Birth Date"
                               FormatString="dd.MM.yyyy" />
        <bp:GridViewTemplateColumn>
            <ContentTemplate>
                <b>{{value: Orders}}</b>
            </ContentTemplate>
        </bp:GridViewTemplateColumn>
    </Columns>
</bp:GridView>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;


namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample1
{
    public class ViewModel : DotvvmViewModelBase
    {
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> 
            {
                OnLoadingData = GetData,
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", BirthDate = DateTime.Now.AddYears(-i), Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample1
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 2: Grid Headers

When the DataSource is empty, the grid will not appear at all by default. The ShowHeaderWhenNoData property can be used to make the grid header visible even if there are no data.

The HeaderCssClass property of the column sets the CSS class to the column header cell.

To place custom content in the header cell, you can use the HeaderTemplate property.

<bp:GridView DataSource="{value: Customers}"
             ShowHeaderWhenNoData="true">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}"
                               HeaderText="Customer ID" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}"
                               HeaderCssClass="gridview-header-highlight">
            <HeaderTemplate>
                <i>Name</i>
            </HeaderTemplate>
        </bp:GridViewTextColumn>
    </Columns>
</bp: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.businesspack.GridView.sample2
{
    public class ViewModel : DotvvmViewModelBase
    {
        public bool ShowHeaderWhenNoData { get; set; }
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> 
            {
                OnLoadingData = GetData,
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}" });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample2
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 3: Grid Footer

The ShowFooter specifies whether the row footer is displayed or not. By default, it is hidden.

The FooterTemplate property of the column can be used to customize the content of the column footer cell.

<bp:GridView DataSource="{value: Customers}"
             ShowFooter="true">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}" HeaderText="ID" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}" HeaderText="Name" />
        <bp:GridViewTextColumn ValueBinding="{value: Orders}" HeaderText="Orders" 
                               FooterCssClass="gridview-footer">
            <FooterTemplate>
                <p>Total orders: {{value: TotalOrders}}</p>
            </FooterTemplate>
        </bp:GridViewTextColumn>
    </Columns>
</bp: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.businesspack.GridView.sample3
{
    public class ViewModel : DotvvmViewModelBase
    {
        public int TotalOrders => Customers.Items.Sum(c => c.Orders);

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

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> 
            {
                OnLoadingData = GetData,
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample3
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 4: Sorting

By default, the sorting is not enabled on any column. You can use the AllowSorting property to enable it.

The columns which have the ValueBinding, will sort using the specified expression by default. If the column doesn't have this property, or you need to use another column for sorting, you can use the SortExpression property. This property takes precedence over the ValueBinding.

To customize the icons for sorting, you can use the SortAscendingHeaderCssClass and SortDescendingHeaderCssClass properties which specify the CSS class to be added to the header of the column which is used for the searching.

You can also set these properties on the GridView control instead of declaring them for each column separately, using GridViewColumn.SortAscendingHeaderCssClass="value".

<bp:GridView DataSource="{value: Customers}">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}"
                               HeaderText="Id"
                               AllowSorting="true"
                               SortAscendingHeaderCssClass="sort-asc-custom"
                               SortDescendingHeaderCssClass="sort-desc-custom" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}"
                               HeaderText="Name"
                               AllowSorting="true"
                               SortExpression="LastName" />
        <bp:GridViewTextColumn ValueBinding="{value: Orders}"
                               HeaderText="Orders"
                               AllowSorting="true" />
    </Columns>
</bp: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.businesspack.GridView.sample4
{
    public class ViewModel : DotvvmViewModelBase
    {
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> 
            {
                OnLoadingData = GetData,
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample4
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 5: Paging

The paging relies on the DataPager control and the use of the BusinessPackDataSet object.

<bp:GridView DataSource="{value: Customers}">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}" HeaderText="ID" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}" HeaderText="Name" />
        <bp:GridViewTextColumn ValueBinding="{value: BirthDate}" HeaderText="Birth Date" 
                               FormatString="dd.MM.yyyy" />
        <bp:GridViewTextColumn ValueBinding="{value: Orders}" HeaderText="Orders" />
    </Columns>
</bp:GridView>

<bp:DataPager DataSet="{value: Customers}" />
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;


namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample5
{
    public class ViewModel : DotvvmViewModelBase
    {
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> 
            {
                OnLoadingData = GetData,
                PagingOptions =
                {
                    PageSize = 5
                },
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };            

            return base.Init();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", BirthDate = DateTime.Now.AddYears(-i), Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample5
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 6: Inline Editing

The InlineEditing property can be use to enable the user edit rows directly in the grid.

Every column has the IsEditable property which specifies whether the column can be edited or not.

The columns also have the EditTemplate property which can be used to define a custom edit template for the cell.

The object that is currently being edited, is identified by the Customers.RowEditOptions.EditRowId property which contains the primary key of the edited object. The name of the property which is a primary key, is stored in Customers.RowEditOptions.PrimaryKeyPropertyName.

<bp:GridView DataSource="{value: Customers}"
             InlineEditing="true">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}"
                               HeaderText="ID"
                               IsEditable="false" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}"
                               HeaderText="Name" />
        <bp:GridViewTemplateColumn HeaderText="Birthdate">
            <ContentTemplate>
                <dot:Literal Text="{value: BirthDate}"
                             FormatString="dd.MM.yyyy" />
            </ContentTemplate>
            <EditTemplate>
                <bp:DateTimePicker SelectedDate="{value: BirthDate}"
                                   FormatString="dd.MM.yyyy"
                                   Mode="Date" />
            </EditTemplate>
        </bp:GridViewTemplateColumn>
        <bp:GridViewTextColumn ValueBinding="{value: Orders}" />
        <bp:GridViewTemplateColumn>
            <ContentTemplate>
                <dot:Button Text="Edit" Click="{command: _parent.EditCustomer(_this)}"/>
            </ContentTemplate>
            <EditTemplate>
                <dot:Button Text="Save" Click="{command: _parent.UpdateCustomer(_this)}"/>
                <dot:Button Text="Cancel" Click="{command: _parent.CancelEditCustomer()}"/>
            </EditTemplate>
        </bp:GridViewTemplateColumn>
    </Columns>
</bp:GridView>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.BusinessPack.Controls;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;


namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample6
{
    public class ViewModel : DotvvmViewModelBase
    {
        public bool IsEditing { get; set; }
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> 
            {
                OnLoadingData = GetData,
                RowEditOptions = new RowEditOptions {
                    PrimaryKeyPropertyName = nameof(Customer.Id),
                    EditRowId = -1
                },
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public void EditCustomer(Customer customer)
        {
            Customers.RowEditOptions.EditRowId = customer.Id;
            IsEditing = true;
        }

        public void UpdateCustomer(Customer customer)
        {
            // Submit customer changes to your database..
            CancelEdit();
        }

        private void CancelEdit()
        {
            Customers.RowEditOptions.EditRowId = -1;
            IsEditing = false;
        }

        public void CancelEditCustomer()
        {
            CancelEdit();
            Customers.RequestRefresh(true);
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", BirthDate = DateTime.Now.AddYears(-i), Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample6
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 7: Inline Inserting

The InlineInserting property can enable the inline insert feature on the grid which adds an extra row on the top or the bottom of the table.

The InlineInsertRowPlacement property specifies whether the insert row is placed on the Top or the Bottom of the table.

In the column, you can then specify the InsertTemplate to provide a custom template for a cell in the insert row.

If you need to combine the inline insert with inline edit, you can provide both templates, or set only the EditTemplate. Provided that the InsertTemplate is not set, the EditTemplate is be used.

<bp:GridView DataSource="{value: Customers}"
             InlineInserting="true"
             InlineInsertRowPlacement="Bottom">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}"
                               HeaderText="ID"
                               IsEditable="false" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}"
                               HeaderText="Name" />
        <bp:GridViewTemplateColumn HeaderText="Birthdate">
            <ContentTemplate>
                <dot:Literal Text="{value: BirthDate}"
                             FormatString="dd.MM.yyyy" />
            </ContentTemplate>
            <InsertTemplate>
                <bp:DateTimePicker SelectedDate="{value: BirthDate}"
                                   FormatString="dd.MM.yyyy"
                                   Mode="Date" />
            </InsertTemplate>
        </bp:GridViewTemplateColumn>
        <bp:GridViewTextColumn ValueBinding="{value: Orders}" />
    </Columns>
</bp:GridView>

<br />
<bp:Button Text="Add"
           Click="{command: InsertNewCustomer()}"
           Visible="{value: !IsInserting}" />
<bp:Button Text="Save"
           Click="{command: SaveNewCustomer()}"
           Visible="{value: IsInserting}" />
<bp:Button Text="Cancel"
           Click="{command: CancelInsertNewCustomer()}"
           Visible="{value: IsInserting}" />
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.BusinessPack.Controls;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;


namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample7
{
    public class ViewModel : DotvvmViewModelBase
    {
        public bool IsInserting { get; set; }
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> 
            {
                OnLoadingData = GetData,
                RowEditOptions = new RowEditOptions {
                    PrimaryKeyPropertyName = nameof(Customer.Id)
                },
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public void InsertNewCustomer()
        {
            Customers.RowInsertOptions.InsertedItem = new Customer {
                Id = Customers.Items.Max(c => c.Id) + 1,
                Orders = 0
            };
            IsInserting = true;
        }

        public void CancelInsertNewCustomer()
        {
            Customers.RowInsertOptions.InsertedItem = null;
            IsInserting = false;
        }

        public void SaveNewCustomer()
        {
            // Save inserted item to database
            Customers.Items.Add(Customers.RowInsertOptions.InsertedItem);
            CancelInsertNewCustomer();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", BirthDate = DateTime.Now.AddYears(-i), Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample7
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 8: Advanced Column Types

There are several columns which use various Business Pack controls in the insert and edit mode:

  • the GridViewComboBoxColumn renders a ComboBox control.

  • The GridViewCheckBoxColumn renders a CheckBox control.

The properties of the column have the same names and meaning like the properties of the control inside the cell.

<bp:GridView DataSource="{value: Orders}"
             InlineEditing="true">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}"
                               HeaderText="Order ID" />
        <bp:GridViewComboBoxColumn ValueBinding="{value: DeliveryType}"
                                   DataSourceBinding="{value: _parent.DeliveryTypes}"
                                   HeaderText="Delivery type" />
        <bp:GridViewTemplateColumn HeaderText="Date">
            <ContentTemplate>
                <dot:Literal Text="{value: CreatedDate}"
                             FormatString="dd.MM.yyyy hh:mm" />
            </ContentTemplate>
            <EditTemplate>
                <bp:DateTimePicker SelectedDate="{value: CreatedDate}"
                                   FormatString="dd.MM.yyyy hh:mm"
                                   Mode="DateTime" />
            </EditTemplate>
        </bp:GridViewTemplateColumn>
        <bp:GridViewCheckBoxColumn ValueBinding="{value: IsPaid}"
                                   HeaderText="Is Paid?" />
        <bp:GridViewTemplateColumn>
            <ContentTemplate>
                <bp:Button Text="Edit"
                           Click="{command: _root.Orders.RowEditOptions.EditRowId = Id}" />
            </ContentTemplate>
            <EditTemplate></EditTemplate>
        </bp:GridViewTemplateColumn>
    </Columns>
</bp:GridView>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;


namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample8
{
    public class ViewModel : DotvvmViewModelBase
    {
        public BusinessPackDataSet<Order> Orders { get; set; }
        public List<string> DeliveryTypes { get; set; } = new List<string> { "Post office", "Home" };

        public override Task Init()
        {
            Orders = new BusinessPackDataSet<Order> {
                OnLoadingData = GetData,
                RowEditOptions = new RowEditOptions {
                    PrimaryKeyPropertyName = nameof(Customer.Id),
                    EditRowId = -1
                },
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public GridViewDataSetLoadedData<Order> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Order> GetQueryable(int size)
        {
            var numbers = new List<Order>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Order { Id = i + 1, DeliveryType = DeliveryTypes[(i + 1) % 2], IsPaid = (i + 1) % 2 == 0, CreatedDate = DateTime.Now.AddDays(-i) });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample8
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}
using System;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample8
{
    public class Order
    {
        public int Id { get; set; }
        public string DeliveryType { get; set; }
        public bool IsPaid { get; set; }
        public DateTime CreatedDate { get; set; }
    }
}

Sample 9: Row Decorators

The RowDecorators property can specify decorators that are applied to individual grid rows. The decorator can add properties or event handlers to the <tr> element rendered by the grid.

For the rows in the edit mode, the EditRowDecorators are used instead of the default decorator collection.

Similarly, for the rows in the insert mode, the InsertRowDecorators are used.

<bp:GridView DataSource="{value: Customers}"
             InlineEditing="true">
    <RowDecorators>
        <%-- Set different css class for even and odd rows --%>
        <dot:Decorator class="{value: Id % 2 == 0 ? 'even-row' : 'odd-row'}" />
        <%-- Set background color warning for customer without any orders --%>
        <dot:Decorator style="{value: Orders == 0 ? 'background-color: palevioletred !important;' : ''}" />
    </RowDecorators>
    <EditRowDecorators>
        <%-- Set css class for edit row scenario --%>
        <dot:Decorator class="edit-row" />
    </EditRowDecorators>
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}" 
                               HeaderText="Customer ID" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}"
                               HeaderText="Name" />
        <bp:GridViewTextColumn ValueBinding="{value: Orders}" 
                               HeaderText="# of orders" />
        <bp:GridViewTemplateColumn>
            <ContentTemplate>
                <bp:Button Text="Edit"
                           Click="{command: _root.Customers.RowEditOptions.EditRowId = Id}" />
            </ContentTemplate>
            <EditTemplate></EditTemplate>
        </bp:GridViewTemplateColumn>
    </Columns>
</bp:GridView>

<style type="text/css">
    .even-row {
        background-color: aquamarine !important;
    }

    .odd-row {
        background-color: azure !important;
    }

    .edit-row {
        background-color: yellow !important;
    }
</style>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;


namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample9
{
    public class ViewModel : DotvvmViewModelBase
    {
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> {
                OnLoadingData = GetData,
                RowEditOptions = new RowEditOptions {
                    PrimaryKeyPropertyName = nameof(Customer.Id),
                    EditRowId = -1
                },
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", BirthDate = DateTime.Now.AddYears(-i), Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample9
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 10: User Settings

The AllowReorderColumns property can be used to let the user reorder the columns.

The UserSettings property allows to persist the customizations that the user has made to the grid control. This property expects an object of type GridViewUserSettings which stores the order, widths and visibility of the individual columns.

This object can be JSON-serialized easily and stored in the database, file system or any other data store. When the user customizes anything in the grid, the changes are stored in this object.

Identification of Grid Columns

Since the developer may change the order of the grid columns, add new columns or remove the existing ones, the GridViewUserSettings object doesn't work with column indexes, but uses column names. You can mark each column in the markup with an unique name that will be used in the user settings object. If you rename the property in the viewmodel, or move the column to another place in the grid, the user settings object won't break and will be able to identify the column.

You can provide the name using the ColumnName property. If the name is not specified, the GridView will try to determine the column name from the ValueBinding property. In case of the GridViewTemplateColumn which does not have the property, the column index will be used instead.

If you use the UserSettings property, make sure that at least all template columns have the ColumnName property set. Otherwise the user settings may break in the future when the columns are changed by the application developer.

<bp:GridView DataSource="{value: Customers}"
             UserSettings="{value: UserSettings}"
             AllowReorderColumns="true">
    <Columns>
        <bp:GridViewTextColumn ColumnName="CustomerName"
                               ValueBinding="{value: Name}"
                               HeaderText="Name" />
        <bp:GridViewTextColumn ColumnName="CustomerOrders"
                               ValueBinding="{value: Orders}"
                               HeaderText="Orders" />
        <bp:GridViewTextColumn ColumnName="CustomerId"
                               ValueBinding="{value: Id}"
                               HeaderText="Customer ID" />
        <bp:GridViewTextColumn ColumnName="CustomerBirthdate"
                               ValueBinding="{value: BirthDate}"
                               FormatString="dd.MM.yyyy"
                               HeaderText="Birthdate" />
    </Columns>
</bp:GridView>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.BusinessPack.Controls;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;


namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample10
{
    public class ViewModel : DotvvmViewModelBase
    {
        public GridViewUserSettings UserSettings { get; set; }
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> {
                OnLoadingData = GetData,
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            UserSettings = new GridViewUserSettings {
                EnableUserSettings = true,
                ColumnsSettings = new List<GridViewColumnSetting> {
                    new GridViewColumnSetting {
                        ColumnName = "CustomerId",
                        DisplayOrder = 0,
                        ColumnWidth = 50
                    },
                    new GridViewColumnSetting {
                        ColumnName = "CustomerName",
                        DisplayOrder = 1,
                        ColumnWidth = 400
                    },
                    new GridViewColumnSetting {
                        ColumnName = "CustomerBirthdate",
                        DisplayOrder = 2
                    },
                    new GridViewColumnSetting {
                        ColumnName = "CustomerOrders",
                        DisplayOrder = 3
                    }
                }
            };

            return base.Init();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", BirthDate = DateTime.Now.AddYears(-i), Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample10
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Sample 11: Server Rendering

The control supports also the server-side rendering. In this mode, many functions cannot work since the control is rendered directly in the HTML output.

The server rendering can be turned on using the RenderSettings.Mode property.

This helps especially the search engines to index the contents of the page. Additionally, the server rendering might make the grid load faster in the browser if there are hundreds of rows or more.

You can read more in the Server-Side HTML Generation and SEO chapter.

<bp:GridView RenderSettings.Mode="Server"
             DataSource="{value: Customers}">
    <Columns>
        <bp:GridViewTextColumn ValueBinding="{value: Id}" 
                               HeaderText="Customer ID" />
        <bp:GridViewTextColumn ValueBinding="{value: Name}" 
                               HeaderText="Name" />
        <bp:GridViewTextColumn ValueBinding="{value: BirthDate}"
                               FormatString="dd.MM.yyyy"
                               HeaderText="Birthdate"/>
        <bp:GridViewTemplateColumn HeaderText="# of orders">
            <ContentTemplate>
                <b>{{value: Orders}}</b>
            </ContentTemplate>
        </bp:GridViewTemplateColumn>
    </Columns>
</bp:GridView>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;


namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample11
{
    public class ViewModel : DotvvmViewModelBase
    {
        public BusinessPackDataSet<Customer> Customers { get; set; }

        public override Task Init()
        {
            Customers = new BusinessPackDataSet<Customer> {
                OnLoadingData = GetData,
                SortingOptions =
                {
                    SortExpression = nameof(Customer.Id)
                }
            };

            return base.Init();
        }

        public GridViewDataSetLoadedData<Customer> GetData(IGridViewDataSetLoadOptions gridViewDataSetOptions)
        {
            var queryable = GetQueryable(15);
            return queryable.GetDataFromQueryable(gridViewDataSetOptions);
        }

        private IQueryable<Customer> GetQueryable(int size)
        {
            var numbers = new List<Customer>();
            for (var i = 0; i < size; i++)
            {
                numbers.Add(new Customer { Id = i + 1, Name = $"Customer {i + 1}", BirthDate = DateTime.Now.AddYears(-i), Orders = i });
            }
            return numbers.AsQueryable();
        }
    }
}
using System;
using System.Linq;

namespace DotvvmWeb.Views.Docs.Controls.businesspack.GridView.sample11
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName => !string.IsNullOrWhiteSpace(Name) ? Name.Split(' ').LastOrDefault() : "";
        public DateTime BirthDate { get; set; }
        public int Orders { get; set; }
    }
}

Properties

Name Type Description Notes Default Value
property icon AllowReorderColumns Boolean Gets or sets whether it is allowed to change order of GridView columns.
attribute
inner element
static value
bindable
default
False
property icon Attributes Dictionary<String,Object>
attribute
inner element
static value
bindable
default
null
property icon ClientIDMode ClientIDMode Gets or sets the client ID generation algorithm.
attribute
inner element
static value
bindable
default
Static
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
HeaderRow
property icon FreezeHeaderRow Boolean Gets or sets whether the header row is freezed and is always visible.
attribute
inner element
static value
bindable
default
False
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 InlineInserting Boolean Gets or sets whether the insert row should be rendered in the Grid. If so, you have to use a BusinessPackDataSet as the DataSource.
attribute
inner element
static value
bindable
default
False
property icon InlineInsertRowPlacement InsertRowPlacement Gets or sets whether the insert row should be rendered in the Grid. If so, you have to use a BusinessPackDataSet as the DataSource.
attribute
inner element
static value
bindable
default
Top
property icon InnerText String Gets or sets the inner text of the HTML element.
attribute
inner element
static value
bindable
default
null
property icon InsertRowDecorators List<Decorator> Gets or sets a list of decorators that will be applied on insert row.
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 edit mode.
attribute
inner element
static value
bindable
default
null
property icon ShowFooter Boolean Gets or sets whether the footer should be displayed or not
attribute
inner element
static value
bindable
default
False
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 UserSettings GridViewUserSettings Gets or sets the user's GridView settings. It can be used to persist column visibility, order, width, etc.
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