最近学习Asp.net Ajax控件开发,自己写了一个 CascadingListBox 控件对应于 AjaxControlToolkit 中的 CascadingDropDown,基本功能都实现了,代码如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
CascadingListBoxExtender.cs
1
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel;
4
using System.Web.UI;
5
using System.Web.UI.WebControls;
6![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
7
namespace yixin_webcontrols
8![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
9![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
10
/// 联动ListBox
11
/// </summary>
12
[DefaultProperty("TargetControlID")]
13
[ToolboxData("<{0}:CascadingListBox runat=server Category=\"\" LoadingText=\"\" EmptyText=\"\" TargetControlID=\"\" ParentControlID=\"\" ServiceMethod=\"\" ServicePath=\"\" />")]
14
[TargetControlType(typeof(ListBox))]
15
public class CascadingListBox : ExtenderControl
16![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
17
private string _ParentControlID;
18![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
19
/// 父ListBox控件
20
/// </summary>
21
[IDReferenceProperty(typeof(ListBox))]
22
[DefaultValue("")]
23
[Category("绑定控件")]
24
[Description("设置父ListBox控件")]
25
public string ParentControlID
26![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
27
get
28![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
29
return _ParentControlID;
30
}
31
set
32![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
33
_ParentControlID = value;
34
}
35
}
36![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
37
private string _Category;
38![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
39
/// 设置分类/种类,用于区分绑定的ListBox显示的类别
40
/// </summary>
41
[DefaultValue("")]
42
[Category("必选属性")]
43
[Description("设置分类/种类,用于区分绑定的ListBox显示的类别")]
44
public string Category
45![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
46![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _Category; }
47![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ _Category = value; }
48
}
49![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
50
private string _EmptyText;
51![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
52
/// 当没有父分类没有选中任何数据时ListBox显示的文本 如:请选择父分类
53
/// </summary>
54
[DefaultValue("")]
55
[Category("可选属性")]
56
[Description("当没有父分类没有选中任何数据时ListBox显示的文本 如:请选择父分类")]
57![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string EmptyText
{ get
{ return _EmptyText; } set
{ _EmptyText = value; } }
58![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
59
private string _LoadingText;
60![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
61
/// 当ListBox正在请求服务器数据时显示的文本 如:正在加载![](https://www.cnblogs.com/Images/dot.gif)
62
/// 不设置此属性将默认显示“正在加载
”
63
/// </summary>
64
[DefaultValue("")]
65
[Category("可选属性")]
66
[Description("当ListBox正在请求服务器数据时显示的文本 如:正在加载
,不设置此属性将默认显示“正在加载
”")]
67![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string LoadingText
{ get
{ return _LoadingText; } set
{ _LoadingText = value; } }
68![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
69
private string _ServicePath;
70![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
71
/// 设置ListBox请求数据的web服务路径
72
/// </summary>
73
[UrlProperty()]
74
[DefaultValue("")]
75
[Category("必选属性")]
76
[Description("设置ListBox请求数据的web服务路径")]
77![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string ServicePath
{ get
{ return _ServicePath; } set
{ _ServicePath = value; } }
78![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
79
private string _ServiceMethod;
80![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
81
/// 设置ListBox请求数据的web服务中调用的方法
82
/// </summary>
83
[DefaultValue("")]
84
[Category("必选属性")]
85
[Description("设置ListBox请求数据的web服务中调用的方法")]
86![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string ServiceMethod
{ get
{ return _ServiceMethod; } set
{ _ServiceMethod = value; } }
87![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
88![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
89
/// 重写基类GetScriptDescriptors()方法 添加控件客户端属性
90
/// </summary>
91
/// <param name="targetControl"></param>
92
/// <returns></returns>
93
protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)
94![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
95
ScriptBehaviorDescriptor descriptor = new ScriptBehaviorDescriptor("Yinxin_WebControls.CascadingListBoxBehavior", targetControl.ClientID);
96
if(_ParentControlID!=null)
97
descriptor.AddProperty("ParentControlID", this._ParentControlID);
98
descriptor.AddProperty("Category", this._Category);
99
if(_EmptyText!=null)
100
descriptor.AddProperty("EmptyText", this._EmptyText);
101
if(_LoadingText !=null)
102
descriptor.AddProperty("LoadingText", this._LoadingText);
103
descriptor.AddProperty("ServicePath", this._ServicePath);
104
descriptor.AddProperty("ServiceMethod", this._ServiceMethod);
105![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
return new ScriptDescriptor[]
{ descriptor };
106
}
107![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
108
/// 重写基类GetScriptReferences()方法 注册yixin_webcontrols.CascadingListBoxBehavior客户端类型
109
/// </summary>
110
/// <returns></returns>
111
protected override IEnumerable<ScriptReference> GetScriptReferences()
112![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
113![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
return new ScriptReference[]
{ new ScriptReference(Page.ClientScript.GetWebResourceUrl(this.GetType(),"yixin_webcontrols.CascadingListBoxBehavior.js")) };
114
}
115
}
116
}
117![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
CascadingListBoxNameValue.cs
1
using System;
2![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
namespace yixin_webcontrols
4![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
5![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
6
/// 用于Web服务返回的ListBox键值对
7
/// </summary>
8
[Serializable]
9
public class CascadingListBoxNameValue
10![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
12
/// ListBox.Option显示的文本
13
/// </summary>
14
public string Name;
15![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
16
/// ListBox.Option的值
17
/// </summary>
18
public string Value;
19![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
20
/// ListBox.Option是否被选中
21
/// </summary>
22
public bool isDefaultValue;
23![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
24![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
25
/// 初始化一个空白的CascadingListBoxNameValue对象
26
/// </summary>
27
public CascadingListBoxNameValue()
28![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
29
}
30![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
31
/// 初始化一个CascadingListBoxNameValue对象
32
/// </summary>
33
/// <param name="name">ListBox.Option显示的文本</param>
34
/// <param name="value">ListBox.Option的值</param>
35
public CascadingListBoxNameValue(string name, string value)
36![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
37
this.Name = name;
38
this.Value = value;
39
}
40![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
41
/// 初始化一个CascadingListBoxNameValue对象
42
/// </summary>
43
/// <param name="name">ListBox.Option显示的文本</param>
44
/// <param name="value">ListBox.Option的值</param>
45
/// <param name="defaultValue">ListBox.Option是否被选中</param>
46
public CascadingListBoxNameValue(string name, string value, bool defaultValue)
47![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
48
this.Name = name;
49
this.Value = value;
50
this.isDefaultValue = defaultValue;
51
}
52
}
53
}
54![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
CascadingListBoxBehavior.js
1
/// <reference name="MicrosoftAjax.js"/>
2![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
Type.registerNamespace("Yinxin_WebControls");
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
Yinxin_WebControls.CascadingListBoxBehavior = function(element)
{
6
Yinxin_WebControls.CascadingListBoxBehavior.initializeBase(this, [element]);
7
this._ParentControlID = null;
8
this._Category = null;
9
this._EmptyText = "[没有数据]";
10
this._LoadingText = "[正在加载
]";
11
this._ServicePath = null;
12
this._ServiceMethod = null;
13
}
14![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
Yinxin_WebControls.CascadingListBoxBehavior.prototype =
{
15
//属性
16![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get_ParentControlID: function()
{
17
return this._ParentControlID;
18
},
19![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set_ParentControlID: function(value)
{
20
this._ParentControlID = value;
21
},
22![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get_Category: function()
{
23
return this._Category;
24
},
25![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set_Category: function(value)
{
26
this._Category = value;
27
},
28![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get_EmptyText: function()
{
29
return this._EmptyText;
30
},
31![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set_EmptyText: function(value)
{
32
this._EmptyText = value;
33
},
34![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get_LoadingText: function()
{
35
return this._LoadingText;
36
},
37![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set_LoadingText: function(value)
{
38
this._LoadingText = value;
39
},
40![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get_ServicePath: function()
{
41
return this._ServicePath;
42
},
43![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set_ServicePath: function(value)
{
44
this._ServicePath = value;
45
},
46![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get_ServiceMethod: function()
{
47
return this._ServiceMethod;
48
},
49![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set_ServiceMethod: function(value)
{
50
this._ServiceMethod = value;
51
},
52
//方法
53![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
Disable: function()
{
54
this.get_element().disabled = 'disabled';
55
},
56![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
Enable: function()
{
57
this.get_element().disabled = '';
58
},
59![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
ClearItems: function()
{
60
this.get_element().innerHTML = "";
61
},
62![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
AddOption: function(Name, Value, isSelected)
{
63
var optionElement = new Option(Name, Value);
64
if (isSelected)
65
optionElement.selected = true;
66
this.get_element().options[this.get_element().options.length] = optionElement;
67
},
68
//事件处理
69![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
_onParentChange: function(e, ParentisNull)
{
70
var knownCategoryValues = "";
71![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!ParentisNull)
{
72
knownCategoryValues = this._ParentElement.value;
73
if (knownCategoryValues == "")
74
return false;
75
}
76
this.ClearItems();
77
this.AddOption(this._LoadingText, "");
78![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
var params =
{ "knownCategoryValues": knownCategoryValues, "category": this._Category };
79
var onsuccess = Function.createDelegate(this, this._onsuccess);
80
var onfailure = Function.createDelegate(this, this._onfailure);
81
Sys.Net.WebServiceProxy.invoke(this.get_ServicePath(), this.get_ServiceMethod(), false, params, onsuccess, onfailure);
82
},
83![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
_onsuccess: function(e)
{
84
this.ClearItems();
85![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
86
this.get_element().value = "";
87![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (var i = 0; i < e.length; i++)
{
88
if (e[i].isDefaultValue)
89
this.AddOption(e[i].Name, e[i].Value, true);
90
else
91
this.AddOption(e[i].Name, e[i].Value);
92
}
93![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
94
this.Enable();
95![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
96
if (this.get_element()._childListBox)
97
this.get_element()._childListBox._onParentChange();
98
},
99![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
_onfailure: function(e)
{
100
alert(this.get_name() + "在对象" + this.ClientID + "上的错误\n\n错误代码:" + e._statusCode + "\n详细信息:" + e._message + "\n" + e._stackTrace);
101
},
102![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
initialize: function()
{
103
Yinxin_WebControls.CascadingListBoxBehavior.callBaseMethod(this, 'initialize');
104
// 在此处添加自定义初始化
105
this.ClientID = this.get_element().id;
106![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
107
this.ClearItems();
108![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
109
this.AddOption(this._EmptyText, "");
110![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
111
this.get_element().disabled = 'disabled';
112![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
113![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (this._ParentControlID != null)
{
114
this._ParentElement = $get(this._ParentControlID);
115
this._ParentElement._childListBox = this;
116
var changeHandler = Function.createDelegate(this, this._onParentChange);
117
$addHandler(this._ParentElement, "change", changeHandler);
118
}
119![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
120
this._onParentChange(null, true);
121
}
122
},
123![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
dispose: function()
{
124
//在此处添加自定义释放操作
125
$clearHandlers(this.get_element());
126
Yinxin_WebControls.CascadingListBoxBehavior.callBaseMethod(this, 'dispose');
127
}
128
}
129
Yinxin_WebControls.CascadingListBoxBehavior.registerClass('Yinxin_WebControls.CascadingListBoxBehavior', Sys.UI.Behavior);
130![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
131
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
132![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
最后把脚本注册为资源就OK了
1
//加入这句
2
[assembly: System.Web.UI.WebResource("yixin_webcontrols.CascadingListBoxBehavior.js","text/javascript")]
使用事例:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
ClassService.cs
1
//web服务
2
using System;
3
using System.Web;
4
using System.Collections;
5
using System.Web.Services;
6
using System.Web.Services.Protocols;
7
using DWZ_DAL.Xml;
8
using DWZ_Entity.Xml;
9
using yixin_webcontrols;
10![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
11![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
12![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//// <summary>
13
/// ClassService 的摘要说明
14
/// </summary>
15
[WebService(Namespace = "http://tempuri.org/")]
16
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
17
[System.Web.Script.Services.ScriptService]
18
public class ClassService : System.Web.Services.WebService
19![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
20
[WebMethod]
21
public CascadingListBoxNameValue[] GetClasses(string knownCategoryValues, string category)
22![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
23
//knownCategoryValues:父ListBox选中的value
24
//category:当前ListBox所属分类
25![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
26
CascadingListBoxNameValue[] cddnv;
27
switch (category)
28![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
29
case "Classes":
30
//cddnv[0] = new CascadingListBoxNameValue(Name,Id);
31
//cddnv[1] = new CascadingListBoxNameValue(Name,Id);
32
//其他操作![](https://www.cnblogs.com/Images/dot.gif)
33
break;
34
default:
35
//cddnv[0] = new CascadingListBoxNameValue("未定义的category:" + category, "-1");
36
break;
37
}
38
return cddnv;
39
}
40
}
41![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
42![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
然后在页面上使用控件:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
<%@ Register Assembly="yixin_webcontrols2.0" Namespace="yixin_webcontrols" TagPrefix="cc3" %>
<asp:ListBox ID="ListBox1" runat="server" Height="300px" Width="140px"></asp:ListBox>
<cc3:CascadingListBox ID="CascadingListBox1" Category="BigClass" EmptyText="" TargetControlID="ListBox1" ServiceMethod="GetClasses" ServicePath="../Service/ClassService.asmx" runat="server" />
<asp:ListBox ID="ListBox2" runat="server" Height="300px" Width="140px"></asp:ListBox>
<cc3:CascadingListBox ID="CascadingListBox2" Category="Classes" EmptyText="请选择大分类" TargetControlID="ListBox2" ParentControlID="ListBox1" ServiceMethod="GetClasses" ServicePath="../Service/ClassService.asmx" runat="server" />
<asp:ListBox ID="ListBox3" runat="server" Height="300px" Width="140px"></asp:ListBox>
<cc3:CascadingListBox ID="CascadingListBox3" Category="Class" EmptyText="请选择一级分类" TargetControlID="ListBox3" ParentControlID="ListBox2" ServiceMethod="GetClasses" ServicePath="../Service/ClassService.asmx" runat="server" />