自己好几个地方要用到联动控件,项目又不想用Ajax,又想在客户端实现联动而不刷新,还想在服务器端用相似的代码来绑定项,还想在服务器端用相同的代码得到选定的值(也就是值可以提交),想了想,还是写一个控件好了.
以国家,省,市举例,我的实现思路是,
1.把所有国家绑定到国家列表,把所有的省绑定在省列表(包括各各国家),把所以的市绑定在市列表(包括所有的市).
2. 在客户端,用脚本把省,市和各项分组并保存,然后从 select.options 里去除不需要的option.
修正不能在同页面有多个联动的BUG
代码如下:
1. 控件代码:
namespace Iyond.Web.UI.WebControls


{
public class RelationDropDownList : System.Web.UI.WebControls.DropDownList

{
protected ValueParentValueDictionary valueParentValues = new ValueParentValueDictionary();

[DescriptionAttribute("ParentDropDownListControl"), IDReferenceProperty, TypeConverter(typeof(RelationDropDownListControlConverter)), Themeable(false), DefaultValue(""), CategoryAttribute("Behavior")]
public string ParentDropDownListControl

{
get

{
object obj1 = this.ViewState["ParentDropDownListControl"];
if (obj1 != null)

{
return (string)obj1;
}
return string.Empty;
}
set

{
this.ViewState["ParentDropDownListControl"] = value;
}
}

[DescriptionAttribute("ParentDropDownListControl"), IDReferenceProperty, TypeConverter(typeof(RelationDropDownListControlConverter)), Themeable(false), DefaultValue(""), CategoryAttribute("Behavior")]
public string ChildDropDownListControl

{
get

{
object obj1 = this.ViewState["ChildDropDownListControl"];
if (obj1 != null)

{
return (string)obj1;
}
return string.Empty;
}
set

{
this.ViewState["ChildDropDownListControl"] = value;
}
}


[DescriptionAttribute("DataParentValueField"), Themeable(false), DefaultValue(""), CategoryAttribute("Data")]
public virtual string DataParentValueField

{
get

{
object obj2 = this.ViewState["ParentDataValueField"];
if (obj2 != null)

{
return (string)obj2;
}
return string.Empty;
}
set

{
this.ViewState["ParentDataValueField"] = value;
if (base.Initialized)

{
base.RequiresDataBinding = true;
}
}
}



protected RelationDropDownList ParentDropDownList

{
get

{
if (string.IsNullOrEmpty(this.ParentDropDownListControl))
return null;

return this.NamingContainer.FindControl(this.ParentDropDownListControl) as RelationDropDownList;
}
}

protected RelationDropDownList ChildDropDownList

{
get

{
if (string.IsNullOrEmpty(this.ChildDropDownListControl))
return null;

return this.NamingContainer.FindControl(this.ChildDropDownListControl) as RelationDropDownList;
}
}

protected override void Render(HtmlTextWriter writer)

{

base.Render(writer);

if (this.ChildDropDownList == null)

{
//这是最后一级,依本身的SelectedIndex 来更新上级 修正不能在同页面有多个联动的BUG
Page.ClientScript.RegisterStartupScript(this.GetType(), this.ClientID + "_relddl_clearUp", string.Format("javascript:relddl_clearUp('{0}');", this.ClientID),true);
}
}

protected override void OnPreRender(EventArgs e)

{
Page.ClientScript.RegisterClientScriptResource(typeof(RelactionDropDownList), "Iyond.Web.UI.WebControls.DropDownList.Resources.RelationDDL.js");
base.OnPreRender(e);
}

protected override void AddAttributesToRender(HtmlTextWriter writer)

{
base.AutoPostBack = false;
base.AddAttributesToRender(writer);

writer.AddAttribute("parentSelect", this.ParentDropDownList != null?this.ParentDropDownList.ClientID:"");
writer.AddAttribute("childSelect",this.ChildDropDownList != null?this.ChildDropDownList.ClientID: "");


writer.AddAttribute( HtmlTextWriterAttribute.Onchange, "javascript:relddl_onchange(this,event)");
}

protected override void PerformDataBinding(System.Collections.IEnumerable dataSource)

{
base.PerformDataBinding(dataSource);
if (this.ParentDropDownList != null)

{
valueParentValues.Clear();

foreach (object obj in dataSource)

{
string dataValueField = this.DataValueField;
string parentDataValueField = this.DataParentValueField;
string value = Convert.ToString(DataBinder.GetPropertyValue(obj, dataValueField));
if (valueParentValues.ContainsKey(value))

{
throw new ArgumentException("相关的列表中. DataValueField 字段的值不能重复");
}


string parentValue = Convert.ToString(DataBinder.GetPropertyValue(obj, parentDataValueField));
valueParentValues.Add(value, parentValue);
}

SetItemParentValue();
}

}

protected virtual void SetItemParentValue()

{
foreach (string value in valueParentValues.Keys)

{
string parentValue = valueParentValues[value];

ListItem lt = this.Items.FindByValue(value);
if (lt != null)

{
lt.Attributes["parentValue"] =parentValue;
}
}
}



protected override object SaveViewState()

{
object x = base.SaveViewState();
object y = valueParentValues;
object z = null;
if (((z == null) && (y == null)))

{
return null;
}
return new Triplet(x, y, z);
}

protected override void LoadViewState(object savedState)

{
if (savedState != null)

{
Triplet triplet = (Triplet)savedState;
base.LoadViewState(triplet.First);
valueParentValues = triplet.Second as ValueParentValueDictionary;
if (valueParentValues != null)

{
SetItemParentValue();
}
}
else

{
base.LoadViewState(null);
}
}

}

public class RelationDropDownListControlConverter : ControlIDConverter

{
protected override bool FilterControl(Control control)

{
if (control is RelationDropDownList)
return true;
else

{
return false;
}

}
}

[Serializable]
public class ValueParentValueDictionary : Dictionary<string, string>

{
public ValueParentValueDictionary()
:base()

{}

public ValueParentValueDictionary(IDictionary<string, string> dictionary)
:base(dictionary)

{}
public ValueParentValueDictionary(IEqualityComparer<string> comparer)
:base(comparer)

{}

public ValueParentValueDictionary(int capacity)
:base(capacity)

{}

public ValueParentValueDictionary(IDictionary<string, string> dictionary, IEqualityComparer<string> comparer)
:base(dictionary,comparer)

{}
public ValueParentValueDictionary(int capacity, IEqualityComparer<string> comparer)
:base(capacity,comparer)

{}
protected ValueParentValueDictionary(SerializationInfo info, StreamingContext context)
:base(info,context)

{}
}

}

2. 使用举例:
<iyond:RelationDropDownList ID="ddlCountry" runat="server" ChildDropDownListControl="ddlProvince">
</iyond:RelationDropDownList>
<iyond:RelationDropDownList ID="ddlProvince" runat="server" ChildDropDownListControl="ddlCity" ParentDropDownListControl="ddlCountry">
</iyond:RelationDropDownList>
<iyond:RelationDropDownList ID="ddlCity" runat="server" ParentDropDownListControl="ddlProvince">
</iyond:RelationDropDownList>

protected void Page_Load(object sender, EventArgs e)

{
if (!Page.IsPostBack)

{
List<ZoneItem> listCountry = new List<ZoneItem>(

