This example demonstrates how to implement cascading combo box editors in batch mode and use WebMethods to populate the editors with data. This example combines the following approaches:
- Grid View for ASP.NET Web Forms - Cascading Combo Boxes in Batch Edit Mode
- Combo Box for ASP.NET Web Forms - How to use the WebMethod attribute to populate a cascading editor with data
Overview
The main idea is to use WebMethods to update the secondary editor's data based on the primary editor's value.
JavaScriptvar lastCountryID;
var lastCityID;
function CountriesCombo_SelectedIndexChanged(s, e) {
var currentCountryID = s.GetSelectedItem().value;
lastCountryID = currentCountryID;
lastCityID = -1;
PageMethods.GetCities(lastCountryID, CitiesCombo_OnSuccessGetCities);
}
To enable this functionality, add the ScriptManager control to the page and set its EnablePageMethods property to true
.
ASPx<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
</asp:ScriptManager>
Files to Review
- Default.aspx (VB: Default.aspx)
- Default.aspx.cs (VB: Default.aspx.vb)
- JavaScript.js (VB: JavaScript.js)
Documentation
Example Code
ASPx<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Assembly="DevExpress.Web.v19.2, Version=19.2.15.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web" TagPrefix="dx" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="JavaScript.js"></script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"></asp:ScriptManager>
<dx:ASPxGridView runat="server" OnDataBinding="grid_DataBinding" OnBatchUpdate="grid_BatchUpdate" KeyFieldName="CustomerID" ClientInstanceName="grid" ID="grid">
<Columns>
<dx:GridViewCommandColumn ShowEditButton="true" ShowNewButtonInHeader="true" ShowDeleteButton="true"></dx:GridViewCommandColumn>
<dx:GridViewDataColumn FieldName="CustomerID">
<EditFormSettings Visible="False" />
</dx:GridViewDataColumn>
<dx:GridViewDataTextColumn FieldName="CustomerName">
<PropertiesTextEdit>
<ValidationSettings RequiredField-IsRequired="true" Display="None"></ValidationSettings>
</PropertiesTextEdit>
</dx:GridViewDataTextColumn>
<dx:GridViewDataComboBoxColumn Caption="Country" FieldName="CountryID" >
<PropertiesComboBox ValueField="CountryID" ClientInstanceName="CountryID" TextField="CountryName" ValueType="System.Int32">
<ValidationSettings RequiredField-IsRequired="true" Display="None"></ValidationSettings>
<ClientSideEvents SelectedIndexChanged="CountriesCombo_SelectedIndexChanged" />
</PropertiesComboBox>
</dx:GridViewDataComboBoxColumn>
<dx:GridViewDataComboBoxColumn FieldName="CityID" Width="100px" Caption="City">
<PropertiesComboBox ValueType="System.Int32" TextField="CityName" ValueField="CityID"
ClientInstanceName="CityID">
<ValidationSettings RequiredField-IsRequired="true" Display="None"></ValidationSettings>
</PropertiesComboBox>
</dx:GridViewDataComboBoxColumn>
</Columns>
<ClientSideEvents Init="OnInit" EndCallback="OnEndCallback" BatchEditStartEditing="OnBatchEditStartEditing" BatchEditEndEditing="OnBatchEditEndEditing" />
<SettingsEditing Mode="Batch">
<BatchEditSettings ShowConfirmOnLosingChanges="true" EditMode="Row" />
</SettingsEditing>
</dx:ASPxGridView>
</div>
</form>
</body>
</html>
C#using DevExpress.Web;
using System;
using System.Collections;
using System.Web.Services;
public partial class _Default : System.Web.UI.Page {
protected void Page_Init(object sender, EventArgs e) {
((GridViewDataComboBoxColumn)grid.Columns["CountryID"]).PropertiesComboBox.DataSource = DataProvider.GetCountries();
((GridViewDataComboBoxColumn)grid.Columns["CityID"]).PropertiesComboBox.DataSource = DataProvider.GetCities();
if(!IsPostBack)
grid.DataBind();
}
protected void grid_DataBinding(object sender, EventArgs e) {
grid.DataSource = DataProvider.GetCustomers();
}
protected void grid_BatchUpdate(object sender, DevExpress.Web.Data.ASPxDataBatchUpdateEventArgs e) {
foreach(var args in e.InsertValues)
DataProvider.InsertCustomer((string)args.NewValues["CustomerName"], (int)args.NewValues["CountryID"], (int)args.NewValues["CityID"]);
foreach(var args in e.UpdateValues)
DataProvider.UpdateCustomer((int)args.Keys["CustomerID"], (string)args.NewValues["CustomerName"], (int)args.NewValues["CountryID"], (int)args.NewValues["CityID"]);
foreach(var args in e.DeleteValues)
DataProvider.DeleteCustomer((int)args.Keys["CustomerID"]);
e.Handled = true;
}
[WebMethod]
public static IEnumerable GetCities(int countryID) {
return DataProvider.GetCities(countryID);
}
}
JavaScriptvar currentEditableVisibleIndex;
var lastCountryID;
var lastCityID;
function CountriesCombo_SelectedIndexChanged(s, e) {
var currentCountryID = s.GetSelectedItem().value;
lastCountryID = currentCountryID;
lastCityID = -1;
PageMethods.GetCities(lastCountryID, CitiesCombo_OnSuccessGetCities);
}
function IntializeGlobalVariables(grid) {
lastCountryID = -1;
currentEditableVisibleIndex = -1;
lastCityID = -1;
}
function OnInit(s, e) {
IntializeGlobalVariables(s);
}
function OnEndCallback(s, e) {
IntializeGlobalVariables(s);
}
function CitiesCombo_OnSuccessGetCities(response) {
CityID.ClearItems();
for (var i in response) {
CityID.AddItem(response[i].CityName, response[i].CityID);
}
if (lastCityID == -1)
CityID.SetSelectedIndex(0);
else if (lastCityID > -1) {
CityID.SetSelectedItem(CityID.FindItemByValue(lastCityID));
lastCityID = -1;
}
}
function OnBatchEditStartEditing(s, e) {
currentEditableVisibleIndex = e.visibleIndex;
var currentCountryID = grid.batchEditApi.GetCellValue(currentEditableVisibleIndex, "CountryID");
var currentCityID = grid.batchEditApi.GetCellValue(currentEditableVisibleIndex, "CityID")
lastCityID = currentCityID;
if (lastCountryID == currentCountryID)
CityID.SetSelectedItem(CityID.FindItemByValue(lastCityID));
else {
if (currentCountryID == null) {
CityID.SetSelectedIndex(-1);
return;
}
lastCountryID = currentCountryID;
PageMethods.GetCities(lastCountryID, CitiesCombo_OnSuccessGetCities);
}
}
function OnBatchEditEndEditing(s, e) {
currentEditableVisibleIndex = -1;
}