1.当前要准备好js,下面的代码在网上下的,作者不可考,向这位IT工作者致敬! linkage.js (仅在changeLinkage方法中加入一个SetAssociatedDropDownListValue(element);) 此js库依赖于prototype.js而运行,网上到处有下的
var Linkage = Class.create();
Linkage.prototype = {
 initialize : function(dataSrc, xmlFile) {
 this.dataSrc = dataSrc;
 this.xmlFile = xmlFile;
 },
 dataSrc : "" ,
 xmlFile : "" ,
 
 BLANK_SELECT : "-----Select-----" ,
 AllMenuArr : new Array() ,
 MenuIdArr : new Array() ,
 MenuInfoArr : new Array() ,
 iDepth : -1 ,
 tree : function(dataSrc, Element) {
 var node = "";
 if(Element.nodeType != 3) {
 node = Element;
 this.onElement(dataSrc, Element);
 }
 if(Element.hasChildNodes) {
 for(var i=0;i if (Element.childNodes[i].nodeType != 3) {
 this.iDepth++;
 this.tree(dataSrc, Element.childNodes[i]);
 }
 }
 }
 if(node) {
 this.endElement();
 }
 } ,
 onElement : function(dataSrc, ele) {
 if (V(ele, "Value") != null) {
 if (this.MenuInfoArr[dataSrc] == null) {
 this.MenuInfoArr[dataSrc] = new Array();
 }
 if (this.MenuInfoArr[dataSrc][this.iDepth] == null) {
 this.MenuInfoArr[dataSrc][this.iDepth] = new Array();
 }
 this.MenuInfoArr[dataSrc][this.iDepth].push(new MenuInfo(V(ele.parentNode, "Value") , V(ele, "Value") , (V(ele, "Desc")==null ? V(ele, "Value") : V(ele, "Desc"))));
 }
 } ,
 endElement : function() {
 this.iDepth--;
 } ,
 initBlank : function(element) {
 element.length = 0;
 element.options.add(new Option( this.BLANK_SELECT, "" ));
 element.selectedIndex = 0;
 } ,
 updateAllLast : function(dataSrc, nLevel) {
 for(i = nLevel+1; i < this.MenuIdArr[dataSrc].length; i++) {
 childNode = (this.MenuIdArr[dataSrc][i]);
 this.initBlank(childNode);
 childNode.disabled = true;
 }
 } ,
 initLinkage : function(dataSrc, sValue, nLevel) {
 nLevel = Number(nLevel);
 if (nLevel > this.MenuIdArr[dataSrc].length || nLevel < 1) {
 return;
 }
 currNode = (this.MenuIdArr[dataSrc][nLevel-1]);
 childNode = (this.MenuIdArr[dataSrc][nLevel]);
 if (currNode.disabled) {
 return;
 }
 for (i=0; i if (currNode.options[i].value == sValue) {
 currNode.selectedIndex = i;
 break;
 }
 }
 if (childNode != null) {
 currArr = this.AllMenuArr[dataSrc][nLevel];
 this.initBlank(childNode);
 for(i=0; i if (currArr[i].parentValue == sValue) {
 childNode.options.add(new Option(currArr[i].Desc, currArr[i].Value));
 }
 }
 if ((sValue != '') && (childNode.length > 1)) {
 childNode.disabled = false;
 } else {
 childNode.disabled = true;
 }
 }
 this.updateAllLast(dataSrc, nLevel);
 } ,
 changeLinkage : function(element) {
 SetAssociatedDropDownListValue(element);
 this.initLinkage(V(element , "USEDATA"), F(element), V(element , "SUBCLASS"));
 } ,
 setDataSrc : function(dataSrc) {
 this.dataSrc = dataSrc;
 } ,
 setXmlFile : function(xmlFile) {
 this.xmlFile = xmlFile;
 } ,
 init : function() {
 var rootEle = loadXML(this.dataSrc, this.xmlFile);
 this.tree(this.dataSrc, rootEle);
 this.iDepth = -1;
 for (i=0; i if (this.AllMenuArr[this.dataSrc] == null) {
 this.AllMenuArr[this.dataSrc] = new Array();
 }
 this.AllMenuArr[this.dataSrc].push(this.MenuInfoArr[this.dataSrc][i]);
 }
 var selectNodes = document.getElementsByTagName("select");
 for (i=0; i if (V(selectNodes[i] , "USEDATA") == this.dataSrc) {
 if (this.MenuIdArr[this.dataSrc] == null) {
 this.MenuIdArr[this.dataSrc] = new Array();
 }
 var subClass = Number(V(selectNodes[i] , "SUBCLASS")) - 1;
 this.MenuIdArr[this.dataSrc][subClass] = V(selectNodes[i] , "id");
 Event.observe(selectNodes[i], "change", this.changeLinkage.bind(this, selectNodes[i]));
 }
 }
 firstNode = (this.MenuIdArr[this.dataSrc].first());
 this.initBlank(firstNode);
 for (i=0; i firstNode.options.add(new Option(this.AllMenuArr[this.dataSrc].first()[i].Desc, this.AllMenuArr[this.dataSrc].first()[i].Value));
 }
 this.updateAllLast(this.dataSrc, 0);
 }
}
var MenuInfo = Class.create();
MenuInfo.prototype = {
 initialize : function(sParentValue, sValue, sDesc) {
 this.parentValue = sParentValue;
 this.Value = sValue;
 this.Desc = sDesc;
 }
}
function V(ele, attr) {
 return ele.getAttribute(attr);
}
function createXMLDom() {
 if (window.ActiveXObject)
 var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
 else
 if (document.implementation&&document.implementation.createDocument)
 var xmldoc = document.implementation.createDocument("","doc",null);
 xmldoc.async = false;
 xmldoc.preserveWhiteSpace=true;
 return xmldoc;
} 
function loadXML(dataSrc, xmlFile) {
 if (xmlFile == null) {
 if (window.ActiveXObject) {
 return (dataSrc).documentElement;
 } else {
 for (i=0; i<(dataSrc).childNodes.length; i++) {
 if ((dataSrc).childNodes[i].tagName != null) {
 return (dataSrc).childNodes[i];
 break;
 }
 }
 }
 } else {
 var xmlDom = createXMLDom();
 try{
 xmlDom.load(xmlFile);
 }catch(e){
 alert("lost xml File");
 }
 return xmlDom.documentElement;
 }
} 
2.简单的控件类 必须的属性有USEDATA和Xml,USEDATA可以随便指定,应该是为了页面上有多个联动而设计的,现在没有支持,另一个xml属性用于指定xml格式数据源 ,另外依赖于外部js /Script/linkage.js和/Script/prototype.js
.using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.ComponentModel;
using System.Collections.Specialized;
namespace Blackant.Controls
{
 [DefaultProperty("Value")]
 public class AssociatedDropDownList : WebControl, IPostBackDataHandler
 {
 字段#region 字段
 private string _Xml="";
 private XmlDocument _XmlDoc;
 
