I am trying to create a dynamic survey page. The idea seems simple, but trying to implement it in ASP.NET is getting me very frustrated...
Each user is linked to an individual list of (multiple-choice) questions. I have the following data tables:
Surveys:
User | Question | Rank
-------+------------+-----
user-x | question-x | 1
user-x | question-y | 2
user-y | question-z | 1
user-y | question-x | 2
Questions:
ID | Text | Choices
-----------+------+-----------------------
question-x | Foo? | yes|no
question-y | Bar? | never|sometimes|always
question-z | Baz? | 1|2|3|4|5|6|7|8|9|10
Answers:
User | Question | Answer
-------+------------+-------
user-x | question-x | 0
user-x | question-y | 2
user-y | question-z | 5
So the answer choices are character-separated strings that need to be expended when databinding, and the answers are stored as a 0-based index to the answer. (So user-x answered "always" on question-y.)
Here is my first version of the code:
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:dbconn %>"
SelectCommand="
SELECT Questions.Text AS Question, Questions.Choices, Answers.Answer
FROM Questions
INNER JOIN Surveys ON Surveys.Question = Questions.ID
LEFT OUTER JOIN Answers ON Questions.ID = Answers.Question
AND Users.ID = Answers.User
WHERE (Surveys.User = @User)
ORDER BY Surveys.Rank">
<SelectParameters>
<asp:QueryStringParameter Name="User" QueryStringField="id" />
</SelectParameters>
</asp:SqlDataSource>
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1"
onitemdatabound="Repeater1_ItemDataBound">
<HeaderTemplate><table></HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("Question") %></td>
<td><asp:Label runat="server" ID="ChoicesLabel"/></td>
</tr>
</ItemTemplate>
<FooterTemplate></table></FooterTemplate>
</asp:Repeater>
<asp:Button ID="Button1" runat="server" Text="Submit" onclick="Button1_Click"/>
and:
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType != ListItemType.AlternatingItem)
return;
DataRowView row = (DataRowView)e.Item.DataItem;
RadioButtonList rbl = new RadioButtonList();
rbl.RepeatDirection = RepeatDirection.Horizontal;
string[] Choices = row["Choices"].ToString().Split('|');
for (int n = 0; n < Choices.Length; n++)
{
rbl.Items.Add(new ListItem(Choices[n], n.ToString()));
}
if (row["Answer"] != DBNull.Value)
rbl.SelectedIndex = (int)row["Answer"];
((Label)e.Item.FindControl("ChoicesLabel")).Controls.Add(rbl);
}
protected void Button1_Click(object sender, EventArgs e)
{
}
Now, the first problem was that after I click "Submit", I get a page in return which only contains the questions, not the radiobuttons with answers! After lots of searching, I fixed this by forcing the data binding to occur on page initialization:
public void Page_Init(Object sender, EventArgs e)
{
Repeater1.DataBind();
}
However, I am still completely in the dark if it is possible to do a 2-way databinding on the RadioButtonLists? (I mean with a <%# Bind() %> command.) Or do I have to write my own procedure for submitting the answers back to the database? To make things more complicated, on first visit the answers will have to be INSERTed into the Answers table, while on return visits the existing rows can be UPDATEd.