1

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.

4

1 に答える 1

2

で動的コントロールを作成しないでください。これOnInitはライフサイクルの初期段階にあり、不快なうさぎの穴に落ちてしまいます。その代わり:

  • Click イベント ハンドラー (ライフサイクルの後半) で、ViewState または Session に QuestionID または作成するコントロールを決定するために必要なその他の情報を格納します。次に、コントロールを追加します。そのため、ページがユーザーに戻ってくると、コントロールが表示されます。

  • CreateChildControlsViewState に 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"]);
    }
}
于 2009-11-02T16:46:02.670 に答える