1

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

总结页面层次结构:

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

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

我在让它发挥作用方面遇到了很多麻烦。

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

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

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

任何提示将非常感谢。

更新

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

  • 寻呼机
  • 对话器
  • 对话框 OnInit
  • 页面初始化
  • 页面 CreateChildControls
  • 对话框 CreateChildControls
  • 页面加载
  • 对话框加载
  • Page OnContactorComplianceQuestionSelected
  • 对话框渲染内容

我只知道在 Page OnContactorComplianceQuestionSelected 之后 Dialog 应该包含什么类型的控件。

4

1 回答 1

2

不要在其中创建动态控件OnInit——这在生命周期中太早了,会让你陷入令人不快的兔子洞。反而:

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

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

所以像:

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"]);
    }
}
于 2009-11-02T16:46:02.670 回答