views:

210

answers:

2

I am creating a simple form. I have created two simple classes, Question and QuestionSection.

I then create some subclasses of question, e.g. SimpleQuestion, MultipleChoiceQuestion, with different behaviour and markup.

QuestionSection has a property of a collection of questions, like so-

private List<Question> _Questions = new List<Question>();
public List<Question> Questions
{
    get { return _Questions; }
}

which is set on, say, SurveyForm.aspx like so-

<uc:QuestionSection ID="ucQuestionSection" runat="server">
        <questions> 
            <uc:SimpleQuestion ID="qFirstName" runat="server" QuestionText="First name" />
            <uc:SimpleQuestion ID="qLastName" runat="server" QuestionText="Last name" />
            <uc:MultipleChoiceQuestion ID="qEmail" runat="server" QuestionText="Email address" />
        </questions>
</uc:QuestionSection>

On my QuestionSection.ascx page I have-

<div class="portlet-section-body form-fields">
    <asp:Panel ID="pnlQuestions" runat="server" ></asp:Panel>
</div>

which is load by this function on QuestionSection.ascx.cs

protected void Page_Init(object sender, EventArgs e)
{
      foreach (Question q in Questions)
      {
          pnlQuestions.Controls.Add(q);                
      }
}

I have a couple of questions-

  1. Is this a good idea?
  2. I am having some problems around postback and persistance of controls. My thinking is that these question controls are not dynamic, and so should work. However, on postback the question controls are not shown.
  3. Is there a better control to use in QuestionSection than the Panel control? I considered just using this.Controls.Add, but I can't see how I can add a div on either side of the control collection.
A: 

There are a couple of issues you raise. First of all, dynamically created controls don't properly persist on postback and must be re-created on each postback if you want their events to work.

Second, a better approach would be to use the control to create the questions. This control lets you define a pattern of controls to create.

I'm not sure what the HTML definition of the question object is, but here is an example of how you might modify QuestionSection.ascx to use a listview:

<div class="portlet-section-body form-fields">
    <asp:ListView runat="server" ID="QuestionsListView" 
     onitemcommand="QuestionsListView_ItemCommand">
     <LayoutTemplate>
      <div>
       <asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
      </div>
      <div>
       <asp:Button runat="server" ID="bnSave" Text="Save" 
        CommandName="Save" />
       <asp:Button runat="server" ID="bnCancel" Text="Cancel" 
        CommandName="Cancel" />
      </div>
     </LayoutTemplate>
     <ItemTemplate>
      <div class="QuestionRow">
       <asp:Label runat="server" Text='<%#Eval("QuestionText") %>' 
        AssociatedControlID="tbAnswer"></asp:Label>
       <asp:TextBox runat="server" ID="tbAnswer"></asp:TextBox>
      </div>
     </ItemTemplate>
    </asp:ListView>
</div>

Here is the code behind to populate it and to handle the button click event. If you needed another event type, try to wire the events to the ListView control, itself, rather then the subcontrols:

protected void Page_Load(object sender, EventArgs e)
{
    List<string> Questions = new List<string>()
            {
             "First Name",
             "Last Name",
             "Email Address"
            };
    QuestionsListView.DataSource =
     from q in Questions
     select new
     {
      QuestionText = q
     };

    QuestionsListView.DataBind();
}

protected void QuestionsListView_ItemCommand
    (object sender, ListViewCommandEventArgs e)
{
    switch(e.CommandName)
    {
     case "Save":
      break;

     case "Cancel":
      break;
    }
}
Michael La Voie
Thanks for your efforts. This isn't going to work for me, as I am looking for flexibilty in both the behaviour and appearance of the question controls (e.g. create a subclass of question for, say, a multiple choice question).I'm still not certain that the question controls are dynamic. Aren't they initiated on the page, then referenced by the QuestionSection control, rather than being created in the code?Either way, I realised I needed to add re-loading code anyway (load from save), and can use that to get around the persistance problems.
Spongeboy
A: 

For Part 3 - Is there a better control to use in QuestionSection than the Panel control?

Yes, the Placeholder control. It won't add a div around the controls.

Also, there is a dynamic placeholder control which aims to provide persistance to dynamic controls. However, I was unable to get this to work in my situation.

Spongeboy