This example demonstrates how to create combo box editors and configure the grid's cell edit functionality in batch mode.
Overview
Follow the steps below to implement cascading combo boxes in batch edit mode:
- Create a combo box column - call the MVCxGridViewColumn.EditorProperties method and add a MVCxColumnComboBoxProperties object.Razor
settings.Columns.Add(c => c.CountryId, country => { country.Caption = "Country"; country.EditorProperties().ComboBox(cs => cs.Assign(ComboBoxPropertiesProvider.Current.CountryComboBoxProperties)); }); settings.Columns.Add(c => c.CityId, city => { city.Caption = "City"; city.EditorProperties().ComboBox(cs => cs.Assign(ComboBoxPropertiesProvider.Current.CityComboBoxProperties)); });
- Handle the grid's client-side BatchEditStartEditing event. In the handler, get the cell value and call the secondary combo box editor's
PerformCallback
method to update the editor's data.JavaScriptfunction OnBatchEditStartEditing(s, e) { curentEditingIndex = e.visibleIndex; var currentCountry = grid.batchEditApi.GetCellValue(curentEditingIndex, "CountryId"); if (currentCountry != lastCountry && e.focusedColumn.fieldName == "CityId" && currentCountry != null) { lastCountry = currentCountry; grid.GetEditor("CityId").PerformCallback(); } }
- Handle the primary editor's client-side SelectedIndexChanged event. In the handler, get the editor's value and send a callback to the server.JavaScript
function CountriesCombo_SelectedIndexChanged(s, e) { lastCountry = s.GetValue(); isCustomCascadingCallback = true; grid.GetEditor("CityId").PerformCallback(); }
- Use the GetComboBoxCallbackResult method to get the result of callback processing.C#
public ActionResult ComboBoxCountryPartial(){ return GridViewExtension.GetComboBoxCallbackResult(ComboBoxPropertiesProvider.Current.CountryComboBoxProperties); } public ActionResult ComboBoxCityPartial(){ return GridViewExtension.GetComboBoxCallbackResult(ComboBoxPropertiesProvider.Current.CityComboBoxProperties); }
- Handle the secondary editor's EndCallback event to select an item after the callback.JavaScript
function CitiesCombo_EndCallback(s, e) { if (isCustomCascadingCallback) { if (s.GetItemCount() > 0) grid.batchEditApi.SetCellValue(curentEditingIndex, "CityId", s.GetItem(0).value); isCustomCascadingCallback = false; } }
Files to Review
- HomeController.cs (VB: HomeController.vb)
- ComboBoxPropertiesProvider.cs (VB: ComboBoxPropertiesProvider.vb)
- Customer.cs (VB: Customer.vb)
- CascadingComboBoxesBatchEdit.js (VB: CascadingComboBoxesBatchEdit.js)
- GridViewPartial.cshtml
- Index.cshtml
Documentation
More Examples
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using System.Web.Mvc;
using E4425.Models;
using DevExpress.Web.Mvc;
using System.Linq;
namespace E4425.Controllers
{
public class HomeController : Controller
{
WorldCitiesEntities entity = new WorldCitiesEntities();
public ActionResult Index()
{
return View(entity.Customers.ToList());
}
public ActionResult GridViewPartial()
{
return PartialView(entity.Customers.ToList());
}
public ActionResult GridViewEditPartial(MVCxGridViewBatchUpdateValues<Customer, int> modifiedValues)
{
foreach (var customerInfo in modifiedValues.Insert)
{
if (modifiedValues.IsValid(customerInfo))
entity.Customers.Add(customerInfo);
}
foreach (var customerInfo in modifiedValues.Update)
{
if (modifiedValues.IsValid(customerInfo))
{
entity.Customers.Attach(customerInfo);
var entry = entity.Entry(customerInfo);
entry.Property(e => e.CityId).IsModified = true;
entry.Property(e => e.CountryId).IsModified = true;
entry.Property(e => e.CustomerName).IsModified = true;
}
}
foreach (var customerID in modifiedValues.DeleteKeys)
{
entity.Customers.Remove(entity.Customers.Find(customerID));
}
// uncomment the next line to enable database updates
// entity.SaveChanges();
return PartialView("GridViewPartial", entity.Customers.ToList());
}
public ActionResult ComboBoxCountryPartial()
{
return GridViewExtension.GetComboBoxCallbackResult(ComboBoxPropertiesProvider.Current.CountryComboBoxProperties);
}
public ActionResult ComboBoxCityPartial()
{
return GridViewExtension.GetComboBoxCallbackResult(ComboBoxPropertiesProvider.Current.CityComboBoxProperties);
}
}
}
C#using DevExpress.Web;
using DevExpress.Web.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
namespace E4425.Models
{
public class ComboBoxPropertiesProvider : IDisposable
{
static ComboBoxPropertiesProvider current;
public static ComboBoxPropertiesProvider Current
{
get
{
if (current == null)
current = new ComboBoxPropertiesProvider();
return current;
}
}
public int EditableCountryID
{
get
{
string rawCountryId = HttpContext.Current.Request["CountryId"];
return string.IsNullOrEmpty(rawCountryId) ? -1 : int.Parse(rawCountryId);
}
}
MVCxColumnComboBoxProperties cityComboBoxProperties;
public MVCxColumnComboBoxProperties CityComboBoxProperties
{
get
{
if (cityComboBoxProperties == null)
cityComboBoxProperties = CreateCityComboBoxProperties();
return cityComboBoxProperties;
}
}
MVCxColumnComboBoxProperties countryComboBoxProperties;
public MVCxColumnComboBoxProperties CountryComboBoxProperties
{
get
{
if (countryComboBoxProperties == null)
countryComboBoxProperties = CreateCountryComboBox();
return countryComboBoxProperties;
}
}
WorldCitiesEntities worldCities;
protected WorldCitiesEntities WorldCities
{
get
{
if (worldCities == null)
worldCities = new WorldCitiesEntities();
return worldCities;
}
}
protected MVCxColumnComboBoxProperties CreateCountryComboBox()
{
MVCxColumnComboBoxProperties cs = new MVCxColumnComboBoxProperties();
cs.CallbackRouteValues = new { Controller = "Home", Action = "ComboBoxCountryPartial" };
cs.Width = Unit.Percentage(100);
cs.TextField = "CountryName";
cs.ValueField = "CountryId";
cs.ValueType = typeof(int);
cs.IncrementalFilteringDelay = 1000;
cs.IncrementalFilteringMode = IncrementalFilteringMode.Contains;
cs.FilterMinLength = 2;
cs.CallbackPageSize = 20;
cs.ClientSideEvents.SelectedIndexChanged = "CountriesCombo_SelectedIndexChanged";
cs.BindList(WorldCities.Countries.ToList());
return cs;
}
protected MVCxColumnComboBoxProperties CreateCityComboBoxProperties()
{
MVCxColumnComboBoxProperties cs = new MVCxColumnComboBoxProperties();
cs.CallbackRouteValues = new { Controller = "Home", Action = "ComboBoxCityPartial" };
cs.Width = Unit.Percentage(100);
cs.CallbackPageSize = 20;
cs.TextField = "CityName";
cs.ValueField = "CityId";
cs.ValueType = typeof(int);
cs.IncrementalFilteringDelay = 1000;
cs.IncrementalFilteringMode = IncrementalFilteringMode.Contains;
cs.FilterMinLength = 2;
cs.ValidationSettings.Display = Display.None;
cs.BindList(OnItemsRequestedByFilterCondition, OnItemRequestedByValue);
cs.ClientSideEvents.BeginCallback = "CitiesCombo_BeginCallback";
cs.ClientSideEvents.EndCallback = "CitiesCombo_EndCallback";
return cs;
}
protected object OnItemRequestedByValue(ListEditItemRequestedByValueEventArgs e)
{
int id;
if (e.Value == null || !int.TryParse(e.Value.ToString(), out id))
return null;
var query = WorldCities.Cities.Where(city => city.CityId == id);
return query.ToList();
}
protected object OnItemsRequestedByFilterCondition(ListEditItemsRequestedByFilterConditionEventArgs e)
{
IQueryable<City> query;
var skip = e.BeginIndex;
var take = e.EndIndex - e.BeginIndex + 1;
if (EditableCountryID > -1)
query = WorldCities.Cities.Where(city => city.CityName.Contains(e.Filter) && city.Country.CountryId == EditableCountryID).OrderBy(city => city.CityId);
else
query = WorldCities.Cities.Where(city => city.CityName.Contains(e.Filter)).OrderBy(city => city.CityId);
query = query.Skip(skip).Take(take);
return query.ToList();
}
#region IDisposable Members
public void Dispose()
{
if (this.worldCities != null)
worldCities.Dispose();
}
#endregion
}
}
C#//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace E4425.Models
{
using System;
using System.Collections.Generic;
public partial class Customer
{
public int CustomerId { get; set; }
public string CustomerName { get; set; }
public Nullable<int> CountryId { get; set; }
public Nullable<int> CityId { get; set; }
public virtual City City { get; set; }
public virtual Country Country { get; set; }
}
}
JavaScriptvar curentEditingIndex;
var lastCountry = null;
var isCustomCascadingCallback = false;
function OnBatchEditStartEditing(s, e) {
curentEditingIndex = e.visibleIndex;
var currentCountry = grid.batchEditApi.GetCellValue(curentEditingIndex, "CountryId");
if (currentCountry != lastCountry && e.focusedColumn.fieldName == "CityId" && currentCountry != null) {
lastCountry = currentCountry;
grid.GetEditor("CityId").PerformCallback();
}
}
function CountriesCombo_SelectedIndexChanged(s, e) {
lastCountry = s.GetValue();
isCustomCascadingCallback = true;
grid.GetEditor("CityId").PerformCallback();
}
function CitiesCombo_BeginCallback(s, e) {
e.customArgs['CountryId'] = lastCountry;
}
function CitiesCombo_EndCallback(s, e) {
if (isCustomCascadingCallback) {
if (s.GetItemCount() > 0)
grid.batchEditApi.SetCellValue(curentEditingIndex, "CityId", s.GetItem(0).value);
isCustomCascadingCallback = false;
}
}
Razor@using E4425.Models;
@(Html.DevExpress().GridView<Customer>(settings => {
settings.Name = "grid";
settings.KeyFields(c => c.CustomerId);
settings.Width = System.Web.UI.WebControls.Unit.Pixel(500);
settings.CallbackRouteValues = new { Controller = "Home", Action = "GridViewPartial" };
settings.SettingsEditing.Mode = GridViewEditingMode.Batch;
settings.SettingsEditing.BatchEditSettings.EditMode = GridViewBatchEditMode.Cell;
settings.SettingsEditing.BatchUpdateRouteValues = new { Controller = "Home", Action = "GridViewEditPartial" };
settings.CommandColumn.Visible = true;
settings.CommandColumn.ShowNewButtonInHeader = true;
settings.CommandColumn.ShowDeleteButton = true;
settings.Columns.Add(c => c.CustomerId).Visible = false;
settings.Columns.Add(c => c.CustomerName);
settings.SettingsEditing.ShowModelErrorsForEditors = true;
settings.Columns.Add(c => c.CountryId, country => {
country.Caption = "Country";
country.EditorProperties().ComboBox(cs => cs.Assign(ComboBoxPropertiesProvider.Current.CountryComboBoxProperties));
});
settings.Columns.Add(c => c.CityId, city => {
city.Caption = "City";
city.EditorProperties().ComboBox(cs => cs.Assign(ComboBoxPropertiesProvider.Current.CityComboBoxProperties));
});
settings.CellEditorInitialize = (s, e) => {
ASPxEdit editor = (ASPxEdit)e.Editor;
editor.ValidationSettings.Display = Display.None;
};
settings.ClientSideEvents.BatchEditStartEditing = "OnBatchEditStartEditing";
}).Bind(Model).GetHtml())
Razor@{
ViewBag.Title = "GridView - How to implement cascading comboboxes in Batch Edit mode";
}
<script src="@Url.Content("~/Scripts/CascadingComboBoxesBatchEdit.js")"></script>
@using (Html.BeginForm())
{
@Html.Partial("GridViewPartial")
}