最近碰到这样一个问题,可以描述为:
我要在页面上找到指定的DropDownList,并在该DropDownList的前面加入一个动态创建的RequiredFieldValidator
之所以要加在前面是可以使errormessage出现在控件的上方
DropDownList 的 Item不是在aspx中用asp:ListItem写死,而是通过DropDownList.Items.Insert或者DataBind在后台添加
(至于如何指定DropDownList,用的是Attribute,在这里就不多说了)
Page_Load()中给DropDownList添加项的代码:
ddl1.Items.Insert(0,new ListItem(“”, “”));
ddl1.Items.Insert(1,new ListItem(“1”, “1”));
ddl1.Items.Insert(2,new ListItem(“2”, “2”));
Page_Load()中插入动态控件的代码:
targetControl = “ddl1”; // targetControl, the id of the target dropdownlist
errorMessage = “Must choose one.”;
RequiredFieldValidator rfv = new RequiredFieldValidator();
rfv.ID = targetControl + “RequiredFieldValidator”;
rfv.ControlToValidate = targetControl;
rfv.ErrorMessage = errorMessage;
rfv.Display = ValidatorDisplay.Dynamic;
rfv.EnableViewState = false;
controlToValidate = FindControl(targetControl);
container = controlToValidate.Parent;
index = container.Controls.IndexOf(controlToValidate);
container.Controls.AddAt(index,rfv);
错误是:无论如何选择,DropDownList提交上来的值始终是空
研究发现,动态绑定的DropDownList在PostBack后是通过ViewState取值的,而只要动态插入的控件的位置在DropDownList之前,即使我把动态控件的EnableViewState设为false,PostBack后就会出现”Failed to load viewstate”或者控件从viewstate中取到的值为空的错误。
我的解决方法是:
1.用Controls.Add把动态控件插到DropDownList之后,也就是Validator的index比DropDownList大,就不会影响DropDownList从viewstate取值
2.如果一定要放在前面,可以把上面两段代码的任意一段放到OnInit中
对此我的理解是:
1.页面的ViewState是在Page_Load以前生成,所以Page_Load中动态加入的控件不改变当前ViewState,但改变了当前页控件的顺序,所以在PostBack后读取ViewState到对应的控件出错。
2.动态绑定DropDownList的代码放在Page_Load中,提交后页面从ViewState中取得保存的值,如果页面禁用ViewState就只好放到OnInit中,每次刷新后重新Init。