Web 控件生命周期问题:页面、网格和对话框(包含其类型取决于网格中所选行的动态控件)

发布于 2024-08-09 15:19:13 字数 1508 浏览 8 评论 0原文

我有一个带有 GridView 的网页。 GridView 包含 Question 对象的列表。每个问题都有一个 QuestionType。当用户单击 Question 控件时,会出现一个 Ajax 模式弹出窗口,其中包含一个 Dialog 自定义 Web 控件。对话框 Web 控件旨在将子自定义 Web 控件与“确定”和“取消”按钮封装在一起。在此方案中,子控件是代表所选问题的问题自定义控件。在单击 GridView 中的行之前,不知道 Question 控件的确切类型。

总结页面层次结构:

  • 包含问题的页面
  • GridView(在 .aspx 标记中声明,触发 单击一行时的事件)
  • 链接到 AJAX 模式弹出扩展器的面板(在 .aspx 中声明) 标记)
  • 对话框控件(在 .aspx 标记中声明)
  • 问题控件(在对话框中动态创建 控制,类型未知,直到 选择问题)
  • 确定按钮(在对话框控件中动态创建)
  • 取消按钮(在对话框控件中动态创建 ) 控件)

当用户单击对话框中的“确定”按钮时,我希望能够从包含的页面获取对话框的内容。 (各种问题控件中都有代码验证答案,对话框中有一个属性将答案公开给包含的页面。)

我在使其正常工作时遇到了很多麻烦。

我已经用谷歌搜索了几个小时,所有有关自定义 Web 控件的文章都指出您需要在 OnInit 覆盖中创建子控件。但是,在我的场景中,在 GridView 触发其行​​单击事件之前调用 Dialog OnInit 方法,这意味着我无法创建 Question 控件,因为我不知道目标类型。

如果我将创建动态问题控件的代码移至对话框生命周期的稍后点(例如 RenderContents),我至少可以使其显示动态问题控件。然而,根据所有文章,这都是不正确的,并且无论如何都是无用的,因为当单击对话框中的“确定”按钮时,该控件仍然不可用(因为对话框是隐藏的,并且永远不会调用 RenderContents)。

所以,我想问这里的 ASP.NET 人员应该如何完成此操作?我不是在寻找代码;只是策略。设置这个的正确方法是什么?目标是一个包含动态创建的控件的对话框,该控件的类型取决于 GirdView 中所选的行,并且可以在回发后由包含的页面访问。

任何提示将不胜感激。

更新

我添加了日志记录,单击网格后事件触发的顺序如下:

  • Page ctor
  • Dialog ctor
  • Dialog OnInit
  • Page OnInit
  • Page CreateChildControls
  • Dialog CreateChildControls
  • Page OnLoad
  • Dialog OnLoad
  • Page OnContactorComplianceQuestionSelected
  • Dialog RenderContents

我只知道对话框应该是什么类型的控件包含在页面 OnContactorComplianceQuestionSelected 之后。

I have a web page with a GridView. The GridView contains a list of Question objects. Each Question has a QuestionType. When the user clicks on the Question control, an Ajax modal popup appears containing a Dialog custom web control. The Dialog web control is designed to encapsulate a child custom web control together with OK and Cancel buttons. In this scenario, the child control is a Question custom control that represents the selected Question. The exact type of the Question control is not known until a row in the GridView is clicked.

To sum up the page hierarchy:

  • Page
  • GridView containing questions (declared in the .aspx markup, fires
    an event when a row is clicked)
  • Panel linked to AJAX modal popup extender (declared in the .aspx
    markup)
  • Dialog control (declared in the .aspx markup)
  • Question control (created dynamically within the Dialog
    control, type not known until
    Question selection is made)
  • OK button (created dynamically within the Dialog control)
  • Cancel button (created dynamically within the Dialog
    control)

When the user clicks the OK button in the Dialog, I want to be able to get at the contents of the Dialog from the containing page. (There is code in the various Question controls that validates the answer and a property in the Dialog that exposes the answer to the containing page.)

I have been having large amounts of trouble in getting this to work.

I have been googling for hours and all articles about custom web controls state that you need to create child controls within the OnInit override. However, in my scenario, the Dialog OnInit method is called before GridView fires its row clicked event, meaning I can't create the Question control because I don't know the target type.

I can make it at least show the dynamic Question control if I move code that creates it to a later point in the lifecycle of the Dialog e.g. RenderContents. However, this is not correct according to all the articles and useless anyway because the control is still not available when the OK button in the Dialog is clicked (as the dialog is hidden and RenderContents will never be called).

So, I'm asking the ASP.NET guys on here how this is supposed to be done? I'm not looking for the code; just strategy. What is the correct way to set this up? The aim is a dialog that contains a dynamically created control whose type depends on the selected row in the GirdView and that can be accessed by the containing page after a postback.

Any tips would be greatly appreciated.

UPDATE

I added logging and the order of events firing after the grid is clicked is as follows:

  • Page ctor
  • Dialog ctor
  • Dialog OnInit
  • Page OnInit
  • Page CreateChildControls
  • Dialog CreateChildControls
  • Page OnLoad
  • Dialog OnLoad
  • Page OnContactorComplianceQuestionSelected
  • Dialog RenderContents

I only know what type of control the Dialog is supposed to contain after Page OnContactorComplianceQuestionSelected.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花开浅夏 2024-08-16 15:19:13

不要在 OnInit 中创建动态控件 - 这在生命周期中为时过早,并且会让您陷入不愉快的兔子洞。相反:

  • 在 Click 事件处理程序(生命周期后期)中,将 QuestionID 或确定要创建哪些控件所需的任何其他信息存储在 ViewState 或 Session 中。然后添加控件。因此,当页面返回给用户时,控件将出现。

  • CreateChildControls中检查ViewState是否包含QuestionID,如果包含,则从那里重新添加控件。因此,当用户重新提交页面时,这一次在生命周期中,您可以按照应有的方式重新构建控件树。

所以像这样:

private void AddQuestionControls(int questionID)
{
    //create and add question controls
}

void Handle_Click(object sender, EventArgs e)
{
    //determine question ID
    ViewState["QuestionID"] = questionID;
    AddQuestionControls(questionID);
}

override void CreateChildControls()
{
    if(ViewState["QuestionID"] != null)
    {
        AddQuestionControls(Convert.ToInt32(ViewState["QuestionID"]);
    }
}

Don't create dynamic controls in OnInit - that is way too early in the lifecycle and will take you down an unpleasant rabbit hole. Instead:

  • In your Click event handler (late in the lifecycle) store in the ViewState or Session the QuestionID or whatever other information you need to determine which controls to create. Then add the controls. So when the page comes back to the user, the controls will be present.

  • In CreateChildControls check to see if the ViewState contains a QuestionID and if so, re-add the controls from there. So when the user re-submits the page, this time around in the lifecycle, you can reconstitute the control tree as it should be.

So something like:

private void AddQuestionControls(int questionID)
{
    //create and add question controls
}

void Handle_Click(object sender, EventArgs e)
{
    //determine question ID
    ViewState["QuestionID"] = questionID;
    AddQuestionControls(questionID);
}

override void CreateChildControls()
{
    if(ViewState["QuestionID"] != null)
    {
        AddQuestionControls(Convert.ToInt32(ViewState["QuestionID"]);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文