前几天泡论坛的时候发现有很多人问关于联动DropDownList的问题 在下不才写了个支持联动的DropDownList服务器控件 方便大家 代码有点儿不好懂我会写上注释 2楼上调用代码 欢迎拍砖
源代码:using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;[assembly: TagPrefix("WebApplication", "MyControl")]
namespace WebApplication1
{
    
    [ToolboxData("<{0}:LinkedDropDownList runat=server></{0}:LinkedDropDownList>")]
    public class LinkedDropDownList : DropDownList//继承自基本的DropDownList
    {
        private DropDownList _linkedDropDownList;        public LinkedDropDownList()
        {
            this.SelectedIndexChanged += new EventHandler(LinkedDropDownList_SelectedIndexChanged);//添加自己的SelectedIndexChanged事件
            this.AutoPostBack = true;//强制设置自己的AutoPostBack为true
        }
        //下面两个事件都作为获取数据源的事件
        public event EventHandler BindData;//这个事件为绑定父DropDownList
        public event Action<object, DropDownListIndexChangeEventArg> BindLinkedData;//这个事件为绑定子DropDownList        protected void LinkedDropDownList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.BindLinkedData != null)
            {
                this._linkedDropDownList = this.NamingContainer.FindControl(this.NextDropDownListID) as DropDownList;//从控件容器中找出子下拉菜单
                var newE = new DropDownListIndexChangeEventArg(this.SelectedValue, this.SelectedItem.Text, this.SelectedIndex,this._linkedDropDownList);
                BindLinkedData(this, newE);
            }
            //如果子DropDownList本身也为联动DropDownList 执行子DropDownList的绑定
            var next = this.NamingContainer.FindControl(this.NextDropDownListID) as LinkedDropDownList;
            if (next != null)
            {
                next.OnSelectedIndexChanged(EventArgs.Empty);
            }
        }
        //重写OnLoad使得可以发生数据绑定
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (this.BindData != null && !Page.IsPostBack)
            {
                BindData(this, EventArgs.Empty);
                this.SelectedIndex = 0;
                
            }
            if (this.BindLinkedData != null &&!Page.IsPostBack)
            {
                this._linkedDropDownList = this.NamingContainer.FindControl(this.NextDropDownListID) as DropDownList;
                var newE = new DropDownListIndexChangeEventArg(this.SelectedValue, this.SelectedItem.Text, this.SelectedIndex, this._linkedDropDownList);
                BindLinkedData(this, newE);
            }
        }
        //子DropDownList的ID
        public string NextDropDownListID
        {
            get
            {
                return ViewState[this.ID + "LinkedDropDownList"] as string;//加上自身的ID做唯一标示
            }
            set
            {
                ViewState[this.ID + "LinkedDropDownList"] = value;
               
            }
        }
    }
    //事件参数 方便绑定子菜单时候得到数据源绑定参数
    public class DropDownListIndexChangeEventArg : EventArgs
    {
        private readonly string _selectedValue = null;
        private readonly string _selectedText = null;
        private readonly int _selectedIndex;
        private readonly DropDownList _nextDropDownList = null;        public DropDownListIndexChangeEventArg(string selectedValue, string selectedText, int selectedIndex,DropDownList nextDropDownList)
        {
            this._selectedValue = selectedValue;
            this._selectedText = selectedText;
            this._selectedIndex = selectedIndex;
            this._nextDropDownList = nextDropDownList;
        }        public string SelectedValue
        {
            get
            {
                return this._selectedValue;
            }
        }        public string SelectedText
        {
            get
            {
                return this._selectedText;
            }
        }        public int SelectedIndex
        {
            get
            {
                return this._selectedIndex;
            }
        }        public DropDownList NextDropDownList
        {
            get
            {
                return this._nextDropDownList;
            }
        }
    }
}

