|
|
Posted on 2005-07-11 14:34 冰戈 阅读(5584) 评论(39) 编辑 收藏 所属分类: 技术随笔
《[分享]新封装的一个实现无刷新连动下拉列表类 》的改进版本
变化比较大: 1.改写方法的实现,降低函数的耦合度; 2.解决了上个post中提到的“注册多对下拉列表时就会产生紊乱”的问题; 3.暴露一个方法用于实现一拖n,多级联动问题,使用方法见测试代码;
一般情况下基本够用
下面是源码,欢迎拍砖 NoRefreshJointDDL2.cs
using System;
using System.Data;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace NoRefreshJointDDL
  {
 /**//// <summary>
///
/// </summary>
public class NoRefreshJointDDL2:System.Web.UI.Page
 {
 成员变量#region 成员变量
private string CilentScript;
private bool IsWrited = false;
#endregion
public NoRefreshJointDDL2()
 {
CilentScript = @"<script language=""javascript""> {0} {1} </script>";
CilentScript = String.Format(CilentScript,"RegisterScriptoylb",GetFunctionCilentScript());
}
 /**//// <summary>
/// 设置联动关系,通过暴露此方法来达到多级联动的目的,注意此处只能用于已注册的DropDownList
/// </summary>
/// <param name="driver">驱动方</param>
/// <param name="drivener">从动方</param>
public void SetDDLsRelation(DropDownList driver,DropDownList drivener)
 {
string ddlDriverID = driver.ID.ToString().Trim();
string ddlDrivenerID = drivener.ID.ToString().Trim();
driver.Attributes["onchange"] = "javascript:changedownlist(document.Form1," + ddlDriverID + ",Array"+ddlDriverID+"," + ddlDrivenerID + ",Array"+ddlDrivenerID+");";
}
 /**//// <summary>
/// 注册需联动的下拉列表
/// </summary>
/// <param name="driver">驱动方</param>
/// <param name="driverRelation">驱动方关系列</param>
/// <param name="drivener">从动方</param>
/// <param name="drivenerRelation">从动方关系列</param>
public void RegisterDropDownList(DropDownList driver,string driverRelation,DropDownList drivener,string drivenerRelation)
 {
string strRegisterScript = GetInitArrayScript(driver,driverRelation);
strRegisterScript += GetInitArrayScript(drivener,drivenerRelation);
//这里使用“RegisterScriptoylb”继续占位,留予下次注册下拉列表,最后注册脚本时将清除
CilentScript = CilentScript.Replace("RegisterScriptoylb","RegisterScriptoylb "+strRegisterScript);
SetDDLsRelation(driver,drivener);
}
 /**//// <summary>
/// 注册需联动的下拉列表
/// </summary>
/// <param name="driver">驱动方</param>
/// <param name="driverRelation">驱动方关系列</param>
/// <param name="drivener">从动方</param>
/// <param name="drivenerRelation">从动方关系列</param>
/// <param name="iswrite">是否直接写入客户端</param>
public void RegisterDropDownList(DropDownList driver,string driverRelation,DropDownList drivener,string drivenerRelation,bool iswrite)
 {
RegisterDropDownList(driver,driverRelation,drivener,drivenerRelation);
if (iswrite)
 {
WriteScriptToCilent();
IsWrited = true;
}
}
//获取初始化数组脚本
private string GetInitArrayScript(DropDownList ddl,string driverRelation)
 {
//驱动部分
string strValueField = ddl.DataValueField; //编码列
string strTextField = ddl.DataTextField; //显示列
string strRelation = driverRelation; //关系列
//数据源
DataTable dtSource = (DataTable)(ddl.DataSource);
//组成变量
string ddlID = ddl.ID.ToString().Trim();
string strCount = "count"+ddlID;
string strArray = "Array"+ddlID;
string strRegisterScript = @"
var {0} = 0;
{1} = new Array();";
strRegisterScript = String.Format(strRegisterScript,strCount,strArray);
//初始化数组值
DataRow drDriver = null;
for(int i = 0;i <dtSource.Rows.Count ;i++)
 {
drDriver = dtSource.Rows[i];
 strRegisterScript += String.Format(strArray+"["+strCount+"++] = new Array(\" {0}\",\" {1}\",\" {2}\");\n", drDriver[strValueField].ToString(),drDriver[strTextField].ToString(), drDriver[strRelation].ToString());
}
return strRegisterScript;
}
//根据驱动方选择的项,初始化从动方数据
private void InitDrivener(DropDownList driver,string driverRelation,DropDownList drivener,string drivenerRelation)
 {
//取得数据源
DataTable dtDriver = (DataTable)(driver.DataSource);
DataTable dtDrivener = (DataTable)(drivener.DataSource);
//获取选定值,并过滤从动下拉列表的数据
int iIndex = GetSelectRowID(driver);
DataRow drFilter = dtDriver.Rows[iIndex];
string strRelate = drFilter[driverRelation].ToString().Trim();
DataView dv = new DataView(dtDrivener);
dv.RowFilter = driverRelation + "='"+strRelate+"'";
drivener.Items.Clear();
drivener.DataSource = dv;
drivener.DataTextField = drivener.DataValueField;;
drivener.DataValueField = drivener.DataTextField;
drivener.DataBind();
}
//得到下拉列表选定值所在数据源行的行号
private int GetSelectRowID(DropDownList ddl)
 {
string strValueFiled = ddl.DataValueField;
string strSelectValue = ddl.SelectedValue.ToString();
DataView dv = new DataView((DataTable)(ddl.DataSource));
dv.Sort = strValueFiled;
return dv.Find(strSelectValue);
}
//得到事件函数脚本
private string GetFunctionCilentScript()
 {
string strScript = @"
function changedownlist(myfrm,Driver,ArrayDriver,Drivener,ArrayDrivener)
{
var SelectedBigId,i,j,SelectDataType;
for (i= Drivener.options.length-1;i>=0 ;--i)
{
Drivener.options[i] = null;
}
SelectedBigId = Driver.options[Driver.selectedIndex].value;
for (i=0;i<ArrayDriver.length;i++)
{
if (SelectedBigId == ArrayDriver[i][0])
{
SelectDataType = ArrayDriver[i][2];
break;
}
}
j = 0;
for (i=0 ;i< ArrayDrivener.length ;i++)
{
if (SelectDataType == ArrayDrivener[i][2])
{
Drivener.options[j] = new Option(ArrayDrivener[i][1],ArrayDrivener[i][0]);
++j;
}
}
}";
return strScript;
}
 /**//// <summary>
/// 写入脚本
/// </summary>
public void WriteScriptToCilent()
 {
if (IsWrited)
 {
throw new Exception("自定义错误信息:重复写入客户端脚本,注册联动下拉列表失败!");
}
//去掉占位字符串
string strCilentScript = CilentScript.Replace("RegisterScriptoylb","");
//将脚本写入客户端
HttpContext.Current.Response.Write(strCilentScript);
}
}
}
测试代码:
protected System.Web.UI.WebControls.DropDownList ddlDrivener;
protected System.Web.UI.WebControls.DropDownList ddlDriver2;
protected System.Web.UI.WebControls.DropDownList ddlDrivener2;
protected System.Web.UI.WebControls.DropDownList ddlDriver;
private void Page_Load(object sender, System.EventArgs e)
 {
if (!IsPostBack)
 {
DataTable dtType = new DataTable();
dtType.Columns.Add("TypeCode");
dtType.Columns.Add("TypeName");
dtType.Columns.Add("DataType");
DataTable dtValue = new DataTable("MyTable");
dtValue.Columns.Add("ValueCode");
dtValue.Columns.Add("ValueName");
dtValue.Columns.Add("DataType");
DataRow Dr = dtType.NewRow();
Dr["TypeCode"] = "AllMoney";
Dr["TypeName"] = "应发工资";
Dr["DataType"] = "Num";
dtType.Rows.Add(Dr);
DataRow Dr1 = dtType.NewRow();
Dr1["TypeCode"] = "Uid";
Dr1["TypeName"] = "身份证号码";
Dr1["DataType"] = "Char";
dtType.Rows.Add(Dr1);
DataRow Dr2 = dtType.NewRow();
Dr2["TypeCode"] = "Worker";
Dr2["TypeName"] = "行政职务";
Dr2["DataType"] = "Meg";
dtType.Rows.Add(Dr2);
//开始添加第二个表中的内容
DataRow Dr3 = dtValue.NewRow();
Dr3["ValueCode"] = "=";
Dr3["ValueName"] = "等于";
Dr3["DataType"] = "Num";
dtValue.Rows.Add(Dr3);
DataRow Dr4 = dtValue.NewRow();
Dr4["ValueCode"] = "<>";
Dr4["ValueName"] = "不等于";
Dr4["DataType"] = "Char";
dtValue.Rows.Add(Dr4);
DataRow Dr5 = dtValue.NewRow();
Dr5["ValueCode"] = "like";
Dr5["ValueName"] = "相似";
Dr5["DataType"] = "Char";
dtValue.Rows.Add(Dr5);
DataRow Dr6 = dtValue.NewRow();
Dr6["ValueCode"] = ">";
Dr6["ValueName"] = "大于";
Dr6["DataType"] = "Num";
dtValue.Rows.Add(Dr6);
DataRow Dr7 = dtValue.NewRow();
Dr7["ValueCode"] = "=";
Dr7["ValueName"] = "否";
Dr7["DataType"] = "Meg";
dtValue.Rows.Add(Dr7);
DataRow Dr8 = dtValue.NewRow();
Dr8["ValueCode"] = "=";
Dr8["ValueName"] = "是";
Dr8["DataType"] = "Meg";
dtValue.Rows.Add(Dr8);
ddlDriver.DataSource = dtType;
ddlDriver.DataTextField = "TypeName";
ddlDriver.DataValueField = "TypeCode";
ddlDriver.DataBind();
ddlDriver.SelectedIndex = 2;
ddlDrivener.DataSource = dtValue;
ddlDrivener.DataTextField ="ValueName";
ddlDrivener.DataValueField = "ValueCode";
ddlDrivener.DataBind();
ddlDriver2.DataSource = dtType;
ddlDriver2.DataTextField = "TypeName";
ddlDriver2.DataValueField = "TypeCode";
ddlDriver2.DataBind();
ddlDriver2.SelectedIndex = 1;
ddlDrivener2.DataSource = dtValue;
ddlDrivener2.DataTextField ="ValueName";
ddlDrivener2.DataValueField = "ValueCode";
ddlDrivener2.DataBind();
NoRefreshJointDDL2 uc = new NoRefreshJointDDL2();
uc.RegisterDropDownList(ddlDriver,"DataType",ddlDrivener,"DataType");
uc.RegisterDropDownList(ddlDriver2,"DataType",ddlDrivener2,"DataType",true);
//--------------------下面设置可出现一拖二,多级连动效果,测试时可逐个设置
//设置出现一拖二
uc.SetDDLsRelation(ddlDriver,ddlDrivener2);
// //设置出现多级连动
// uc.SetDDLsRelation(ddlDriver,ddlDriver2);
} 源码下载: NoRefreshJointDDL2.0.rar
Feedback
@kkding
你觉得有必要吗?不是什么都要封成控件吧?
倒是想过封成控件,但是感觉还没这种好用,目前做的页面全是动态生成,使用封装的控件反而不方便
你这种没意思,或许我的思路你不知道。
用集合呗。parent就指定了,只有一个,child就有多个。呵呵。
没有多大技术含量。
献丑了。
终于等到了....看看是不是我想要的多级联动....1拖n...怎么觉得和想像的不一样...呵呵
看看去.....
@kkding
这样吧,你花点工夫封个出来看看,大家学习学习,怎么样?
@补丁
说说你的需要吧,也许能实现,我这边基本能满足需求了,就没想花工夫去琢磨了,如果你有特殊的需要,我尽量帮你改个!
我觉得用javascript和xml来做最好,提供固定格式数据就可以了,n级都可以实现.
我的需求就是可以无限级绑定数据显示多级联动的菜单
如选择
中国--山东--淄博--张店
或者
1983年--3月--21日
我想这样的要求还是不少的^^
我的博客上有,不过一直没有改,当时也是匆匆写的。后面发现一个很大的漏洞,就是不该用到viewstate。现在很少有机会做这个,所以一直没有重写。自己下了改改吧。很简单的。
@补丁
其实我的本意是把这样的东西封在一个类中,免得到每个页面去写或每个页面都调js脚本,而且还难调试;而且你说的那个要求基本可以实现了啊
连动其实很容易实现,关键是有没有这两个功能
1、可以设置初始值
2、可以无限级(至少也是4级)
@ziyang
现在这两个功能基本都能实现了,只不过使用起来会有一点局限性,比如数据源要用datatable,倒是可以改造
好呀,这个我正想要,发个源码过来好吗?
pangandyou@163.com
有点不爽就是继承的是System.Web.UI.Page。
现在还有问题吧。
我在你的DEMO上加个BUTTOM,然后试一下联动,然后再按一下
按钮,联动控件就出错了。
当POSTBACK以后,ArrayddlDriver就没有了。所以出错。
@neuhawk
的确有这个问题,我抓紧改一下,谢谢
这个联动很好用,而且很合理
但是存在一个问题,在我的应用中,当这个网页被刷新之后,就会导致无法联动了,不知道能怎么样解决
如果想获得我写的DEMO的话,可以与我联系
我的Email:cnming@163.com
谢谢
您这个“无刷新连动下拉列表”页面回传就会出现问题的
现在还有问题吧。 我在你的DEMO上加个BUTTOM,然后试一下联动,然后再按一下 按钮,联动控件就出错了。
|