~~蜉蝣的梦

记录我的技术成长历程……
  首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

动态控件,编码生成过程,神秘的Container变量

Posted on 2007-05-25 17:56  右手边  阅读(682)  评论(0)    收藏  举报

这几天有几人在问类似的问题,“动态加载控件,为什么控件事件不能触发了?”,问题是他们都是在

if (!IsPostBack)
{
        //动态产生或装载控件
        //也许需要连接控件事件处理函数
       //加到父控件的Controls
}

里生成或装载了动态控件。当控件在客户端触发,postback到服务器端时,IsPostBack==true,这些控件没有被重新生成,怎么能 触发事件?所以答案是,当你需要动态生成或装载控件时,应该在if (!IsPostBack)之外做。我问为什么想在if (!IsPostBack)之内做呢?回答是想只生成一次,跟在ASPX页面里一样

<form id="form1" runat=server>
<asp:Button id="Button1" runat="server" Text="Button1" OnClick="Button_Click"/>

#%&%#&%^#&,你怎么会认为这个控件只生成一次呢?这些玩意也不是魔术,想生成一个Button对象,你需要用

Button btn = new Button();

需要触发它的Click事件,你需要用

btn.Click += new EventHandler(YourHandler);

即使象包含

<asp:Button id="Button1" runat="server" Text="Button1" OnClick="Button_Click"/>

的页面,它也是被转化成C#或VB文件,编译成assembly,然后再被执行的啊

不信?加一个页面,TestControls.aspx:

<%@ Page Debug="true" %>
<%@ Import Namespace="System.Data"%>
<%@ Import Namespace="System.Data.SqlClient"%>

<form id="form1" runat=server>
<asp:Button id="Button1" runat="server" Text="Button1" OnClick="Button_Click"/>
<asp:DataGrid id="DataGrid1" runat="server" AutoGenerateColumns="false" GridLines="Both">
<Columns>
 <asp:TemplateColumn HeaderText="Name">
 <ItemTemplate><%# DataBinder.Eval(Container.DataItem,"Name")%></ItemTemplate>
 </asp:TemplateColumn>
</Columns>
</asp:DataGrid>
</form>
<script language="C#" runat="server">
void Button_Click(Object sender, EventArgs e)
{
  Button btn = (Button)sender;
  Response.Write(btn.Text + " is clicked<BR>");
}

void Page_Load(Object sender, EventArgs e)
{
  
 Button btn = new Button();
 btn.ID = "Button2";
 btn.Text = "Button2";
 btn.Click += new EventHandler(Button_Click);
 form1.Controls.Add(btn);
   if (!IsPostBack)
   {
 SqlDataAdapter da = new SqlDataAdapter("select Name=au_fname + ' ' + au_lname from authors", "server=localhost;database=pubs;uid=sa;pwd=;");
 DataTable dt = new DataTable();
 da.Fill(dt);
 DataGrid1.DataSource = dt.DefaultView;
 DataGrid1.DataBind();
   }
 
//}//这是故意的

</script>

把最后一个“}”注释掉,然后在浏览器里向你的服务器调用TestControls.aspx,你将看到编译错误,按 ,你将看到:


参看加亮的编码句子。

去除那个注释,然后请求该页,你在C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files下能找到一个cs文件,内含同样的编码,注意要加

<%@ Page Debug="true" %>

是否曾经疑惑过DataGrid模板里的Container是什么玩意?哪里也找不到它的定义?看看上面加亮的编码,原来它是个局部变量名!

System.Web.UI.WebControls.DataGridItem Container;

  2004年4月14日 5:19 - (阅读:9685;评论:34)

 

