如何处理Asp.Net中页面运行时动态载入的UserControl内元素事件?
在Asp.Net页面的开发过程中,我们肯定经常会用到自定义的UserControl来复用部分页面元素,我们有两种使用UserControl的方式
1、在设计时往页面里添加需要的UserControl(最常用的就是从SolutionExplorer拖ascx到设计页面)
此种情况下,如果将UserControl放置在runat=server的html标签中,将可能导致UserControl内的元素事件处理不能正确执行。
例如:我们有时用一个div作为边框包含了需要的UserControl,而出于在运行时控制div的显示效果(比如运行时隐藏/显示这个div)的目的,可能将该div设为runat=server,此时,往往包含于div的UserControl内的元素事件触发可能被忽略,UserControl内的事件处理函数往往是不能正常运行的。
2、在运行时使用LoadControl函数动态载入UserControl,再Add到指定的位置
在动态载入的情况下,除了以上的问题同样存在之外,还会带来相应的初始化时的问题,这时,为了保证你的UserControl以你希望的语义正常运行,必须注意两点:
1)如果在LoadControl该UserControl的同时需要调用UserControl的某个初始化函数的话,该初始化函数的调用必须在将该ctlAdd到指定的页面某元素的Controls中之后进行,即必须按如下顺序:
...
MyCtl ctl = (MyCtl)LoadControl("path");
this.someCtl.Controls.Add(ctl);
ctl.InitMethod();//本语句必须在上一条之后,否则ctl中的事件导致PostBack后,需要保持的textbox、listbox等的数据将丢失,导致各种错误
2)如果在LoadControl该UserControl的同时需要调用UserControl的某个初始化函数的话,该函数体内要注意对不需每次执行的代码放入if (!IsPostBack){}语句块中,否则会导致每次提交时被重复运行,这和Page_Load中的处理方法其实是一样的,但往往容易被忽略。
对于动态载入的UserControl还要保证每次PostBack时都重新Load所有的UserControl(但PostBack时可以不初始化UserControl内的元素的初始值),否则事件处理函数会找不到对应的触发源,保存于ViewState的数据也将因找不到对应元素而保持不了。
posted on 2005-05-11 23:40 Teddy's Knowledge Base 阅读(6846) 评论(13) 编辑收藏 引用 收藏至365Key
2005-05-12 09:09 jlzhou本文地址:http://www.45fan.com/dnjc/71531.html
评论
好文章,谢谢!已收藏!回复
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-05-12 15:41 ASTAR Coming Now
======================
我们有时用一个div作为边框包含了需要的UserControl,而出于在运行时控制div的显示效果(比如运行时隐藏/显示这个div)的目的,可能将该div设为runat=server,此时,往往包含于div的UserControl内的元素事件触发可能被忽略,UserControl内的事件处理函数往往是不能正常运行的。
======================
webcontrols中的panel就是html的div服务器控件,而加入panel的usercontrol,不会出现事件被忽略的问题。
usercontrol的事件是否能被正确的触发,是取决于申明事件的位置是否正确。
通常都应该在pageload事件中申明。
=================================
MyCtl ctl = (MyCtl)LoadControl("path");
this.someCtl.Controls.Add(ctl);
ctl.InitMethod();//本语句必须在上一条之后,否则ctl中的事件导致PostBack后,需要保持的textbox、listbox等的数据将丢失,导致各种错误
=================================
把一个usercontrol加入到另外的contro控件里面,可以在
this.someCtl.Controls.Add(ctl); 之前调用该control的方法
也可以在之后调用此控件的方面,这没有什么分别。
有可能出错的是,该控件调用的方法有问题。
有问题,请给出代码大家研讨一下
回复
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-05-12 16:27 Teddy's Knowledge Base
首先我要说明,以上说到的情况都是小弟亲身经历过的,但不排除有其他原因导致的错觉,为了证实我的说法,在身边的电脑又做了个小测试,对于ASTAR Coming Now 不同意的情形一,没有重现出我说的错误,对于第二种情形,千真万确会出错!
请看示例程序:
http://teddy.51.net/test.rar
以上程序中WebForm1.aspx内包含三个WebUserControl1,
第一个是静态放置的,第二个第三个是动态Load的,只是第二个是以:
MyCtl ctl = (MyCtl)LoadControl("path");
ctl.InitMethod();
this.someCtl.Controls.Add(ctl);
顺序添加
第三个是以:
MyCtl ctl = (MyCtl)LoadControl("path");
this.someCtl.Controls.Add(ctl);
ctl.InitMethod();
顺序添加
请点击按钮,看执行效果!
回复
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-05-13 15:52 ASTAR Coming Now
我已经下载了你提供的代码,并作了相关实验了。
你发现的问题很好,这样讨论一下,有助于我们了解aspnet的模型。
这是你加载usercontrol的代码
{
//在此处放置用户代码以初始化页面
WebUserControl11.InitCtl();
WebUserControl1ctl=(WebUserControl1)LoadControl("WebUserControl1.ascx");
if(!IsPostBack)
{
ctl.InitCtl();
}
this.Form1.Controls.Add(ctl);
WebUserControl1ctl2=(WebUserControl1)LoadControl("WebUserControl1.ascx");
this.Form1.Controls.Add(ctl2);
if(!IsPostBack)
{
ctl2.InitCtl();
}
}
web程序运行后,你认为ctlpost事件有问题,即中间的那个usercontrol出现问题。
比如:
4/2=2这个是没有问题的,但是非要用4/0,肯定要出错。(可能说的有点严重,呵呵)
其实,上面的代码只注释一句就保证让那个usercontrol的事件在post的时候触发。
看代码
{
//在此处放置用户代码以初始化页面
WebUserControl11.InitCtl();
WebUserControl1ctl=(WebUserControl1)LoadControl("WebUserControl1.ascx");
//if(!IsPostBack) //就是这一句握!!
{
ctl.InitCtl();
}
this.Form1.Controls.Add(ctl);
WebUserControl1ctl2=(WebUserControl1)LoadControl("WebUserControl1.ascx");
this.Form1.Controls.Add(ctl2);
if(!IsPostBack)
{
ctl2.InitCtl();
}
}
究其原因是第一次加载页面的时候,运行了.InitCtl(),而postback的时候页面又没有运行了.InitCtl(),
当然就没有初始化下拉数据
{
TextBox1.Text="initedbyInitCtl";
DropDownList1.Items.Add("item1");
DropDownList1.Items.Add("item2");
DropDownList1.Items.Add("item3");
}
你会问我,为什么加载ctl2就不会出现这样的问题呢?
this.Form1.Controls.Add(ctl2);
if(!IsPostBack)
{
ctl2.InitCtl();
}
也就是说为什么ctl2能够保持状态(所谓状态,指两样,值和事件),在第二次postback的时候能够触发事件呢?
因为ctl2也有子控件,它的子控件有
一个textbox,一个dropdownlist,一个button
而状态保存是靠什么保存的?viewstate,一个子控件如何从viewstate恢复?靠它自己的UniqueID从viewstate中恢复。
//myText.UniqueID为null
this.Controls.Clear();
this.Controls.Add(myText);
//此时myText.UniqueID不为null
所以,
在this.someCtl.Controls.Add(ctl); 之前调用该control的方法或者在之后调用控件方法都可以,
不过不要加If(!ispostback)的判断,
如果一定要加postback的判断,则需要在子控件的UniqueID生成之后,再调用控件的方法。
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-05-13 15:52 ASTAR Coming Now
mark回复
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-05-13 16:01 ASTAR Coming Now
修正一些东西,
实际上
ctl和ctrl1的button事件都是被触发的。
区别是
而只是里面的子控件,dropdownlist的子项没有保存或保存。回复
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-05-13 16:34 Teddy's Knowledge Base
确实很有可能是UniqueID的问题,曾经多次遇到此类问题是在我需要嵌套的动态Load页面控件时,嵌套控件内的元素的事件确实是可以触发并PostBack,但是,常常不能正确的定位到触发源,甚至,触发源被张冠李戴,不知是否也是因为UniqueID的问题,UniqueID应该是系统生成且只读的吧,这样的话理论上是不是不应该有重复的UniqueID发生呢?会不会有服务器端控件在最终执行时未被指定UniqueID的情况出现,从而导致被触发事件找不到触发源呢?有待进一步实验研究~~回复
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-06-11 16:07 s
博客堂上思归他们曾经讨论过这个问题。可以去参考一下。回复
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-08-11 20:44 天浩
我做了一个用户控件,控件里有个dropdownlist,我让它selectindexchanged时,就执行一段代码.但是这段代码执行了3次就不执行了.我查了好久,不知道原因,还望各位高手赐教啊!回复
#re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-08-11 20:58 Teddy's Knowledge Base
@天浩:
你这个情况如果是刚开始执行的,后来突然不执行了的话,一是检查一下dropdownlist.SelectedIndexChanged+=...这句是不是丢失了;
再有就是检查这个dropdownlist是不是处在另一个runat=server的控件内部,而两者的加载顺序相冲突。
当然以上只是猜测,要详细确定原因,还是必须针对具体的代码!回复