Asp.Net 中动态添加的控件
我正在尝试了解 asp.net。 我有一个长期的 php 开发人员背景,但我现在面临着学习 asp.net 的任务,并且我在这方面遇到了一些麻烦。 这很可能是因为我试图迫使框架去做一些它不适合的事情——所以我想学习如何“以正确的方式”做到这一点。 :-)
我的问题是如何在运行时以编程方式向页面添加控件。 据我所知,您需要在 page_init 创建控件,否则它们会在下一次回发时消失。 但很多时候我面临的问题是我不知道在 page_init 中添加哪些控件,因为它依赖于先前回发的值。
一个简单的场景可能是在设计器中添加了下拉控件的表单。 下拉列表设置为 AutoPostBack。 当发生回发时,我需要根据下拉控件中所选的值来渲染一个或多个控件,并且最好让这些控件表现得就像它们是由设计添加的一样(如“回发时,表现得“正确”)。
我在这里走错路了吗?
I'm trying to wrap my head around asp.net. I have a background as a long time php developer, but I'm now facing the task of learning asp.net and I'm having some trouble with it. It might very well be because I'm trying to force the framework into something it is not intended for - so I'd like to learn how to do it "the right way". :-)
My problem is how to add controls to a page programmatically at runtime. As far as I can figure out you need to create the controls at page_init as they otherwise disappears at the next PostBack. But many times I'm facing the problem that I don't know which controls to add in page_init as it is dependent on values from at previous PostBack.
A simple scenario could be a form with a dropdown control added in the designer. The dropdown is set to AutoPostBack. When the PostBack occur I need to render one or more controls denepending on the selected value from the dropdown control and preferably have those controls act as if they had been added by the design (as in "when posted back, behave "properly").
Am I going down the wrong path here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您必须在 OnInit 事件中添加控件,并且视图状态将被保留。 不要使用if(ispostback),因为每次都必须添加控件,事件在回发中!
视图状态的(反)序列化发生在 OnInit 之后和 OnLoad 之前,因此您的视图状态持久性提供程序将看到动态添加的控件(如果它们是在 OnInit 中添加的)。
但在您描述的场景中,可能多视图或简单的隐藏/显示(可见属性)将是更好的解决方案。
这是因为在 OnInit 事件中,当您必须读取下拉列表并添加新控件时,视图状态尚未读取(反序列化),并且您不知道用户选择了什么! (你可以做 request.form() ,但这感觉有点不对)
You must add your control inside OnInit event and viewstate will be preserved. Don't use if(ispostback), because controls must be added every time, event in postback!
(De)Serialization of viewstate happens after OnInit and before OnLoad, so your viewstate persistence provider will see dynamically added controls if they are added in OnInit.
But in scenario you're describing, probably multiview or simple hide/show (visible property) will be better solution.
It's because in OnInit event, when you must read dropdown and add new controls, viewstate isn't read (deserialized) yet and you don't know what did user choose! (you can do request.form(), but that feels kinda wrong)
在与这个问题斗争了一段时间之后,我想出了这些基本规则,这些规则似乎有效,但是 YMMV。
真正了解 ViewState 是必须的-读。
了解动态控件示例展示了一些有关如何使用数据绑定而不是动态控件的技术。
真正了解动态控件 还阐明了可用于避免动态控制的技术。
希望这可以帮助其他遇到同样问题的人。
After having wrestled with this problem for at while I have come up with these groundrules which seems to work, but YMMV.
TRULY Understanding ViewState is a must-read.
Understanding Dynamic Controls By Example shows some techniques on how to use databinding instead of dynamic controls.
TRULY Understanding Dynamic Controls also clarifies techniques which can be used to avoid dynamic controls.
Hope this helps others with same problems.
如果您确实需要使用动态控件,则应执行以下操作:
重新添加您不需要的“陈旧”控件并将在 OnLoad 时删除似乎有点奇怪,但 Asp.Net 的设计并没有真正考虑到动态控件创建。 如果在视图状态加载期间没有保留完全相同的控件层次结构,则各种难以发现的错误就会开始潜伏在页面中,因为旧控件的状态会加载到新添加的控件中。
阅读 Asp.Net 页面生命周期,特别是视图状态如何工作,你就会变得清楚。
编辑:这是一篇非常好的文章,介绍了视图状态的行为方式以及处理动态控件时应考虑的事项:<链接>
If you truly need to use dynamic controls, the following should work:
Re-adding the "stale" controls that you will not need and will be removed at OnLoad anyway seems a bit quirky, but Asp.Net was not really designed with dynamic control creation in mind. If the exact same control hierarchy is not preserved during viewstate loading, all kinds of hard-to find bugs begin lurking in the page, because states of older controls are loaded into newly added ones.
Read up on Asp.Net page life cycle and especially on how the viewstate works and it will become clear.
Edit: This is a very good article about how viewstate behaves and what you should consider while dealing with dynamic controls: <Link>
啊,这就是 ASP.NET Web 表单抽象漏洞的问题。
也许您有兴趣了解用于创建此 stackoverflow.com 网站的 ASP.NET MVC? 对于具有 PHP(因此,当涉及到 HTML 和 Javascript 时,全力以赴)背景的您来说,这应该更适合您。
Ah, that's the problem with the leaky abstraction of ASP.NET web forms.
Maybe you'll be interested to look at ASP.NET MVC, which was used for the creation of this stackoverflow.com web site? That should be an easier fit for you, coming from a PHP (thus, pedal-to-the-metal when it comes to HTML and Javascript) background.
出色地。 如果您可以摆脱动态创建控件的麻烦,那么就这样做 - 否则,我应该做的是使用 Page_Load 而不是 Page_Init,而不是在 If Not IsPostBack 中放置内容,然后直接在方法中设置 i 。
Well. If you can get out of creating controls dynamicly, then do so - otherwise, what i whould do is to use Page_Load instead of Page_Init, but instead of placing stuff inside the If Not IsPostBack, then set i just directly in the method.
我认为这里的答案是在
MultiView
控件中,以便例如下拉菜单在多视图中的不同视图之间切换。您甚至可以将多视图的当前视图属性数据绑定到下拉列表的值!
I think the answer here is in the
MultiView
control, so that for example the dropdown switches between different views in the multi-view.You can probably even data-bind the current view property of the multiview to the value of the dropdown!
唯一正确的答案是艾兹曼给出的。 LoadViewState 是添加动态控件的唯一位置,重新创建时它们的视图状态值将被恢复,并且您可以访问视图状态以确定要添加的控件。
The only correct answer was given by Aydsman. LoadViewState is the only place to add dynamic controls where their viewstate values will be restored when recreated and you can access the viewstate in order to determine which controls to add.
我在“Pro ASP.NET 3.5 in C# 2008”一书中的“动态控件创建”部分遇到了这一点:
我还没有测试过这个,但你可以研究一下。
I ran across this in the book "Pro ASP.NET 3.5 in C# 2008" under the section Dynamic Control Creation:
I have not tested this, but you might look into it.
我同意这里提出的其他观点“如果您可以摆脱动态创建控件的束缚,那么就这样做......”(作者:@Jesper Blad Jenson 又名),但这是我过去使用动态创建的控件解决的一个技巧。
问题变成先有鸡还是先有蛋。 您需要 ViewState 来创建控件树,并且需要创建控件树来获取 ViewState。 嗯,这几乎是正确的。 有一种方法可以在填充树的其余部分之前获取 ViewState 值。 这是通过覆盖
LoadViewState(...)
和SaveViewState(...)
。在 SaveViewState 中存储您想要创建的控件:
当框架调用您的“LoadViewState”覆盖时,您将得到从“SaveViewState”返回的确切对象:
我已经成功地使用它来创建数据集所在的 ASP.Net 页面序列化到 ViewState 以存储对整个数据网格的更改,允许用户使用 PostBack 进行多次编辑,并最终在单个“保存”操作中提交所有更改。
I agree with the other points made here "If you can get out of creating controls dynamically, then do so..." (by @Jesper Blad Jenson aka) but here is a trick I worked out with dynamically created controls in the past.
The problem becomes chicken and the egg. You need your ViewState to create the control tree and you need your control tree created to get at your ViewState. Well, that's almost correct. There is a way to get at your ViewState values just before the rest of the tree is populated. That is by overriding
LoadViewState(...)
andSaveViewState(...)
.In SaveViewState store the control you wish to create:
When the framework calls your "LoadViewState" override you'll get back the exact object you returned from "SaveViewState":
I've used this successfully to create ASP.Net pages where a DataSet was serialised to the ViewState to store changes to an entire grid of data allowing the user to make multiple edits with PostBacks and finally commit all their changes in a single "Save" operation.