反馈

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-14 13:02 Lostinet
测试一下。

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-14 13:04 f
f

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-14 13:05 f2
f2

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-14 13:27 cc
我有2个问题,希望大侠回答:
1。我做了个比较复杂的服务器控件,所有子控件都是在CreateChildControls中生成的(没有使用Render方法),有很多类似
Button btn = new Button();
btn.ID = "Button2";
btn.Text = "Button2";
btn.Click += new EventHandler(Button_Click);
的代码,也使用了大量的this.FindControl(),使程序执行顺序混乱。而我的同事说我的方法不好,他使用Render方法来生成的子控件,其中用到了大量的HTML串。请问我的思想是不不正确,到底用那个方法好?
2。我的服务器控件的数据是通过一个属性从数据库获得的,加到页面上后,使用者需要可以动态的修改这个属性来使用数据库的不同数据,我是模仿 DataGrid override 了OnDataBinding(),通过DataBind实现,我有的同事说在属性变化时读数据库就行了,是这样吗?

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-14 13:42 Rover
我一直认为用CreateChildControls生成的控件是复合控件,一般是要处理子控件的事件的,可以把子控件的事件冒泡到父控件处理,而用 Render方法生成的控件的控件,一般只需要处理控件本身的事件就可以了,而User Control里包容的控件,一般也不需要处理自控件的事件,还没有掌握控件编程的机理,请大侠指教

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-14 14:03 saucer
cc:

第一个问题,在不清楚你的控件的用途以及没看见编码的情形下,很难做全面的评价。但从基本编程的角度,我偏向你的做法,理由有几个,一,你的方法 相对来说比较好维护,当然你说“用了大量的this.FindControl(),使程序执行顺序混乱”,你也许应该仔细审视自己的编码,尽量把结构弄清 晰;二,hard code HTML不是很好的做法,因为用服务器端控件的话,系统会根据UserAgent设备自动产生相应的客户端编码;三,如果需要处理子控件的事件的话,你的 方法应该比较好

第二个问题,我也喜欢你的做法,编程的原则是loose coupling,separate concerns,一样东西应该把一件事做好,不应该把不相干的事集中在一起做。除非在特殊情形下,把访问数据库的编码写在控件里一般不是好的做法,如果 有一天,你的数据源变成XML文件,你就不需要修改你的控件编码

Rover:
需要具体情形具体分析

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-14 15:00 ghj1976
在 aspx+aspx.cs 结构中,如何看到这些code呢??


# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-14 20:57 PM
说句实话,除了Container,其他不是很明白要说明什么问题?

# 一个问题 2004-4-16 20:38 dawave
关于“动态加载控件,为什么控件事件不能触发了?”的问题,saucer为什么不建议用CreateChildControls的方法呢?

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-18 22:38 goodbaby
我遇到一个问题请问:
我动态的加载了一个用户控件:
Control c1 = LoadControl("AddUser.ascx");
((AddUsee)c1).ID="AU";
MYPanel.Controls.Add(c1);
用户控件里有一个按钮,我双击他为他添加事件(Click)处理程序,我在父窗体里的一个Button的Click里调用上面的程序动态的添加用 户控件但是用户控件的Click没有触发,我认真看了你文章,还有另一位你们这里的Bloger的关于动态控件的文章但我还是没有得到解决办法,希望您帮 帮我。

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-18 23:31 goodbaby
问题解决,谢谢saucer的文章,是我没看仔细。

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-19 10:43 华安
很好,我也遇到这样的问题,已经解决

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-21 20:16 azmore
呵呵,又有新的了解了,好

看saucer的文章总是有进步

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-22 12:56 csr
我有个问题,希望大侠解答
我在用ASP.NET做一个数据录入程序,希望直接在datagrid里面编辑数据,请问应该怎么做才能在点击datagrid的时候弹出一个 dropdownlist,然后选择dropdownlist里面一项后,把dropdownlist的text放到datagrid里面去

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-4-25 0:14 ling
我有一个问题:
我是动态生成的DataGrid,在处理EditCommand时遇到了问题。在页面加载后第一次点Edit后,相应的列变成了TextBox, 但此时在点Update和Cancel按钮却不能触发对应的事件,并且此时再点其他行的Edit按钮,页面也没有任何变化(还是原来行显示 TextBox,而不是后来点击Edit的那行)。
我在Page_Load事件中类似这样:
LoadDataSource(); //读入数据源
myDiv.Controls.Add(MakeGrid()); //动态生成DataGrid,并通过Div加到aspx页面

在Page_Load中并没有用if(!IsPostBack)这样的代码块。
Datagrid的EnableViewState=true.
并在MakeGrid()中有将Edit,Update,Cancel的Handler中添加到委托。