解决方案 »

  1.   

    调用代码:
    首先我们需要一个Mock类来产生绑定的数据 下面是Mock类的代码using System;
    using System.Data;
    using System.Configuration;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Linq;
    using System.Collections.Generic;
    namespace WebApplication1
    {
        public class MockData
        {
            public Dictionary<int,string> GetRootData()
            {
                var returnValue = new Dictionary<int, string>();
                returnValue.Add(1, "a");
                returnValue.Add(2, "b");
                returnValue.Add(3, "c");
                return returnValue;
            }        public Dictionary<string,string> GetLinkedData(string value)
            {
                var intValue = int.Parse(value);
                var returnValue = new Dictionary<string, string>();
                returnValue.Add(value, value);
                returnValue.Add((intValue + 1).ToString(), (intValue + 1).ToString());
                return returnValue;
            }        public Dictionary<int, int> GetLinkedData(int value)
            {
                var returnValue = new Dictionary<int, int>();
                returnValue.Add(value + 1, value + 1);
                return returnValue;
            }
        }
    }
      

  2.   

    这里演示了两种调用 一种是三级联动 一种是在数据绑定控件Repeater里面的联动 先是前台代码  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %><%@ Register Assembly="WebApplication1" Namespace="WebApplication1" TagPrefix="cc1" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>无标题页</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <cc1:LinkedDropDownList ID="LinkedDropDownList1" runat="server" NextDropDownListID="LinkedDropDownList2">
        </cc1:LinkedDropDownList>
        <cc1:LinkedDropDownList ID="LinkedDropDownList2" runat="server" NextDropDownListID="NextDropDownList2">
        </cc1:LinkedDropDownList>
        <asp:DropDownList ID="NextDropDownList2" runat="server">
        </asp:DropDownList>
        <asp:Repeater ID="RPTTest" runat="server">
            <HeaderTemplate>
            </HeaderTemplate>
            <ItemTemplate>
                <cc1:LinkedDropDownList ID="TestLinkedInRepeater" runat="server" NextDropDownListID="DDLNext"
                    OnBindData="LinkedDropDownList1_BindData" OnBindLinkedData="LinkedDropDownList1_BindLinkedData">
                </cc1:LinkedDropDownList>
                <asp:DropDownList ID="DDLNext" runat="server">
                </asp:DropDownList>
            </ItemTemplate>
            <FooterTemplate>
            </FooterTemplate>
        </asp:Repeater>
        </form>
    </body>
    </html>后台代码using System;
    using System.Collections;
    using System.Configuration;
    using System.Data;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Linq;
    using System.Collections.Generic;namespace WebApplication1
    {
        public partial class _Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                //所有绑定事件最后都是用的同一套代码
                LinkedDropDownList1.BindData += new EventHandler(LinkedDropDownList1_BindData);
                LinkedDropDownList1.BindLinkedData += new Action<object, DropDownListIndexChangeEventArg>(LinkedDropDownList1_BindLinkedData);
                LinkedDropDownList2.BindLinkedData += new Action<object, DropDownListIndexChangeEventArg>(LinkedDropDownList2_BindLinkedData);//对于三级绑定 只需要写绑定子菜单的事件就可以
                if(!IsPostBack)//给Repeater一个数据源
                {
                    var rptDataSource = new List<string>() { "0", "0", "0" };
                    RPTTest.DataSource = rptDataSource;
                    RPTTest.DataBind();
                }
            }
            //所以绑定只需要考虑数据获取和绑定即可 不需要考虑IsPostBack,FindControl等问题
            protected void LinkedDropDownList1_BindLinkedData(object arg1, DropDownListIndexChangeEventArg arg2)
            {
                var mock = new MockData();
                var dataSource = mock.GetLinkedData(arg2.SelectedValue);
                arg2.NextDropDownList.DataSource = dataSource;
                arg2.NextDropDownList.DataTextField = "Value";
                arg2.NextDropDownList.DataValueField = "Key";
                arg2.NextDropDownList.DataBind();
            }        protected void LinkedDropDownList1_BindData(object sender, EventArgs e)
            {
                var mock = new MockData();
                var ddl = sender as DropDownList;
                ddl.DataSource = mock.GetRootData();
                ddl.DataTextField = "Value";
                ddl.DataValueField = "Key";
                ddl.DataBind();
            }        void LinkedDropDownList2_BindLinkedData(object arg1, DropDownListIndexChangeEventArg arg2)
            {
                var mock = new MockData();
                var dataSource = mock.GetLinkedData(int.Parse(arg2.SelectedValue));
                arg2.NextDropDownList.DataSource = dataSource;
                arg2.NextDropDownList.DataTextField = "Value";
                arg2.NextDropDownList.DataValueField = "Key";
                arg2.NextDropDownList.DataBind();
            }    }
    }
      

  3.   

    恩 不过无刷新的写AJAX太麻烦了~
      

  4.   

    我觉得无刷新用jq+ajax还是挺快的
      

  5.   

    不用这么麻烦吧?
    代码太多了
    ajax其实挺简单的。
      

  6.   

    顶, 多谢分享。ajax还是比较简单的,楼主在尝试开源一个。哈哈
      

  7.   

    还是有点复杂,希望楼主改的再简单点...现在只用mvc3+jquery
      

  8.   

    我也觉得,LZ可以用jquery+ajax+ashx+(xml或者sqlserver)来写,很方便的联动
      

  9.   

    thank you for open code.
      

  10.   

    楼主,建议你设置个属性,IsAjax,如果是true的话,那么你服务端输出一些资源文件(js)之类的,然后使用ajax来做级联效果,如果是false的话,就默认是postback提交
      

  11.   

    ajax化考虑到客户端的数据格式无法预知 没法定义一个比较通用的接口~
      

  12.   

    楼主你想多了。别人在使用你的服务器控件的时候,一样的设置数据源来绑定,只是你在客户端表现形式,以及回发方法不一样而已,跟客户端数据格式没关系。我以前做过一个服务器控件就是这样的,一种ajax,一种postback