Ajax 级联下拉列表与 GridView






4.88/5 (5投票s)
这是“Ajax 级联下拉列表与 GridView”的替代方案
引言
大家好,今天我将写一篇文章,介绍如何在 GridView 中使用 Ajax 级联下拉列表,通过 Web 服务来实现。级联下拉列表可以帮助我们避免页面回发。每次父级下拉列表控件的选择发生变化时,它都会调用指定的 Web 服务来检索下拉列表中下一组值的列表。
以前我们使用 Ajax 和 JavaScript 来实现这类任务,但现在 Ajax Control Toolkit 中提供了一个名为 Cascading Drop-down Control 的控件,可以实现相同的功能。本文将涵盖以下几点:
- 在 GridView 中绑定 Ajax 级联下拉列表。
- 如何设置级联控件的属性。
- 页面加载后,如何重新绑定它。
背景
您还可以参考这个 Cascading-Dropdownlist 来了解此控件的基本功能和属性。以下是部分功能列表:
- TargetControlID - 要填充的下拉列表的 ID。
- Category - 此下拉列表代表的类别名称。
- PromptText - 用户从下拉列表中选择值之前显示的选填文本。
- PromptValue - 显示 Prompt-text 时设置的选填值。
- EmptyText - 下拉列表没有数据可显示时显示的选填文本。
- EmptyValue - 显示 Empty-text 时设置的选填值。
- LoadingText - 加载下拉列表数据时显示的选填文本。
- ServicePath - 返回用于填充下拉列表的数据的 Web 服务的路径。如果 ServiceMethod 指向页面方法,则应将此属性留空。Web 服务应装饰有 System.Web.Script.Services.ScriptService 属性。
- ServiceMethod - 返回用于填充下拉列表的数据的 Web 服务方法。
- ContextKey - 提供给 ServiceMethod/ServicePath 描述的 Web 方法的可选重载的用户/页面特定上下文。如果使用上下文键,它应具有相同的签名,并增加一个名为 contextKey 的字符串类型参数。
- UseContextKey - 是否应使用 ContextKey 属性。如果 ever 设置了 ContextKey 属性(在客户端或服务器端),则此属性将自动启用。
- ParentControlID - 父下拉列表的可选 ID,用于控制此下拉列表的内容。
- SelectedValue - 可选的默认选定值。这需要与下拉列表中的值字符串表示形式完全匹配。
使用代码
我将在我的网页上创建一个 GridView 控件。我在 GridView 中放置了两个下拉列表和两个级联控件。
客户端代码:
<asp:GridView GridLines="Vertical" ID="grdDemo" runat="server" AutoGenerateColumns="False"
BackColor="White" BorderColor="#DEDFDE" BorderStyle="None" BorderWidth="1px"
CellPadding="4" ForeColor="Black" OnRowDataBound="grdDemo_RowDataBound" OnRowDeleting="grdDemo_RowDeleting">
<EmptyDataTemplate>
<div>
No record found</div>
</EmptyDataTemplate>
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:TemplateField HeaderText="Brand Name">
<ItemTemplate>
<asp:DropDownList ID="ddlBrand" runat="server" Font-Size="9" Width="130">
</asp:DropDownList>
<ajaxToolKit:CascadingDropDown UseContextKey="true" ContextKey='<%# Bind("BrandId") %>'
ID="ccdRegion" runat="server" Category="BrandName" TargetControlID="ddlBrand"
ServiceMethod="GetAllCarBrand" ServicePath="~/WebService/CarService.asmx">
</ajaxToolKit:CascadingDropDown>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Model Name">
<ItemTemplate>
<asp:DropDownList ID="ddlModelName" runat="server" Font-Size="9" Width="130">
</asp:DropDownList>
<ajaxToolKit:CascadingDropDown UseContextKey="true" ContextKey='<%# Bind("ModelId") %>'
ID="ccdDistrict" runat="server" Category="Model" ParentControlID="ddlBrand" TargetControlID="ddlModelName"
ServiceMethod="GetAllModelByBrand" ServicePath="~/WebService/CarService.asmx">
</ajaxToolKit:CascadingDropDown>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="BtnAdd" Text="Add" runat="server" OnClick="BtnAdd_Click" />
<asp:Button ID="BtnDelete" Visible="false" Text="Delete" CommandName="Delete" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<FooterStyle BackColor="#CCCC99" />
<HeaderStyle BackColor="#6B696B" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#F7F7DE" ForeColor="Black" HorizontalAlign="Right" />
<RowStyle BackColor="#F7F7DE" />
<SelectedRowStyle BackColor="#CE5D5A" Font-Bold="True" ForeColor="White" />
<SortedAscendingCellStyle BackColor="#FBFBF2" />
<SortedAscendingHeaderStyle BackColor="#848384" />
<SortedDescendingCellStyle BackColor="#EAEAD3" />
<SortedDescendingHeaderStyle BackColor="#575357" />
</asp:GridView>
在客户端页面上创建 GridView 后,我将创建一个名为 CarService.asmx 的 Web 服务。在此 Web 服务中,我创建了两个方法来绑定这两个下拉列表控件,分别命名为 GetAllCarBrand 和 GetAllModelByBrand。
这些方法返回由 Ajax Control-toolkit 库提供的 CascadingDropDownName Value 类的数组。列表包含汽车品牌名称,并根据品牌返回汽车型号名称,例如 Maruti 是一个品牌名称,Swift 是一个汽车型号。我使用了常量值来填充我的列表。Web 服务方法中应定义三个参数。
- Category:代表下拉列表的类别名称。
- KnownCategoryValues:此参数将返回一个字符串,其中包含当前选定的类别值以及要检索值的类别。这样我们就可以轻松找到父级下拉列表的值。
- Context key:用于绑定该下拉列表的选定值。您可以使用此上下文键来重新绑定下拉列表中已选定的值。
Web 服务代码如下:
/// <summary>
/// Summary description for CarService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class CarService : System.Web.Services.WebService
{
#region Public Member Declare Here
private List<CascadingDropDownNameValue> ListCascading;
#endregion
/// <summary>
/// Gets all car brand.
/// </summary>
/// <param name="knownCategoryValues">The known category values.</param>
/// <param name="category">The category.</param>
/// <param name="contextKey">The context key.</param>
/// <returns></returns>
[WebMethod]
public CascadingDropDownNameValue[] GetAllCarBrand(string knownCategoryValues, string category, string contextKey)
{
try
{
ListCascading = new List<CascadingDropDownNameValue>();
List<CarBrand> LstBrand = new List<CarBrand>();
LstBrand.Add(new CarBrand() { BrandId = 1, BrandName = "BMW" });
LstBrand.Add(new CarBrand() { BrandId = 2, BrandName = "Maruti" });
LstBrand.Add(new CarBrand() { BrandId = 3, BrandName = "Audi" });
LstBrand.Add(new CarBrand() { BrandId = 4, BrandName = "Ford" });
foreach (var item in LstBrand)
{
string brandId = item.BrandId.ToString();
string brandName = item.BrandName;
ListCascading.Add(new CascadingDropDownNameValue(brandName, brandId));
}
CascadingDropDownNameValue selectedVal = (from x in ListCascading where x.value == contextKey select x).FirstOrDefault();
if (selectedVal != null)
selectedVal.isDefaultValue = true;
return ListCascading.ToArray();
}
catch (SoapException)
{
throw;
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Gets all model by brand.
/// </summary>
/// <param name="knownCategoryValues">The known category values.</param>
/// <param name="category">The category.</param>
/// <param name="contextKey">The context key.</param>
/// <returns></returns>
[WebMethod]
public CascadingDropDownNameValue[] GetAllModelByBrand(string knownCategoryValues, string category, string contextKey)
{
try
{
ListCascading = new List<CascadingDropDownNameValue>();
//Find the selected value of brand
StringDictionary brandDetails = AjaxControlToolkit.CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);
var brandId = Convert.ToInt64(brandDetails["BrandName"]);
var LstOfCarModel = GetListOfModel().Where(u=>u.BrandId == brandId) ;
foreach (var item in LstOfCarModel)
{
string modelId = item.ModelId.ToString();
string modelName = item.CarName;
ListCascading.Add(new CascadingDropDownNameValue(modelName, modelId));
}
//Select the Selected value of Dropdown list.
CascadingDropDownNameValue selectedVal = (from x in ListCascading where x.value == contextKey select x).FirstOrDefault();
if (selectedVal != null)
selectedVal.isDefaultValue = true;
return ListCascading.ToArray();
}
catch (SoapException)
{
throw;
}
catch (Exception)
{
throw;
}
}
GetAllCarBrand 返回多个汽车品牌列表,方法 GetAllModelByBrand 根据品牌返回汽车型号。
创建 Web 服务后,设置 GridView 中级联下拉列表的属性。我已经在我的客户端代码中完成了这些操作。
CascadingDropDown 类有一个用于解包类别值的辅助方法:
StringDictionary brandDetails = AjaxControlToolkit.CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);
此方法将返回一个 StringDictionary,其中包含当前选定值的名称/值对。
这是我的 C# 类。此类包含一个名为 CarList 的方法,用于从汽车型号列表中绑定 GridView。我还使用了 grdDemo_RowDeleting 事件来删除 GridView 行,以及 grdDemo_RowDataBound 事件来在 GridView 控件的每一行中维护添加和删除功能。
public partial class Default : System.Web.UI.Page
{
#region Define Member Variable Here
static List<CarList> Staticlist;
#endregion
/// <summary>
/// Handles the Load event of the Page control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGrid();
}
}
/// <summary>
/// Binds the grid.
/// </summary>
private void BindGrid()
{
if (Staticlist == null)
{
Staticlist = new List<CarList>();
Staticlist.Add(new CarList());
}
grdDemo.DataSource = Staticlist;
grdDemo.DataBind();
}
/// <summary>
/// Handles the Click event of the BtnAdd control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void BtnAdd_Click(object sender, EventArgs e)
{
FillExistingValue();
Staticlist.Add(new CarList());
BindGrid();
}
/// <summary>
/// Fills the existing value.
/// </summary>
private void FillExistingValue()
{
for (int i = 0; i < grdDemo.Rows.Count; i++)
{
Staticlist[i].BrandId = Convert.ToInt32(((DropDownList)grdDemo.Rows[i].FindControl("ddlBrand")).SelectedItem.Value);
Staticlist[i].ModelId = Convert.ToInt32(((DropDownList)grdDemo.Rows[i].FindControl("ddlModelName")).SelectedItem.Value);
}
}
/// <summary>
/// Handles the RowDeleting event of the grdDemo control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewDeleteEventArgs"/> instance containing the event data.</param>
protected void grdDemo_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
Staticlist.RemoveAt(e.RowIndex);
BindGrid();
}
/// <summary>
/// Handles the RowDataBound event of the grdDemo control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewRowEventArgs"/> instance containing the event data.</param>
protected void grdDemo_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var BtnAdd = ((Button)e.Row.FindControl("BtnAdd"));
var BtnDel = ((Button)e.Row.FindControl("BtnDelete"));
if (e.Row.RowIndex == Staticlist.Count - 1)
{
BtnAdd.Visible = true;
BtnDel.Visible = false;
}
else
{
BtnAdd.Visible = false;
BtnDel.Visible = true;
}
}
}
}
我希望这篇文章能对大家有很大帮助。我将在文章中附上完整的代码。我的演示 GridView 的最终视图如下所示。
值得关注的点
这是 Ajax Control Toolkit 提供的一个非常好的功能。首先,我尝试用 Jquery 来实现相同的功能,但 Jquery 在处理客户端和服务器端时有点困难,在页面回发后您会丢失客户端值。您需要编写大量客户端代码来处理这种情况。此控件最大限度地减少了代码量,并提供了更大的灵活性来处理您的页面回发和事件,例如,我在我的演示 GridView 中有添加和删除按钮。
结论
有关源代码的更多详细信息,请从本文顶部的链接下载源代码。源代码易于理解且注释良好。
希望这个教程有用。