请帮我看看可能哪里出错了好吗?
已经困惑了一整天了。
谢谢大家!

# 回复: 动态控件,编码生成过程,神秘的Container变量 2004-5-15 16:42 hello
深有体会,十分感谢!思归高手!

# re: 动态控件,编码生成过程,神秘的Container变量 2004-9-15 12:38 jimodelang
请教各位,在.cs代码页该怎样写自动生成按钮代码.

我在.cs的代码页的page_Load事件里写
Button btn = new Button();
btn.ID = "Button2";
btn.Text = "Button2";
Form1.Controls.Add(btn);

但页面错误并说 :类型“Button”的控件“Button2”必须放在具有 runat=server 的窗体标记内。

但我的Form1已经定了是runat="server",下面是那页面body的html
<BODY>
<form id="Form1" runat="server">
<asp:button id="Button1" runat="server" text="B1"></asp:button>
</form>
</BODY>


# re: 动态控件,编码生成过程,神秘的Container变量 2004-9-24 10:01 jinanlikai
我在.cs的代码页的page_Load事件里写
Button btn = new Button();
btn.ID = "Button2";
btn.Text = "Button2";
Form1.Controls.Add(btn);

但页面错误并说 :类型“Button”的控件“Button2”必须放在具有 runat=server 的窗体标记内。

但我的Form1已经定了是runat="server",下面是那页面body的html
<BODY>
<form id="Form1" runat="server">
<asp:button id="Button1" runat="server" text="B1"></asp:button>
</form>
</BODY>

============================================
改成这样
============================================
我在.cs的代码页的page_Load事件里写
Button btn = new Button();
btn.ID = "Button2";
btn.Text = "Button2";
//Form1.Controls.Add(btn);
placeholder1.Controls.Add(btn) ;

但页面错误并说 :类型“Button”的控件“Button2”必须放在具有 runat=server 的窗体标记内。

但我的Form1已经定了是runat="server",下面是那页面body的html
<BODY>
<form id="Form1" runat="server">
<asp:button id="Button1" runat="server" text="B1"></asp:button>
<asp:placeholder id="placeholder1" runat="server" />
</form>
</BODY>



# re: 动态控件,编码生成过程,神秘的Container变量 2005-5-31 10:51 新鮮魚排
厲害

# re: 动态控件,编码生成过程,神秘的Container变量 2005-9-23 14:42 Ric
QUOTE: "是否曾经疑惑过DataGrid模板里的Container是什么玩意?哪里也找不到它的定义?看看上面加亮的编码,原来它是个局部变量名!"
其实,最根本的原因不是局部变量,而是ASP.net对每次request都会重新new一个新的page对象进行服务响应,当这个page服务 完成一个request后它就销毁了。 所以你在两次request中根本不可能得到同一个page对象,即使他们是在同一个session的上下文中, 所以page对象中的 IsPostBack属性其实已经是另外一个对象的属性了,这个属性是由IHttpHandler来负责设置的,而IhttpHandler又会由最基本 的Application对象创建。

# re: 动态控件,编码生成过程,神秘的Container变量 2005-11-11 16:47 dr3000
不错

http://www.51team.com

# re: 动态控件,编码生成过程,神秘的Container变量 2005-12-2 10:05 笨笨蜗牛
http://daview.cnblogs.com/archive/2004/08/09/31358.html
http://daview.cnblogs.com/archive/2004/08/09/31360.html

# re: 动态控件,编码生成过程,神秘的Container变量 2006-3-25 15:54 Anson
我以下的代码,再单击加入DataGrid1的DDD时,就不显示DDD is clicked了。是不是UniqueID改变了,事件无法映射。有什么办法可以维持事件映射,我急着实现主从表编辑功能,所以需要高手指定一二。

<%@ Page Debug="true" %>
<%@ Import Namespace="System.Data"%>
<%@ Import Namespace="System.Data.SqlClient"%>
<script language="C#" runat="server">
void Button_Click(Object sender, EventArgs e)
{
Button bt = (Button)sender;
Response.Write(bt.Text + " is clicked<BR>");
if(bt.ID=="Button1")
{
(DataGrid1.Items[0] as TableRow).Cells[0].Controls.Add(DDD);
}
}

