chiname

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在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 阅读(4147) 评论(10)  编辑 收藏 收藏至365Key

Feedback

# re: Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项 2005-05-12 09:09 jlzhou
好文章,谢谢!已收藏!
  

# 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的代码
private void Page_Load(object sender, System.EventArgs e)
        
{
            
// 在此处放置用户代码以初始化页面
            WebUserControl11.InitCtl();

            WebUserControl1 ctl 
= (WebUserControl1)LoadControl("WebUserControl1.ascx");
            
if (!IsPostBack)
            
{
                ctl.InitCtl();
            }

            
this.Form1.Controls.Add(ctl);

            WebUserControl1 ctl2 
= (WebUserControl1)LoadControl("WebUserControl1.ascx");
            
this.Form1.Controls.Add(ctl2);
            
if (!IsPostBack)
            
{
                ctl2.InitCtl();
            }

        }

web程序运行后,你认为ctlpost事件有问题,即中间的那个usercontrol出现问题。
即: 
post的时候无法触发事件。
安照你的代码,的确出现那样的问题。
 
不过我个人认为那是代码不合理造成的。
比如:
4/2=2这个是没有问题的,但是非要用4/0,肯定要出错。(可能说的有点严重,呵呵)
其实,上面的代码只注释一句就保证让那个usercontrol的事件在post的时候触发。
看代码
private void Page_Load(object sender, System.EventArgs e)
        
{
            
// 在此处放置用户代码以初始化页面
            WebUserControl11.InitCtl();

            WebUserControl1 ctl 
= (WebUserControl1)LoadControl("WebUserControl1.ascx");
            
//if (!IsPostBack)  //就是这一句握!!
            {
                ctl.InitCtl();
            }

            
this.Form1.Controls.Add(ctl);

            WebUserControl1 ctl2 
= (WebUserControl1)LoadControl("WebUserControl1.ascx");
            
this.Form1.Controls.Add(ctl2);
            
if (!IsPostBack)
            
{
                ctl2.InitCtl();
            }

        }

究其原因是第一次加载页面的时候,运行了.InitCtl(),而postback的时候页面又没有运行了.InitCtl(),
当然就没有初始化下拉数据
public void InitCtl()
        
{
            TextBox1.Text 
= "inited by InitCtl";
            DropDownList1.Items.Add(
"item1");
            DropDownList1.Items.Add(
"item2");
            DropDownList1.Items.Add(
"item3");
        }

你会问我,为什么加载ctl2就不会出现这样的问题呢?
WebUserControl1 ctl2 = (WebUserControl1)LoadControl("WebUserControl1.ascx");
            
this.Form1.Controls.Add(ctl2);
            
if (!IsPostBack)
            
{
                ctl2.InitCtl();
            }

也就是说为什么ctl2能够保持状态(所谓状态,指两样,值和事件),在第二次postback的时候能够触发事件呢?

因为ctl2也有子控件,它的子控件有
一个textbox,一个dropdownlist,一个button
而状态保存是靠什么保存的?viewstate,一个子控件如何从viewstate恢复?靠它自己的UniqueID从viewstate中恢复。
一个子控件还没有UniqueID就操作其控件这个本身就是不合理的。
所以,这也是ctl无法在post的触发事件,而ctl1确可以的真实原因

myText = new TextBox();
//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的控件内部,而两者的加载顺序相冲突。

当然以上只是猜测,要详细确定原因,还是必须针对具体的代码!
posted on 2005-11-29 09:42  把我的欢乐带给你  阅读(1924)  评论(0编辑  收藏  举报