ASP.NET-强制子/容器事件在父onload之前触发?

时间:2010-05-12 04:29:13

标签: asp.net dynamic events viewstate page-lifecycle

我正在研究一种问卷类型的应用程序,其中问题存储在数据库中。因此,我在每个Page.OnLoad上动态创建我的控件。 这就像一个魅力,并且在回发之间保持ViewState,因为我确保我的动态控件始终具有相同的生成Control.ID。

除了动态填充问题的用户控件外,我的问卷页面还包含一个“状态”部分(也由用户控件封装),表示调查问卷的状态(选项为“完成”,“已启动”或“进行中”)。如果用户改变问卷状态(即从“进行中”到“完成”),我需要回发到服务器,因为问卷的动态部分的内容取决于所选状态。

有些问题始终存在,无论状态如何,但其他问题可能根本不存在于所选状态。关键是,当状态发生变化时,我必须回发到页面并呈现正确的问题集。此外,我需要为那些“始终可用”的问题保留任何用户输入的值。

但是,由于ASP.NET中的页面生命周期,“状态”用户控件的OnLoad(包含从数据库加载正确问题所需的正确状态)在“动态问题”之后才会执行'用户控件已经填充(错误/陈旧值)。

为了解决这个问题,我将一个事件从我的“状态”用户控件引发到主页面,以指示状态已更改。然后主页面会在“动态问题”用户控件上引发一个事件。因为当这个事件冒出来时,“动态问题”用户控件已经从DB加载了“错误”的问题,它首先调用Controls.Clear。然后,它愉快地使用新状态来查询数据库中的“正确”问题,并在每个问题上执行Control.Add()。仅供参考,Control.ID在回发中保持一致。

此解决方案有效... sorta。确定了所选状态的正确问题集;然而,ViewState因为“永远可用”的问题而迷失了方向。我猜这是因为“动态问题”用户控件在响应状态更改事件时调用Controls.Clear。这必须以某种方式杀死ViewState和我的动态控件之间的关联,即使Control.ID是一致的。

这似乎是一个常见的要求,我几乎可以肯定,有一个更好,更清洁,更不容易出错的方法来实现这一目标。如果它不明显,尽管在去年使用它,我还是无法理解ASP.NET页面的生命周期。非常感谢任何帮助!

4 个答案:

答案 0 :(得分:2)

  

但是,由于页面生命周期的原因   ASP.NET,'状态'用户控件   OnLoad,包含正确的   加载权利所需的状态   来自DB的问题,没有得到   执行到'动态后'   问题的用户控制已经存在   已填充(错误/陈旧   值)。

如果您知道基础状态控件的客户端ID,则可以通过规避Web表单并直接访问已发布的表单数据来获取页面生命周期中任何时刻的发布值:

// where 'selectedStatus' is the id of the html <input> control the user clicks
string statusString = Request.Form["selectedStatus"];

答案 1 :(得分:0)

您可以将其更改为仅在Page_Load中加载控件(不确定任何与状态相关的内容),并将控件的状态特定呈现移至Page_PreRender。

如果用户控件是负责加载内容的用户控件,则动态用户控件可以从数据库中读取PreRender事件(或DataBind事件)。

我认为问题是用户控件在加载所有控件并加载视图状态之前尝试读取状态。通过将依赖于状态的显示延迟到以后的页面事件,您可以确保它基于正确的状态。

答案 2 :(得分:0)

  

我确保我的动态控件   总是有相同的生成   Control.ID

ViewState无法控制ID。如果您希望动态控件中的进程OnClick事件由用户数据输入,则必须在RaisPostBackEvent事件之前恢复控件层次结构,该事件在Page_load之后立即触发。

如果要将动态控件保存在页面上其他位置的相同状态,或者您希望在创建其他动态控件后有权访问控件,则必须保存控件层次结构。 / p>

原来如此!在一个容器中创建动态控件的第一部分,并在其他容器中创建回发控件。

例如,在页面请求中,您呈现:

< asp:placeholder id="iHaveToBeDuringAllRequests1" >
  First dynamic cintrols
< /asp:placeholder >
< asp:placeholder id="iHaveToBeDuringAllRequests2" >
  Empty on first request 
< /asp:placeholder >

在PostBack上渲染:

< asp:placeholder id="iHaveToBeDuringAllRequests1" >
  First dynamic cintrols(you can clear or do not load these controls if you don't need it)
< /asp:placeholder >
< asp:placeholder id="iHaveToBeDuringAllRequests2" >
  Second dynamic controls load here
< /asp:placeholder >

最后提示:

  

我确保我的动态控件   总是有相同的生成   Control.ID

您需要确保通过动态控件正确触发RaisPostBackEvent(OnClick等)(您可以使用INamingContainer容器而不是占位符)。

答案 3 :(得分:0)

嗯 - ASP.NET页面生命周期;我的最爱之一:)

  

我猜这是因为   '动态问题'用户控制电话   Controls.Clear在响应时   状态改变事件。这必须   以某种方式杀死之间的关联   ViewState和我的动态控件,   即使Control.ID是   是一致的。

听起来这是从视图状态(包括“永远在线”问题)重新创建所有内容,然后将其放入垃圾箱。 之后,重新创建控件(没有任何视图状态,因为已经完成了它的重新创建)。所以是的,我也认为Controls.Clear是您失去视野状态的原因。

这可能不是一个可以解决的问题。我可以想象不同的方法。

  

但是,由于页面生命周期的原因   ASP.NET,'状态'用户控件   OnLoad,包含正确的   加载权利所需的状态   来自DB的问题,没有得到   执行到'动态后'   问题的用户控制已经存在   已填充(错误/陈旧   值)。

“OnLoad包含正确的状态”是什么意思?我想说应该可以在动态问题“数据绑定”期间从状态控件中获取“当前选择”(如果你碰巧在动态问题控件中有这样的东西)。 /我认为这个的原因是“数据绑定”(在父母中)发生在在下面提供的文章“The ASP.NET Page Life Cycle”中提到的第3点之后。因此,如果您的动态问题控件知道它必须遵守的状态,它应该能够获取它。如果这不起作用,我会首先检查问题是否在状态控件内。如果你的动态问题控制不知道任何状态,这显然不起作用。

另一种方法是让你的动态问题控制不要删除它的所有孩子(Controls.Clear),而只删除那些不再需要的孩子。你可以(而且我认为你应该)在PreRender中这样做。因此,对于动态问题控制来说,将“永远在线”问题与其他问题区分开来可能会有所帮助。然后你可以坚持你现在的策略和事件。

如果您想深入了解ASP.NET页面生命周期和查看状态并且不了解它们,这两个链接可能会提供有价值的信息。

The ASP.NET Page Life CycleTRULY Understanding ViewState

  

如果不明显,我   无法理解ASP.NET   页面生命周期尽管工作   它是去年。

如果您找到了以下人员,请告诉我。)