Feel free to share demo-related thoughts here.
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Thank you for the feedback!
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Backend API
@(Html.DevExtreme().DataGrid<DevExtreme.NETCore.Demos.Models.Northwind.Order>()
.ID("grid")
.DataSource(d => d.WebApi()
.Controller("DataGridWebApi")
.LoadAction("Orders")
.InsertAction("InsertOrder")
.UpdateAction("UpdateOrder")
.DeleteAction("DeleteOrder")
.Key("OrderID")
.OnBeforeSend("beforeSend")
)
.ShowBorders(true)
.RepaintChangesOnly(true)
.Scrolling(s => s.Mode(GridScrollingMode.Virtual))
.Editing(e => e
.Mode(GridEditMode.Cell)
.RefreshMode(GridEditRefreshMode.Reshape)
.AllowAdding(true)
.AllowDeleting(true)
.AllowUpdating(true)
)
.Columns(columns => {
columns.AddFor(m => m.CustomerID)
.Lookup(lookup => lookup
.DataSource(d => d.WebApi()
.Controller("DataGridWebApi")
.LoadAction("CustomersLookup")
.LoadMode(DataSourceLoadMode.Raw)
.Key("Value")
.OnBeforeSend("beforeSend")
)
.DataSourceOptions(o => o.Paginate(true))
.ValueExpr("Value")
.DisplayExpr("Text")
);
columns.AddFor(m => m.OrderDate);
columns.AddFor(m => m.Freight);
columns.AddFor(m => m.ShipCountry);
columns.AddFor(m => m.ShipVia)
.Lookup(lookup => lookup
.DataSource(d => d.WebApi()
.Controller("DataGridWebApi")
.LoadAction("ShippersLookup")
.LoadMode(DataSourceLoadMode.Raw)
.Key("Value")
.OnBeforeSend("beforeSend")
)
.ValueExpr("Value")
.DisplayExpr("Text")
);
})
.Summary(s => s
.TotalItems(totalItems => {
totalItems.AddFor(t => t.CustomerID).SummaryType(SummaryType.Count);
totalItems.AddFor(t => t.Freight).ValueFormat("#0.00").SummaryType(SummaryType.Sum);
})
)
)
<div class="options">
<div class="caption">Options</div>
<div class="option">
<span>Refresh Mode:</span>
@(Html.DevExtreme().SelectBox()
.ID("refresh-mode")
.DataSource(new[] { "full", "reshape", "repaint" })
.InputAttr("aria-label", "Refresh Mode")
.Value("reshape")
.OnValueChanged(@<text> function(e) {
$("#grid").dxDataGrid("instance").option("editing.refreshMode", e.value);
} </text>)
)
</div>
<div id="requests">
<div>
<div class="caption">Network Requests</div>
@(Html.DevExtreme().Button()
.ID("clear")
.Text("Clear")
.OnClick(@<text> function() {
$("#requests ul").empty();
} </text>)
)
</div>
<ul></ul>
</div>
</div>
<script>
function beforeSend(operation, ajaxSettings) {
var data = ajaxSettings.data || {},
args = Object.keys(data).map(function (key) {
return key + "=" + data[key];
}).join(" ");
var logList = $("#requests ul"),
time = DevExpress.localization.formatDate(new Date(), "HH:mm:ss"),
newItem = $("<li>").text([time, ajaxSettings.method, ajaxSettings.url, args].join(" "));
logList.prepend(newItem);
}
</script>
using DevExtreme.NETCore.Demos.Models;
using DevExtreme.NETCore.Demos.Models.DataGrid;
using DevExtreme.NETCore.Demos.Models.SampleData;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
namespace DevExtreme.NETCore.Demos.Controllers {
public class DataGridController : Controller {
public ActionResult CRUDOperations() {
return View();
}
}
}
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using DevExtreme.NETCore.Demos.Models.DataGrid;
using DevExtreme.NETCore.Demos.Models.Northwind;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DevExtreme.NETCore.Demos.Controllers.ApiControllers {
[Route("api/[controller]/[action]")]
public class DataGridWebApiController : Controller {
InMemoryNorthwindContext _nwind;
public DataGridWebApiController(NorthwindContext nwind, IHttpContextAccessor httpContextAccessor, IMemoryCache memoryCache) {
_nwind = new InMemoryNorthwindContext(nwind, httpContextAccessor, memoryCache);
}
[HttpGet]
public object Orders(DataSourceLoadOptions loadOptions) {
return DataSourceLoader.Load(_nwind.Orders, loadOptions);
}
[HttpPost]
public IActionResult InsertOrder(string values) {
var newOrder = new Order();
JsonConvert.PopulateObject(values, newOrder);
if(!TryValidateModel(newOrder))
return BadRequest(ModelState.GetFullErrorMessage());
_nwind.Orders.Add(newOrder);
_nwind.SaveChanges();
return Ok(newOrder);
}
[HttpPut]
public IActionResult UpdateOrder(int key, string values) {
var order = _nwind.Orders.First(o => o.OrderID == key);
JsonConvert.PopulateObject(values, order);
if(!TryValidateModel(order))
return BadRequest(ModelState.GetFullErrorMessage());
_nwind.SaveChanges();
return Ok(order);
}
[HttpDelete]
public void DeleteOrder(int key) {
var order = _nwind.Orders.First(o => o.OrderID == key);
_nwind.Orders.Remove(order);
_nwind.SaveChanges();
}
// additional actions
[HttpGet]
public object OrderDetails(int orderID, DataSourceLoadOptions loadOptions) {
return DataSourceLoader.Load(
from i in _nwind.Order_Details
where i.OrderID == orderID
select new {
Product = i.Product.ProductName,
Price = i.UnitPrice,
i.Quantity,
Sum = i.UnitPrice * i.Quantity
},
loadOptions
);
}
[HttpGet]
public object ShippersLookup(DataSourceLoadOptions loadOptions) {
var lookup = from i in _nwind.Shippers
orderby i.CompanyName
select new {
Value = i.ShipperID,
Text = i.CompanyName
};
return DataSourceLoader.Load(lookup, loadOptions);
}
[HttpGet]
public object CustomersLookup(DataSourceLoadOptions loadOptions) {
var lookup = from i in _nwind.Customers
let text = i.CompanyName + " (" + i.Country + ")"
orderby i.CompanyName
select new {
Value = i.CustomerID,
Text = text
};
return DataSourceLoader.Load(lookup, loadOptions);
}
[HttpPost]
public object Batch([FromBody] List<DataChange> changes) {
foreach(var change in changes) {
Order order;
if(change.Type == "update" || change.Type == "remove") {
var key = Convert.ToInt32(change.Key);
order = _nwind.Orders.First(o => o.OrderID == key);
} else {
order = new Order();
}
if(change.Type == "insert" || change.Type == "update") {
JsonConvert.PopulateObject(change.Data.ToString(), order);
if(!TryValidateModel(order))
return BadRequest(ModelState.GetFullErrorMessage());
if(change.Type == "insert") {
_nwind.Orders.Add(order);
}
change.Data = order;
} else if(change.Type == "remove") {
_nwind.Orders.Remove(order);
}
}
_nwind.SaveChanges();
return Ok(changes);
}
}
}
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
namespace DevExtreme.NETCore.Demos.Models.Northwind {
public class InMemoryNorthwindContext : InMemoryDataContext<Order> {
NorthwindContext _nwind;
public InMemoryNorthwindContext(NorthwindContext nwind, IHttpContextAccessor contextAccessor, IMemoryCache memoryCache)
: base(contextAccessor, memoryCache) {
_nwind = nwind;
}
public ICollection<Order> Orders => ItemsInternal;
public DbSet<Customer> Customers => _nwind.Customers;
public DbSet<Order_Detail> Order_Details => _nwind.Order_Details;
public DbSet<Shipper> Shippers => _nwind.Shippers;
protected override IEnumerable<Order> Source => _nwind.Orders;
protected override int GetKey(Order item) => item.OrderID;
protected override void SetKey(Order item, int key) => item.OrderID = key;
}
}
#grid {
height: 440px;
}
.options {
padding: 20px;
margin-top: 20px;
background-color: rgba(191, 191, 191, 0.15);
}
.caption {
margin-bottom: 10px;
font-weight: 500;
font-size: 18px;
}
.option {
margin-bottom: 10px;
}
.option > span {
position: relative;
top: 2px;
margin-right: 10px;
}
.option > .dx-widget {
display: inline-block;
vertical-align: middle;
}
#requests .caption {
float: left;
padding-top: 7px;
}
#requests > div {
padding-bottom: 5px;
}
#requests > div:after {
content: "";
display: table;
clear: both;
}
#requests #clear {
float: right;
}
#requests ul {
list-style: none;
max-height: 100px;
overflow: auto;
margin: 0;
}
#requests ul li {
padding: 7px 0;
border-bottom: 1px solid #dddddd;
}
#requests ul li:last-child {
border-bottom: none;
}