 #endregion
 属性#region 属性
 [Bindable(true)]
 [Category("Appearance")]
 [DefaultValue("0")]
 [Localizable(true)]
 public string Value
 {
 get
 {
 return ViewState["Value"] == null ? "0" : ViewState["Value"].ToString();
 }
 set
 {
 ViewState["Value"] = value;
 }
 }
 public string USEDATA
 {
 get
 {
 if (ViewState["USEDATA"] != null)
 return ViewState["USEDATA"].ToString();
 return String.Empty;
 }
 set { ViewState["USEDATA"] = value; }
 }
 /**//// 
 /// 字符串形式表达的xml格式文档
 /// 
 public string Xml {
 get { return _Xml; }
 set { _Xml = value;
 
 }
 }
 #endregion
 私有方法#region 私有方法
 int GetMaxLevel(XmlNode parent, int CurLevel)
 {
 int MaxLevel = CurLevel;
 foreach (XmlNode xn in parent.ChildNodes)
 {
 if (xn.NodeType == XmlNodeType.Element)
 {
 int tmpLevel = GetMaxLevel(xn, CurLevel + 1);
 MaxLevel = MaxLevel > tmpLevel ? MaxLevel : tmpLevel;
 }
 }
 return MaxLevel;
 }
 #endregion
 重载事件#region 重载事件
 protected override void CreateChildControls()
 {
 _XmlDoc = new XmlDocument();
 _XmlDoc.LoadXml(_Xml);
 XmlElement root = _XmlDoc.DocumentElement;
 int maxLevel = GetMaxLevel(root, 1);
 for (int i = 1; i < maxLevel; i++)
 {
 DropDownList ddl = new DropDownList();
 ddl.Attributes.Add("USEDATA", USEDATA);
 ddl.Attributes.Add("SUBCLASS", i.ToString());
 ddl.ID = ddl.ClientID;
 Controls.Add(ddl);
 }
 base.CreateChildControls();
 }
 protected override void OnPreRender(EventArgs e)
 {
 Page.RegisterRequiresPostBack(this);
 Page.ClientScript.RegisterHiddenField(this.ClientID, Value);
 base.OnPreRender(e);
 }
 protected override void Render(HtmlTextWriter writer)
 {
 
 StringBuilder sb = new StringBuilder();
 sb.AppendFormat("", USEDATA);
 sb.Append(_Xml);
 sb.Append("");
 sb.Append("  ");
 sb.Append(" ");
 sb.Append("");
 Page.ClientScript.RegisterStartupScript(typeof(string), USEDATA, sb.ToString());
 
 
 base.Render(writer);
 }
 #endregion
 IPostBackDataHandler Members#region IPostBackDataHandler Members
 //private static readonly object EventTextChanged = new object();
 public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
 {
 //比较初始数据presentValue和回传数据postedValue
 string postedValue = postCollection[postDataKey];
 string presentValue = Value;
 if (presentValue == null || postedValue != presentValue)
 {
 Value = postedValue;
 return true;
 }
 return false;
 }
 void IPostBackDataHandler.RaisePostDataChangedEvent()
 {
 }
 #endregion
 }
}
3简单运用,
<%@ Page Language="C#" %>
<%@ Register Assembly="Blackant.Controls" Namespace="Blackant.Controls" TagPrefix="bawc" %>
 protected override void OnLoad(EventArgs e)
{
 
 AssociatedDropDownList1.USEDATA = "test";
 AssociatedDropDownList1.Xml = @"
 
  
 
  
  
 
 
 
  
 
 
";
 
 base.OnLoad(e);
}
 protected void btnSubmit_Click(object sender, EventArgs e)
 {
 Response.Write("当前选择:"+AssociatedDropDownList1.Value);
 }
 Untitled Page
 
来源:CSDN