我正在将一个LinkButton控件动态添加到PlaceHolder中。如果我在每个OnInit()上添加一个新的LinkButton实例,那么此LinkButton的OnClick处理程序就可以工作。
但是,如果我将LinkButton的实例存储在会话中,然后将其添加到PlaceHolder的控件集合中,则LinkButton.OnClick将无法触发。
有没有办法在给定方案中重用我在会话中存储的控件?每次重新创建它们都不是一种选择。
正如旁注 - 它是1.1中的继承应用程序,我刚刚迁移到3.5。 “破碎”的方法似乎适用于1.1。
感谢所有答案。
public static void Clicked(object sender, EventArgs e) {
Debugger.Break();
}
protected override void OnPreInit(EventArgs e) {
base.OnPreInit(e);
InitLinkButton();
}
private void InitLinkButton() {
var lb = new LinkButton();
plOne.Controls.Add(lb);
lb.ID = "lb";
lb.Text = "I will work.";
lb.Click += Clicked;
plOne.Controls.Add(lb);
LinkButton lb2 = null;
if (Session["lb2"] == null) {
lb2 = new LinkButton();
lb2.ID = "lb2";
lb2.Text = "I won't work.";
lb2.Click += Clicked;
Session["lb2"] = lb2;
} else {
lb2 = (LinkButton)Session["lb2"];
}
plOne.Controls.Add(lb2);
}
答案 0 :(得分:10)
一些事情:
1)永远不要将WebControl的实例存储到Session。每个WebControl都有一个对象的引用 - 当然它引用了每一个其他的WebControl。只要将WebControl存储到Session中,就基本上存储整个页面及其包含的所有内容。你正在通往内存泄漏城市的高速公路上。
2)每次回发都会重新创建每个控件。我想你可能会认为每次重新创建你的LinkButtons都很慢,但事实并非如此。
3)为什么不在回发选项上重新创建动态控件?这就是你应该用动态控件做的事情。整个想法是您将页面设置为与原来相同,以便ViewState可以根据其ID自动连接到您的控件。如果您尝试在Init()之后的任何位置动态地向页面添加控件,您将无法使用ViewState来处理控件数据,并且必须实现自己的机制。
我的建议是在Init()中重新创建动态控件 - 这是最好的做法。
答案 1 :(得分:3)
要回答您的问题如何让OnClick正常工作,您需要将事件连接到方法;
lb2.Click += new EventHandler(Clicked);
我只是看不到你在init上重新创建控件的问题,不要过于复杂化!关于你在会话中存储的内容已经足够了,所以我不会发布另一个回答这个问题的答案。
答案 2 :(得分:1)
你还应该查看dynamic controls placeholder,这将有助于减少管理动态控件的猴子工作
答案 3 :(得分:1)
将LinkButton存储在会话中真是个糟糕的主意。我甚至无法想象可能导致的问题。至少,LinkButton有一个引用(通过Clicked处理程序)到页面 - 它实际上不应该存在(页面已被渲染并发送到客户端)。但是,引用会使它保持活着,因此它不会被GC控制。
话虽如此,可能你需要重新连接Clicked处理程序:
if (Session["lb2"] == null) {
/* ... */
} else {
lb2 = (LinkButton)Session["lb2"];
lb2.Click += Clicked;
}
由于LinkButton.Click事件连接到Page类的另一个实例(之前使用过的那个),因此它的触发将没有可见效果(因为该页面已经呈现)。当然,就像我上面所说的那样,这只是一种疯狂 - 所以它并不像我测试过的那样。
如果您确实使用了这个,那么您还应该取消订阅Page_PreRender或其他东西以避免GC问题。
再次创建控件是正常的做法 - 对于其他人来说这是一个可行的选择,所以你可能会过度思考其中的复杂情况。