近学习Asp.net Ajax控件开发,自己写了一个 CascadingListBox 控件对应于 AjaxControlToolkit 中的 CascadingDropDown,基本功能都实现了,代码如下:

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
7
namespace yixin_webcontrols
8

{
9
/**//// <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
{
17
private string _ParentControlID;
18
/**//// <summary>
19
/// 父ListBox控件
20
/// </summary>
21
[IDReferenceProperty(typeof(ListBox))]
22
[DefaultValue("")]
23
[Category("绑定控件")]
24
[Description("设置父ListBox控件")]
25
public string ParentControlID
26
{
27
get
28
{
29
return _ParentControlID;
30
}
31
set
32
{
33
_ParentControlID = value;
34
}
35
}
36
37
private string _Category;
38
/**//// <summary>
39
/// 设置分类/种类,用于区分绑定的ListBox显示的类别
40
/// </summary>
41
[DefaultValue("")]
42
[Category("必选属性")]
43
[Description("设置分类/种类,用于区分绑定的ListBox显示的类别")]
44
public string Category
45
{
46
get
{ return _Category; }
47
set
{ _Category = value; }
48
}
49
50
private string _EmptyText;
51
/**//// <summary>
52
/// 当没有父分类没有选中任何数据时ListBox显示的文本 如:请选择父分类
53
/// </summary>
54
[DefaultValue("")]
55
[Category("可选属性")]
56
[Description("当没有父分类没有选中任何数据时ListBox显示的文本 如:请选择父分类")]
57
public string EmptyText
{ get
{ return _EmptyText; } set
{ _EmptyText = value; } }
58
59
private string _LoadingText;
60
/**//// <summary>
61
/// 当ListBox正在请求服务器数据时显示的文本 如:正在加载
62
/// 不设置此属性将默认显示“正在加载
”
63
/// </summary>
64
[DefaultValue("")]
65
[Category("可选属性")]
66
[Description("当ListBox正在请求服务器数据时显示的文本 如:正在加载
,不设置此属性将默认显示“正在加载
”")]
67
public string LoadingText
{ get
{ return _LoadingText; } set
{ _LoadingText = value; } }
68
69
private string _ServicePath;
70
/**//// <summary>
71
/// 设置ListBox请求数据的web服务路径
72
/// </summary>
73
[UrlProperty()]
74
[DefaultValue("")]
75
[Category("必选属性")]
76
[Description("设置ListBox请求数据的web服务路径")]
77
public string ServicePath
{ get
{ return _ServicePath; } set
{ _ServicePath = value; } }
78
79
private string _ServiceMethod;
80
/**//// <summary>
81
/// 设置ListBox请求数据的web服务中调用的方法
82
/// </summary>
83
[DefaultValue("")]
84
[Category("必选属性")]
85
[Description("设置ListBox请求数据的web服务中调用的方法")]
86
public string ServiceMethod
{ get
{ return _ServiceMethod; } set
{ _ServiceMethod = value; } }
87
88
/**//// <summary>
89
/// 重写基类GetScriptDescriptors()方法 添加控件客户端属性
90
/// </summary>
91
/// <param name="targetControl"></param>
92
/// <returns></returns>
93
protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)
94
{
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
return new ScriptDescriptor[]
{ descriptor };
106
}
107
/**//// <summary>
108
/// 重写基类GetScriptReferences()方法 注册yixin_webcontrols.CascadingListBoxBehavior客户端类型
109
/// </summary>
110
/// <returns></returns>
111
protected override IEnumerable<ScriptReference> GetScriptReferences()
112
{
113
return new ScriptReference[]
{ new ScriptReference(Page.ClientScript.GetWebResourceUrl(this.GetType(),"yixin_webcontrols.CascadingListBoxBehavior.js")) };
114
}
115
}
116
}
117

CascadingListBoxNameValue.cs
1
using System;
2
3
namespace yixin_webcontrols
4

{
5
/**//// <summary>
6
/// 用于Web服务返回的ListBox键值对
7
/// </summary>
8
[Serializable]
9
public class CascadingListBoxNameValue
10
{
11
/**//// <summary>
12
/// ListBox.Option显示的文本
13
/// </summary>
14
public string Name;
15
/**//// <summary>
16
/// ListBox.Option的值
17
/// </summary>
18
public string Value;
19
/**//// <summary>
20
/// ListBox.Option是否被选中
21
/// </summary>
22
public bool isDefaultValue;
23
24
/**//// <summary>
25
/// 初始化一个空白的CascadingListBoxNameValue对象
26
/// </summary>
27
public CascadingListBoxNameValue()
28
{
29
}
30
/**//// <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
{
37
this.Name = name;
38
this.Value = value;
39
}
40
/**//// <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
{
48
this.Name = name;
49
this.Value = value;
50
this.isDefaultValue = defaultValue;
51
}
52
}
53
}
54

CascadingListBoxBehavior.js
1
/// <reference name="MicrosoftAjax.js"/>
2
3
Type.registerNamespace("Yinxin_WebControls");
4
5
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
Yinxin_WebControls.CascadingListBoxBehavior.prototype =
{
15
//属性
16
get_ParentControlID: function()
{
17
return this._ParentControlID;
18
},
19
set_ParentControlID: function(value)
{
20
this._ParentControlID = value;
21
},
22
get_Category: function()
{
23
return this._Category;
24
},
25
set_Category: function(value)
{
26
this._Category = value;
27
},
28
get_EmptyText: function()
{
29
return this._EmptyText;
30
},
31
set_EmptyText: function(value)
{
32
this._EmptyText = value;
33
},
34
get_LoadingText: function()
{
35
return this._LoadingText;
36
},
37
set_LoadingText: function(value)
{
38
this._LoadingText = value;
39
},
40
get_ServicePath: function()
{
41
return this._ServicePath;
42
},
43
set_ServicePath: function(value)
{
44
this._ServicePath = value;
45
},
46
get_ServiceMethod: function()
{
47
return this._ServiceMethod;
48
},
49
set_ServiceMethod: function(value)
{
50
this._ServiceMethod = value;
51
},
52
//方法
53
Disable: function()
{
54
this.get_element().disabled = 'disabled';
55
},
56
Enable: function()
{
57
this.get_element().disabled = '';
58
},
59
ClearItems: function()
{
60
this.get_element().innerHTML = "";
61
},
62
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
_onParentChange: function(e, ParentisNull)
{
70
var knownCategoryValues = "";
71
if (!ParentisNull)
{
72
knownCategoryValues = this._ParentElement.value;
73
if (knownCategoryValues == "")
74
return false;
75
}
76
this.ClearItems();
77
this.AddOption(this._LoadingText, "");
78
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
_onsuccess: function(e)
{
84
this.ClearItems();
85
86
this.get_element().value = "";
87
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
94
this.Enable();
95
96
if (this.get_element()._childListBox)
97
this.get_element()._childListBox._onParentChange();
98
},
99
_onfailure: function(e)
{
100
alert(this.get_name() + "在对象" + this.ClientID + "上的错误\n\n错误代码:" + e._statusCode + "\n详细信息:" + e._message + "\n" + e._stackTrace);
101
},
102
initialize: function()
{
103
Yinxin_WebControls.CascadingListBoxBehavior.callBaseMethod(this, 'initialize');
104
// 在此处添加自定义初始化
105
this.ClientID = this.get_element().id;
106
107
this.ClearItems();
108
109
this.AddOption(this._EmptyText, "");
110
111
this.get_element().disabled = 'disabled';
112
113
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
else
{
120
this._onParentChange(null, true);
121
}
122
},
123
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
131
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
132
最后把脚本注册为资源就OK了
1
//加入这句
2
[assembly: System.Web.UI.WebResource("yixin_webcontrols.CascadingListBoxBehavior.js","text/javascript")]
使用事例:

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
11
12
/**//// <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

{
20
[WebMethod]
21
public CascadingListBoxNameValue[] GetClasses(string knownCategoryValues, string category)
22
{
23
//knownCategoryValues:父ListBox选中的value
24
//category:当前ListBox所属分类
25
26
CascadingListBoxNameValue[] cddnv;
27
switch (category)
28
{
29
case "Classes":
30
//cddnv[0] = new CascadingListBoxNameValue(Name,Id);
31
//cddnv[1] = new CascadingListBoxNameValue(Name,Id);
32
//其他操作
33
break;
34
default:
35
//cddnv[0] = new CascadingListBoxNameValue("未定义的category:" + category, "-1");
36
break;
37
}
38
return cddnv;
39
}
40
}
41
42
然后在页面上使用控件:

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" />