void Page_Load(Object sender, EventArgs e)
{
// DDD.Click += new EventHandler(Button_Click);

// if (!IsPostBack)
// {
SqlDataAdapter da = new SqlDataAdapter("select Name=au_fname + ' ' + au_lname from authors", "server=localhost;database=pubs;uid=sa;pwd=123456;");
DataTable dt = new DataTable();
da.Fill(dt);
DataGrid1.DataSource = dt.DefaultView;
DataGrid1.DataBind();
// }
}//这是故意的

</script>
<form id="form1" runat="server">
<asp:Button id="Button1" runat="server" Text="Button1" OnClick="Button_Click" />
<asp:Button id="DDD" runat="server" Text="DDD" OnClick="Button_Click"></asp:Button>
<asp:DataGrid id="DataGrid1" runat="server" AutoGenerateColumns="false" GridLines="Both" EnableViewState="true">
<Columns>
<asp:TemplateColumn HeaderText="Name">
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem,"Name")%>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
</form>


# re: 动态控件,编码生成过程,神秘的Container变量 2006-3-26 22:44 ICEBS
protected void Page_Load(object sender, EventArgs e)
{ RadioButtonList RBL = new RadioButtonList();
RBL.ID = "HD";
RBL.Items.Add("是");
RBL.Items.Add("否");
RBL.Items[0].Value = "Y";
RBL.Items[1].Value = "N";
RBL.SelectedIndexChanged += new EventHandler(RBL_SelectedIndexChanged);
RBL.AutoPostBack = true;
RBL.DataBind();
PlaceHolder1.Controls.Add(RBL);

RadioButtonList TPRBT = (RadioButtonList)PlaceHolder1.FindControl("HD");
Label1.Text = TPRBT.SelectedItem.Text;

}
选中单选框之后,数据总是不能同步刷新,也就是说,我第一次选择是,没反应,再选择否,就出来Y,选择是就出来N,RBL_SelectedIndexChanged 我写就可以,但是我写的程序,要求必须放到peag_load里面,请问有办法解决么?


# re: 动态控件,编码生成过程,神秘的Container变量 2006-3-27 13:16 ICEBS
动态生成RadioButtonList不同步?


protected void Page_Load(object sender, EventArgs e)
{
RBL = new RadioButtonList();
RBL.ID = "HD";
RBL.Items.Add("是");
RBL.Items.Add("否");
RBL.Items[0].Value = "Y";
RBL.Items[1].Value = "N";
RBL.SelectedIndexChanged += new EventHandler(RBL_SelectedIndexChanged);
RBL.AutoPostBack = true;
RBL.DataBind();
PlaceHolder1.Controls.Add(RBL);

RadioButtonList TPRBT = (RadioButtonList)PlaceHolder1.FindControl("HD");
Label1.Text = TPRBT.SelectedValue;

}
生成单选框之后,数据总是不能同步刷新,也就是说,我第一次选择"是",没反应,再选择"否",就出来Y,选择"是"就出来N,
如果我把
RadioButtonList TPRBT = (RadioButtonList)PlaceHolder1.FindControl("HD");
Label1.Text = TPRBT.SelectedValue;
写到
RBL_SelectedIndexChanged
就可以,但是我写的程序,要求必须放到page_load里面,请问有办法解决么?

然后,我把SelectedIndexChanged 改用PreRender 代替,问题解决!
但是同样又产生一个新问题
我要求的效果是,根据动态生成组件选项的不同,再动态生成一个 RadioButtonList
动态生成组件的代码好像必须放在Page_Load,不然就没有ViewState

比如这样
protected void Button2_Click(object sender, EventArgs e)
{
RadioButtonList RBL = new RadioButtonList();
RBL.ID = "HD";
RBL.Items.Add("是");
RBL.Items.Add("否");
RBL.Items[0].Value = "Y";
RBL.Items[1].Value = "N";
RBL.EnableViewState = true;
// RBL.AutoPostBack = true;
RBL.DataBind();
Conl.Controls.Add(RBL);
PlaceHolder1.Controls.Add(Conl);
}
我点Button2按钮生成一个RadioButtonList,然后我选择了一个Items,然后我再点Button2,选中的值自动取消了

