Backend API
@(Html.DevExtreme().DataGrid() .ID("gridContainer") .DataSource(d => d.Array().Data(new JS("products")).Key("ProductID")) .DataSourceOptions(o => o.ReshapeOnPush(true)) .RepaintChangesOnly(true) .ColumnAutoWidth(true) .ShowBorders(true) .Paging(p => p.PageSize(10)) .Columns(c => { c.Add() .DataField("ProductName") .DataType(GridColumnDataType.String); c.Add() .DataField("UnitPrice") .DataType(GridColumnDataType.Number) .Format(Format.Currency); c.Add() .DataField("OrderCount") .DataType(GridColumnDataType.Number); c.Add() .DataField("Quantity") .DataType(GridColumnDataType.Number); c.Add() .DataField("Amount") .DataType(GridColumnDataType.Number) .Format(Format.Currency); }) .Summary(s => s.TotalItems(totalItems => { totalItems.Add() .SummaryType(SummaryType.Count) .Column("ProductName"); totalItems.Add() .SummaryType(SummaryType.Sum) .DisplayFormat("{0}") .ValueFormat(Format.Currency) .Column("Amount"); totalItems.Add() .SummaryType(SummaryType.Sum) .DisplayFormat("{0}") .Column("OrderCount"); }) ) .MasterDetail(md => { md.Enabled(true); md.Template(@<text> @(Html.DevExtreme().DataGrid() .DataSource(new JS("getDetailGridDataSource(key)")) .RepaintChangesOnly(true) .ColumnAutoWidth(true) .ShowBorders(true) .Paging(p => p.PageSize(5)) .Columns(c => { c.Add() .DataField("OrderID") .DataType(GridColumnDataType.Number); c.Add() .DataField("ShipCity") .DataType(GridColumnDataType.String); c.Add() .DataField("OrderDate") .DataType(GridColumnDataType.DateTime); c.Add() .DataField("UnitPrice") .DataType(GridColumnDataType.Number) .Format(Format.Currency); c.Add() .DataField("Quantity") .DataType(GridColumnDataType.Number); c.Add() .Caption("Amount") .DataType(GridColumnDataType.Number) .Format(Format.Currency) .CalculateCellValue("getAmount") .AllowSorting(true); }) .Summary(s => s.TotalItems(totalItems => { totalItems.Add() .SummaryType(SummaryType.Count) .Column("OrderID"); totalItems.Add() .SummaryType(SummaryType.Sum) .DisplayFormat("{0}") .Column("Quantity"); totalItems.Add() .SummaryType(SummaryType.Sum) .DisplayFormat("{0}") .ValueFormat(Format.Currency) .Column("Amount"); }) ) ) </text>); }) ) <script src="~/Scripts/data/realTimeData.js"></script> <script> function getDetailGridDataSource(key) { return { store: ordersStore, filter: ["ProductID", "=", key], reshapeOnPush: true } } function getAmount(order) { return order.UnitPrice * order.Quantity; } function frequencyChanged(e) { updatesPerSecond = e.value; } var updatesPerSecond = 100; $(function () { var productsStore = $("#gridContainer").dxDataGrid("getDataSource").store(); setInterval(function () { if (orders.length > 500000) { return; } for (var i = 0; i < updatesPerSecond / 20; i++) { addOrder(productsStore); } }, 50); }); </script> <div class="options"> <div class="caption">Options</div> <div class="option"> <span>Update frequency:</span> @(Html.DevExtreme().Slider() .ID("frequency-slider") .Min(10) .Max(5000) .Step(10) .Value(new JS("updatesPerSecond")) .OnValueChanged("frequencyChanged") .Tooltip(t => t .Enabled(true) .ShowMode(SliderTooltipShowMode.Always) .Format("#0 per second") .Position(VerticalEdge.Top) ) ) </div> </div>
using DevExtreme.MVC.Demos.Models; using DevExtreme.MVC.Demos.Models.DataGrid; using DevExtreme.MVC.Demos.Models.SampleData; using System; using System.Linq; using System.Web.Mvc; namespace DevExtreme.MVC.Demos.Controllers { public class DataGridController : Controller { public ActionResult RealTimeUpdates() { return View(); } } }
var cities = ["Los Angeles", "Denver", "Bentonville", "Atlanta", "Reno", "Beaver", "Malibu", "Phoenix", "San Diego", "Little Rock", "Pasadena", "Boise", "San Jose", "Chatsworth", "San Fernando", "South Pasadena", "San Fernando Valley", "La Canada", "St. Louis"]; var orders = []; var ordersStore = new DevExpress.data.ArrayStore({ key: "OrderID", data: orders }); var products = []; for (var i = 1; i <= 100; i++) { products.push({ ProductID: i, ProductName: "Product " + i, UnitPrice: Math.floor(Math.random() * 1000) + 1, Quantity: 0, Amount: 0, OrderCount: 0 }); } function addOrder(productsStore) { var product = products[Math.round(Math.random() * 99)]; var order = { OrderID: orders.length ? orders[orders.length - 1].OrderID + 1 : 20001, ShipCity: cities[Math.round(Math.random() * (cities.length - 1))], ProductID: product.ProductID, UnitPrice: product.UnitPrice, OrderDate: new Date(), Quantity: Math.round(Math.random() * 20) + 1 }; ordersStore.push([{ type: "insert", data: order }]); productsStore.push([{ type: "update", key: order.ProductID, data: { OrderCount: product.OrderCount + 1, Quantity: product.Quantity + order.Quantity, Amount: product.Amount + order.UnitPrice * order.Quantity } }]); }
.options { padding: 20px; margin-top: 20px; background-color: rgba(191, 191, 191, 0.15); } .caption { font-weight: 500; font-size: 18px; } .option { margin-top: 10px; display: flex; align-items: center; } .option > span { position: relative; top: 2px; margin-right: 10px; } .option > .dx-widget { width: 500px; display: inline-block; vertical-align: middle; }
Grids in the detail sections are updated in real time as well. All the grids share the same ordersStore that receives pushes, but it is filtered to show only a specific product's orders for each grid.