ASP.NET-强制子/容器事件在父级加载之前触发?
我正在开发一个问卷类型的应用程序,其中问题存储在数据库中。因此,我在每个 Page.OnLoad 上动态创建控件。 这就像一个魅力,ViewState 在回发之间保持不变,因为我确保我的动态控件始终具有相同的生成的 Control.ID。
除了动态填充问题的用户控件之外,我的调查问卷页面还包含一个“状态”部分(也由用户控件封装),它表示调查问卷的状态(选项为“完成”、“已开始”或“正在中”)进步')。如果用户更改调查问卷的状态(即从“进行中”到“完成”),我需要回发到服务器,因为调查问卷动态部分的内容取决于所选状态。
无论状态如何,某些问题始终存在,而其他问题对于所选状态可能根本不存在。关键是,当状态发生变化时,我必须回发到页面并呈现正确的问题集。此外,我需要保留用户为“始终可用”的问题输入的值。
但是,由于 ASP.NET 中的页面生命周期,“状态”用户控件的 OnLoad(包含从数据库加载正确问题所需的正确状态)直到“动态问题”用户控件之后才会执行已经填充(使用错误/陈旧的值)。
为了解决这个问题,我从“状态”用户控件向主页引发一个事件,以指示状态已更改。然后主页在“动态问题”用户控件上引发一个事件。由于当该事件冒泡时,“动态问题”用户控件已经从数据库加载了“错误”问题,因此它首先调用 Controls.Clear。然后,它愉快地使用新状态来查询数据库中的“正确”问题,并对每个问题执行 Control.Add()。仅供参考,Control.ID 在回发中是一致的。
这个解决方案有效......有点。确实会呈现所选状态的正确问题集;然而,ViewState 正在迷失那些“始终可用”的问题。我猜测这是因为“动态问题”用户控件在响应状态更改事件时调用 Controls.Clear。即使 Control.ID 是一致的,这也必须以某种方式终止 ViewState 和我的动态控件之间的关联。
这似乎是一个常见的要求,我几乎肯定有一种更好、更干净、更不易出错的方法来实现这一点。以防万一,尽管去年我一直在使用 ASP.NET 页面,但我还是无法理解它的生命周期。非常感谢任何帮助!
I'm working on a questionnaire type application in which questions are stored in a database. Therefore, I create my controls dynamically on every Page.OnLoad.
This works like a charm and ViewState is persisted between postbacks because I ensure that my dynamic controls always have the same generated Control.ID.
In addition to the user control that dynamically populates the questions, my questionnaire page also contains a 'Status' section (also encapsulated by a user control) which represents the status of the questionnaire (choices are 'Complete', 'Started' or 'In Progress'). If the user changes the status of questionnaire (i.e. from 'In Progress' to 'Complete'), I need to postback to the server because the contents of the dynamic portion of the questionnaire depend on the selected status.
Some questions are always present regardless of status, and yet others may not be present at all for the selected status. The point is, when the status changes, I have to postback to the page and render the right set of questions. Additionally, I need to preserve any user entered values for those questions which are 'always available'.
However, due to the page life cycle in ASP.NET, the 'Status' user control's OnLoad, which contains the correct status needed to load the right questions from the DB, doesn't get executed until after the 'dynamic questions' user control has already been populated (with the wrong/stale values).
To get around this, I raise an event from my 'Status' user control to the main page to indicate that the Status has changed. The main page then raises an event on the 'dynamic questions' user control. Since by the time this event bubbles up, the 'dynamic questions' user control has already loaded the 'wrong' questions from the DB, it first calls Controls.Clear. It then happily uses the new status to query the database for the 'correct' questions and does a Control.Add() on each. FYI, Control.IDs are consistent across postbacks.
This solution works...sorta. The correct set of questions for the selected status do get rendered; however ViewState is getting lost for those 'always available' questions. I'm guessing this is because the 'dynamic questions' user control calls Controls.Clear when responding to the status changed event. This must somehow kill the association between ViewState and my dynamic controls, even though the Control.IDs are consistent.
This seems like such a common requirement, I'm virtually certain there is a better, cleaner and less error prone approach to accomplish this. In case its not plainly obvious, I haven't been able to grok the ASP.NET page life-cycle despite working with it for the last year. Any help is much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您知道底层状态控件的客户端 ID,则可以通过绕过 Web 表单并直接访问发布的表单数据,在页面生命周期的任何时刻获取发布的值:
If you know the client id of the underlying status control, you can get the posted value at any point in the page life cycle by circumventing web forms and directly accessing the posted form data:
ViewState 的设置与控件的 ID 无关。如果您希望在动态控件内处理用户数据输入的 OnClick 事件,则必须在 RaisPostBackEvent 事件之前恢复控件层次结构,RaisPostBackEvent 事件在 Page_load 之后立即触发。
如果您想在页面上的其他位置保存具有相同状态的动态控件,或者您想在创建其他动态控件后访问控件您必须保存控件层次结构。
所以!在一个容器中创建动态控件的第一部分,并在其他容器中创建回发控件。
例如,在页面请求上,您呈现:
在回发上,您呈现:
最后一个提示:
您需要确保动态控件正确触发 RaisPostBackEvent(OnClick 等)(您可以使用 INamingContainer 容器而不是占位符)。
ViewState are made regadless to control`s ID. If you want process OnClick event inside your dynamic control with inputed by user data, you have to restore the structure of your controls hierarchy before RaisPostBackEvent event, that fired right after Page_load.
If you want to save your dynamic controls with the same state in other position on your page, or you want to have access to controls after creating other dynamic controls you HAVE TO save controls hierarchy.
So! Create your first portion of dynamic controls in one container and create controls on postback in other container.
For example on page request you render:
On PostBack you render:
And last tip:
You need to ensure this for correct firing RaisPostBackEvent(OnClick etc.) by your dynamic controls(you can use INamingContainer container instead of placeholder).
您可以将其更改为仅在 Page_Load 中加载控件(而不确定任何与状态相关的内容),并将控件的状态特定呈现移至 Page_PreRender。
如果动态用户控件负责加载内容,则动态用户控件可以在其 PreRender 事件(或 DataBind 事件)中从数据库读取数据。
我认为问题在于用户控件在加载所有控件和加载视图状态之前尝试读取状态。通过将与状态相关的显示延迟到稍后的页面事件,您可以确保它基于正确的状态。
You could change it to just load the controls (without determining any status dependent stuff) in Page_Load, and move the status specific rendering of the controls to Page_PreRender.
The dynamic user control can read from the database in it's PreRender event (or DataBind event), if the user control is the one that has the responsibility of what to load.
I think the problem is that the user controls tries to read the status before all controls are loaded and the viewstate is loaded. By delaying the status-dependent display to a later page event, you make sure it is based on the right status.
嗯 - ASP.NET 页面生命周期;我最喜欢的之一:)
听起来这是从视图状态重新创建所有内容(包括“始终打开”的问题),然后将其扔进垃圾箱。 此后重新创建控件(没有任何视图状态,因为它的重新创建已经完成)。所以是的,我也认为
Controls.Clear
是您丢失视图状态的原因。这可能不是一句话就能解决的。我可以想象不同的方法。
“OnLoad 包含正确的状态”是什么意思?我想说,在动态问题“数据绑定”期间应该可以从状态控件中获取“当前选择”(如果您的动态问题控件中碰巧有类似的内容)。 /me 之所以这么认为,是因为“数据绑定”(在父级中)发生在文章“ASP.NET 页面生命周期"如下所示。因此,如果您的动态问题控件知道它必须遵守的状态,它应该能够获取它。如果这不起作用,我会首先检查问题是否出在状态控件中。如果您的动态问题控件不知道任何状态,这显然不起作用。
另一种方法是让动态问题控件不删除其所有子项 (
Controls.Clear
),而仅删除那些不再需要的子项。您可以(而且我认为您应该)在 PreRender 中执行此操作。因此,动态问题控制有一种方法可以将“始终在线”的问题与其他问题区分开来,这可能会有所帮助。然后你就可以坚持当前的策略和事件。如果您想更深入地了解 ASP.NET 页面生命周期和视图状态,但还不了解它们,那么这两个链接可能会提供有价值的信息。
ASP.NET 页面生命周期 和 真正了解 ViewState。
如果您找到有这样的人,请告诉我:)
Hmm - ASP.NET page life cycle; one of my favourites :)
Sounds like this is recreating everything from view state (including the "always on" questions) and then chuck it to the bin. After this the controls are recreated (without any view state because recreation of it has already been done). So yes, I too think
Controls.Clear
is the reason for your lost view state.This is probably not a one-liner to solve. I could imagine different approaches.
What do you mean by "the OnLoad contains the correct status"? I would say it should be possible to fetch the "current selection" from the status control during the dynamic questions "data bind" (if you happen to have something like this in your dynamic questions control). The reason for /me thinking this is that the "data bind" (in the parent) happens after point 3 mentioned in the article "The ASP.NET Page Life Cycle" provided below. So if your dynamic questions control knows about the status it has to honour, it should be able to fetch it. If this does not work, I would first check if the problem lies within the status control. If your dynamic questions control does not know about any status this will obviously not work.
Another approach would be to have your dynamic questions control not delete all it's children (
Controls.Clear
) but only those that are not needed anymore. You could (and I think you should) do this in PreRender. So it might help to have a mean for the dynamic questions control to distinguish "always on" questions from others. You could then stick to your current tactics and the event.If you want to dig deeper into the ASP.NET page life cycle and view state and do not know them already these two links might provide valuable information.
The ASP.NET Page Life Cycle and TRULY Understanding ViewState.
Let me know if you find someone who has :)