又该如何解决??


# re: 动态控件,编码生成过程,神秘的Container变量 2006-3-31 17:29 冰冰
我在.ascx中做了个联动菜单,用a.aspx,第二级菜单可以正确联动。
小小改动成b.aspx后,第二级菜单就不可以联动了。

a.aspx
private void Page_Load(object sender, System.EventArgs e)
{
Control myControl1 = LoadControl("01.ascx");
if (!this.Page.IsPostBack)
{
this.Controls[1].Controls.Add(myControl1);
}
}
--第二级菜单可以正确联动

private void Page_Load(object sender, System.EventArgs e)
{
Control myControl1 = LoadControl( request["id"] + ".ascx");
if (!this.Page.IsPostBack)
{
this.Controls[1].Controls.Add(myControl1);
}
}--第二级菜单就不可以联动了。

老大!救命!

# re: 动态控件,编码生成过程,神秘的Container变量 2006-4-21 10:26 xhp
to jimodelang:
如果在cs中写的话
HtmlForm form1 = (HtmlForm)this.FindControl("Form1");
form1.Controls.add

# ASP.NET的前台数据绑定概要 2006-4-24 13:19 陈安宝
ASP.NET的前台数据绑定概要

# re: 动态控件,编码生成过程,神秘的Container变量 2006-4-29 21:43 assint
我遇到一个问题请问:
我动态的加载了一个用户控件:
Control c1 = LoadControl("AddUser.ascx");
((AddUsee)c1).ID="AU";
MYPanel.Controls.Add(c1);
用户控件里有一个按钮,我双击他为他添加事件(Click)处理程序,我在父窗体里的一个Button的Click里调用上面的程序动态的添加用 户控件但是用户控件的Click没有触发,我认真看了你文章,还有另一位你们这里的Bloger的关于动态控件的文章但我还是没有得到解决办法,希望您帮 帮我。

这个问题我也遇到过,看了文章也没能解决,哪位好心人给解答一下啊!

# re: 动态控件,编码生成过程,神秘的Container变量 2006-5-21 0:13 xiaog
各位大侠,请教一个问题:如何把用VB.NET生成的应用程序生成控件。。。可以随意拖放到任何地方?嵌入到网页中。。。谢谢

# re: 动态控件,编码生成过程,神秘的Container变量 2006-5-25 10:47 zilan
请各位大侠指教:在vb.net2005中,动态控件的click事件该怎样触发?我看到楼上用but.Click += new EventHandler(YourHandler),问题是我的动态控件里压根连click都没有,所以一写控件名.click就报错,请问这种情况下 应该怎样触发click事件呢?附:生成动态控件的代码:
ReDim Preserve Butadd(AddCount)
Butadd(AddCount) = New Button
With Butadd(AddCount)
.Text = "添加"
.BackColor = Color.WhiteSmoke
.ForeColor = Color.Black
'.Location = New System.Drawing.Point(155 + Col * 138, 58 + Row * 22)
.Location = New System.Drawing.Point(160 + Col * 240, 58 + Row * 22)
.Name = "butadd" & AddCount + 1
.Size = New System.Drawing.Size(50, 21)
.TabIndex = AddCount + 10
Me.Panel2.Controls.Add(Butadd(AddCount))
.BringToFront()
End With

# re: 动态控件,编码生成过程,神秘的Container变量 2006-11-17 16:55 lbc
你们好:我是复合控件的入门学习着,现在我有一个问题要请教大家:我写了一个复合控件,控件里有通过 PlaceHolder 加载的 LinkButton控件,我把该控件的click的事件冒泡到顶级处理,问题的所在是,我每次要点击第二次它,它才能触发该click事件,不知道原因 所在,请教有没有人能告诉我这个问题的所在?先谢谢了

# oraoqkgq 2007-1-26 22:47 oraoqkgq
rcupwacu http://jiyuyrcp.com mosbslqr czleytqk [URL=http://taogonph.com]lyvszbce[/URL] <a href="http://irhxcumq.com">mtrsmxax</a>

# 回复: 动态控件,编码生成过程,神秘的Container变量 2007-1-31 10:39 bibts
可否在页面哪里设置POSTBACK=FALSE来解决呢?