ASP.Net 3.5 AjaxControlToolkit CollapsiblePanelExpander in Master In UpdatePanel partial postback woes - asp.net

Long time reader first time poster
I have a content page linked to a master page. The master has the toolkitscriptmanager. On the content page, I have a nested repeater within the item template of the parent repeater, I have a CollapsiblePanelExtender for the child repeater control. Upon partial postback, if the collapsed attribute is not set, then all of the panels expand. If the collapsed attribute is set to true, then all of the panels are collapsed upon partial postback.
The databinding of the repeater is occurring in the page_init section of the code behind, and I am checking the state of the panels by iterating through the items in the page_load event. Nothing appears to be working, while debugging the code, I do see the properties being appropriately set, but when rendered in the browser, all panels are open. The edit event that triggers the partial postback is preformed in a modalpopup.
I have attempted to move the panels into their own update panel, remove the update panel, place the modal outside of the update panel to no avail. The ViewState is not maintained.
Page Code:
<asp:Repeater ID="rptrConsultants" runat="server" OnItemCommand="rptrConsultants_ItemCommand" OnItemDataBound="rptrConsultants_ItemDataBound">
<HeaderTemplate>
<div class="pageTitle">
Your Consultants (Click on the image beside the consultant to view their group memberships)
<br />
Official names are listed. Expanding the consultant will show the name assigned and the related groups.
</div>
<br />
<table>
<tr>
<td style="width: 60px; font-weight: bold; text-align: center;">
Actions
</td>
<td style="font-weight: bold;">
Consultant information
</td>
</tr>
</HeaderTemplate>
<FooterTemplate>
</table>
<asp:Label ID="lblNoConsultant" runat="server" Text="You have not created any consultants" Visible="false"></asp:Label>
</FooterTemplate>
<ItemTemplate>
<tr>
<td style="width: 60px; text-align: center;">
<asp:Image ID="imgConsultantExpander" runat="server" ToolTip="Click here to toggle consultant details" AlternateText="Toggle Consultant Details" />
<asp:ImageButton ID="btnDeleteConsultant" AlternateText="Delete Consultant" runat="server" CausesValidation="false" CommandName="DeleteConsultant" CommandArgument='<%#DataBinder.Eval(Container.DataItem, "IndividualsID")%>' ImageUrl="~/Styles/Images/Icons/remove_consultant.png" ToolTip="Delete consultant" />
<asp:ImageButton ID="btnAddConsultantToNewGroup" AlternateText="Add consultant to a new group" runat="server" CommandName="AddConsultantToGroup" CommandArgument='<%#DataBinder.Eval(Container.DataItem, "IndividualsID")%>' ImageUrl="~/Styles/Images/Icons/add_user_to_group.png" ToolTip="Add consultant to a new group" />
</td>
<td>
<%#DataBinder.Eval(Container.DataItem, "Name")%>
(<%#DataBinder.Eval(Container.DataItem, "UserID") %>)
<asp:Label ID="lblGroupCount" runat="server" />
</td>
</tr>
<tr>
<td colspan="2">
<asp:Panel ID="pnlConsultantExpander" runat="server">
<asp:Repeater ID="rptrConsultantGroups" runat="server" DataSource='<%#Container.DataItem.Row.GetChildRows("ConsultantGroupRelation") %>' OnItemCommand="rptrConsultantGroups_ItemCommand">
<HeaderTemplate>
<table style="margin-left: 50px;">
<tr>
<td style="width: 40px; text-align: center; font-weight: bold;">
Actions
</td>
<td style="font-weight: bold;">
Membership
</td>
<td style="font-weight: bold;">
Nick Name
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td style="width: 40px;">
<asp:ImageButton ID="btnEditConsultant" AlternateText="Edit Consultant" runat="server" CommandName="EditConsultantInGroup" CommandArgument='<%#Container.DataItem("GroupID") & "|" & Container.DataItem("GroupMembershipID")%>' ImageUrl="~/Styles/Images/Icons/edit_consultant.png" />
<asp:ImageButton ID="btnDeleteConsultant" AlternateText="Remove from group" runat="server" CommandName="DeleteConsultantFromGroup" CommandArgument='<%#Container.DataItem("GroupID") & "|" & Container.DataItem("GroupMembershipID")%>' ImageUrl="~/Styles/Images/Icons/delete_fromgroup.png" ToolTip="Remove from group" />
</td>
<td class="textbold">
<%#Container.DataItem("GroupName")%>
</td>
<td class="textitalic">
<%#Container.DataItem("nickname")%>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</asp:Panel>
<asp:CollapsiblePanelExtender ID="cpepnlConsultantExpander" runat="server" TargetControlID="pnlConsultantExpander" CollapseControlID="imgConsultantExpander" ExpandControlID="imgConsultantExpander" CollapsedImage="~/Styles/Images/Icons/user_info.png" ExpandedImage="~/Styles/Images/Icons/user_open.png" ImageControlID="imgConsultantExpander" EnableViewState="true" CollapsedSize="0" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
And then the code behind method that occurs in page_load:
Private Sub setCollapsiblePanelsInRepeater(ByVal rptr As Repeater)
For Each item As RepeaterItem In rptr.Items
If ((item.ItemType = ListItemType.AlternatingItem) Or (item.ItemType = ListItemType.Item)) Then
For Each ctl As Control In item.Controls
If (TypeOf ctl Is AjaxControlToolkit.CollapsiblePanelExtender) Then
Dim cpe As AjaxControlToolkit.CollapsiblePanelExtender = DirectCast(ctl, AjaxControlToolkit.CollapsiblePanelExtender)
If (Not IsPostBack()) Then
cpe.Collapsed = True
cpe.ClientState = "true"
Else
Dim isCollapsed As Boolean
If (Request.Form(cpe.UniqueID & "_ClientState") IsNot Nothing) Then
isCollapsed = (Request.Form(cpe.UniqueID & "_ClientState").ToString() = "true")
Else
isCollapsed = True
End If
If (isCollapsed) Then
cpe.ClientState = "true"
cpe.Collapsed = True
Else
cpe.ClientState = "false"
cpe.Collapsed = False
End If
End If
End If
Next
End If
Next
End Sub
Note that the initial load event works! The panels are all collapsed on page load
Also note, that the repeater is nested in a tabPanel
Thank you in advance for your answer!
sorry for the long winded explanation
EDIT:
Update:
Attempted the Javascript Route -- Still no avail
pageLoad = function()
{
CheckStatusOfPanels();
};
function CheckStatusOfPanels()
{
var allBehaviors = Sys.Application.getComponents();
for (var loopIndex = 0; loopIndex < allBehaviors.length; loopIndex++)
{
currentBehavior = allBehaviors[loopIndex];
if (currentBehavior._name && currentBehavior.get_name() == 'CollapsiblePanelBehavior')
{
var myID = currentBehavior.get_id() + '_ClientState';
var isCollapsed = document.getElementById(myID).value
if (isCollapsed == 'true')
{
currentBehavior.expandPanel();
currentBehavior._ClientState = isCollapsed;
}
else
{
currentBehavior.collapsePanel();
currentBehavior._ClientState = isCollapsed;
}
}
}
}
** UPDATE #2 **
My Rep is under 100 so I have to wait 8 hrs for the ability to answer my own question:
Here is my "fix" after working almost all day on this:
Ok finally found a solution. Here it goes:
Using the SetCollapsiblePanelsInRepeater method posted in my original post, I added the call to this method in the updatePanel prerender method, and Voila the panels now preserve their state....
Protected Sub updtpnlMain_PreRender(ByVal sender As Object, ByVal e As EventArgs) Handles updtpnlMain.PreRender
setCollapsiblePanelsInRepeater(rptrGroups)
setCollapsiblePanelsInRepeater(rptrConsultants)
End Sub
For Clarity for others Googling this issue, the method that sets the panel events is:
Private Sub setCollapsiblePanelsInRepeater(ByVal rptr As Repeater)
For Each item As RepeaterItem In rptr.Items
If ((item.ItemType = ListItemType.AlternatingItem) Or (item.ItemType = ListItemType.Item)) Then
For Each ctl As Control In item.Controls
If (TypeOf ctl Is AjaxControlToolkit.CollapsiblePanelExtender) Then
Dim cpe As AjaxControlToolkit.CollapsiblePanelExtender = DirectCast(ctl, AjaxControlToolkit.CollapsiblePanelExtender)
If (Not IsPostBack()) Then
cpe.Collapsed = True
cpe.ClientState = "true"
Else
Dim isCollapsed As Boolean
If (Request.Form(cpe.UniqueID & "_ClientState") IsNot Nothing) Then
isCollapsed = (Request.Form(cpe.UniqueID & "_ClientState").ToString() = "true")
Else
isCollapsed = True
End If
If (isCollapsed) Then
cpe.ClientState = "true"
cpe.Collapsed = True
Else
cpe.ClientState = "false"
cpe.Collapsed = False
End If
End If
End If
Next
End If
Next
End Sub

Toolkitscript manager at master pages causes real problems. You may find your solution as using at individual content pages.
Also are you sure that you have enabled viewstate at content pages like this
<%# Page EnableViewState="true" Language="C#" AutoEventWireup="true" CodeFile="myfile.aspx.cs"
Inherits="myfile" %>
This is for C#

Ok finally found a solution. Here it goes:
Using the SetCollapsiblePanelsInRepeater method posted in my original post, I added the call to this method in the updatePanel prerender method, and Voila the panels now preserve their state....
Protected Sub updtpnlMain_PreRender(ByVal sender As Object, ByVal e As EventArgs) Handles updtpnlMain.PreRender
setCollapsiblePanelsInRepeater(rptrGroups)
setCollapsiblePanelsInRepeater(rptrConsultants)
End Sub
For Clarity for others Googling this issue, the method that checks the status of the panels and collapses / expands them is:
Private Sub setCollapsiblePanelsInRepeater(ByVal rptr As Repeater)
For Each item As RepeaterItem In rptr.Items
If ((item.ItemType = ListItemType.AlternatingItem) Or (item.ItemType = ListItemType.Item)) Then
For Each ctl As Control In item.Controls
If (TypeOf ctl Is AjaxControlToolkit.CollapsiblePanelExtender) Then
Dim cpe As AjaxControlToolkit.CollapsiblePanelExtender = DirectCast(ctl, AjaxControlToolkit.CollapsiblePanelExtender)
If (Not IsPostBack()) Then
cpe.Collapsed = True
cpe.ClientState = "true"
Else
Dim isCollapsed As Boolean
If (Request.Form(cpe.UniqueID & "_ClientState") IsNot Nothing) Then
isCollapsed = (Request.Form(cpe.UniqueID & "_ClientState").ToString() = "true")
Else
isCollapsed = True
End If
If (isCollapsed) Then
cpe.ClientState = "true"
cpe.Collapsed = True
Else
cpe.ClientState = "false"
cpe.Collapsed = False
End If
End If
End If
Next
End If
Next
End Sub

Related

Update panel automatically clears textboxes

I'm trying to combine an event of automatic printing of messages in case the passwords will not match. For that purpose I'm using an Update panel.
The Error message prints perfectly My problem is that both text-boxes automatically created after it. even thought I don't specify it in the code. I can't understand what have I done wrong.
This is the code for front end:
<asp:TextBox ID="NonPass1" runat="server" TextMode="Password"></asp:TextBox>
<asp:TextBox ID="NonPass2" runat="server" TextMode="Password" autopostback="True"></asp:TextBox>
<asp:UpdatePanel ID="UpdatePanel6" runat="server">
<ContentTemplate>
<asp:Panel ID="Panel6" runat="server">
<asp:Label ID="Label1" class="errorMess" runat="server" Text="The Passwords do not match!!!"></asp:Label>
</asp:Panel>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="NonPass2" EventName="TextChanged" />
</Triggers>
</asp:UpdatePanel>
this is the back end code(I'm using VB):
Protected Sub NonPass2_TextChanged(ByVal sender As Object, ByVal e As EventArgs) Handles NonPass2.TextChanged
If NonPass1.Text <> NonPass2.Text Then
Panel3.Visible = False
Panel6.Visible = True
Else
Panel3.Visible = False
Panel6.Visible = False
End If
End Sub
maybe you can use javascript functions.
<script>
var t1 = false; // textbox1 onfocus triggered = true;
var t2 = false; // textbox2 onfocus triggered = true;
function clearTBox() {
if (t1 && t2) {
if (document.getElementById("textbox1Name").value != document.getElementById("textbox1Name2").value) {
alert("Insert your code here");
}
}
}
</script>
Heres what i use in c# for this, maybe you can inherit the technique
private void ClearTextBoxes()
{
Action<Control.ControlCollection> func = null;
func = (controls) =>
{
foreach (Control control in controls)
if (control is TextBox)
(control as TextBox).Clear();
else
func(control.Controls);
};
func(Controls);
}
then call cleartextboxes();
Hope that helped :)
what do you mean :
My problem is that both text-boxes automatically created after it
please, make your question more clearance
Try not to use updatepanel,
try this
<asp:TextBox ID="NonPass1" runat="server" TextMode="Password"></asp:TextBox>
<asp:TextBox ID="NonPass2" runat="server" TextMode="Password" autopostback="True"></asp:TextBox>
<div id="Div_Error" runat="server" visible="false" style="width:100%">
<asp:Label ID="Label1" class="errorMess" runat="server" Text="The Passwords do not match!!!"></asp:Label>
and use this in the code behind:
Protected Sub NonPass2_TextChanged(ByVal sender As Object, ByVal e As EventArgs) Handles NonPass2.TextChanged
If NonPass1.Text <> NonPass2.Text Then
Div_Error.visible=true;
Else
Div_Error.visible=false;
End If
End Sub
The only logical reason for the behavior as you described is perhaps, you put the above password boxes inside another UpdatePanel.
Therefore, the password boxes will be reloaded on postbacks (textchanged event), and TextBox of type Password do not retain its value after postbacks for security reason.
Though, if security is not a concern for you, there is a workaround to 'avoid' the password textboxes from being cleared on postbacks, by reassigning their values every time postbacks occur. Just include the following codes in the page Load event.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
NonPass1.Attributes.Add("value", NonPass1.Text)
NonPass2.Attributes.Add("value", NonPass2.Text)
End Sub
this is a simple example:
<table class="mytable" cellspacing="0" style="width: 100%">
<tr>
<td>
<asp:TextBox ID="Txt_Pass" runat="server" ></asp:TextBox>
</td>
<td>
<asp:TextBox ID="Txt_Re_Pass" runat="server" ></asp:TextBox>
</td>
<td width="66%" align="left">
<asp:Button ID="Btn_Filter" runat="server" Text="" Height="22px" />
</td>
</tr>
</table>
<br />
<div id="Div_Error" runat="server" visible="false" style="width:100%">
<asp:Label ID="lbl_Error" runat="server" class="msg">
</asp:Label>
</div>
and in the code behind , use this:
Protected Sub Btn_Filter_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Btn_Filter.Click
If Trim(Txt_Re_Pass.Text) <> "" Then
Div_Error.Visible = False
if Txt_Pass.Text <> Txt_Re_Pass.Text then
Div_Error.Visible = True
lbl_Error.text="The Passwords do not match!!!""
else
Div_Error.Visible = False
End if
Else
Div_Error.Visible = True
lbl_Error.text="Please re enter your password"
End If
End Sub

Accessing button in repeater control

I'm trying - quite unsuccessfully - to access a button inside a repeater control. I have a repeater set up on a page that displays movies that are currently showing in cinemas. I have created two buttons and added them to the repeater - one for trailer and another for review. For the review I want to link to another page which will have another repeater with paging enabled. When a users clicks the review button they should be brought to a page that shows only the reviews for that specific movie. This is that code I have:
MARKUP:
The repeater:
<asp:Repeater ID="movies" runat="server">
<ItemTemplate>
<table width="641px">
<tr>
<td>
<span style="font-weight:bold;font-size:16px;">
<%# Container.DataItem("MovieTitle")%>
</span>
</td>
<td>
<span style="float:right;">
<asp:Image ID="Image1" runat="server" ImageUrl = '<%# Eval("Total")%>' style="width:80px;height:14px;"/>
</span>
</td>
</tr>
<tr>
<td colspan="2">
<hr style="height:1px;border-bottom:none;color:#e3e3e3;"/>
</td>
</tr>
</table>
<table width="641px">
<tr>
<td>
<asp:Image ID="Image2" runat="server" ImageUrl = '<%# Eval("MovieImageFileName")%>' style="width:180px;height:108px;border:1px solid #e3e3e3;"/>
</td>
<td style="vertical-align:top;">
<%# Container.DataItem("Synopsis")%>
</td>
</tr>
</table>
<table width="641px">
<tr>
<td>
<span style="float:right">
<asp:Button ID="btnTrailer" runat="server" Text="Trailer" BackColor="#FF9900" ForeColor="White" />
<asp:Button ID="btnReview" runat="server" Text="Review" BackColor="#FF9900" ForeColor="White" CommandName="Review" />
</span>
</td>
</tr>
<tr>
<td>
<hr style="height:1px;border-bottom:none;color:#e3e3e3;"/>
</td>
</tr>
</table>
</ItemTemplate>
</asp:Repeater>
CodeBehind:
Dim movie_title As String
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim myConn As New OleDbConnection
Dim cmd As New OleDbCommand
Dim dr, aDataReader As OleDbDataReader
Dim query, movieID As String
movie_title = Request.QueryString("id")
myConn = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source = " & _
Server.MapPath("/App_Data/MovieBoard.accdb"))
myConn.Open()
Dim sqlQuery = "Select movieID From Movies"
Dim aCmd = New OleDbCommand(sqlQuery, myConn)
aDataReader = aCmd.ExecuteReader()
If aDataReader.Read() = True Then
movieID = aDataReader(0)
Else
movieID = "0"
End If
query = ("Select MovieTitle, Genre, Synopsis, Starring, Total, Director, MovieImageFileName From Movies, MovieReviews, MReviewRatings WHERE Movies.MovieID = MovieReviews.MovieID AND MovieReviews.MReviewID = MReviewRatings.MReviewID AND ReviewerTypeID = 1")
cmd = New OleDbCommand(query, myConn)
dr = cmd.ExecuteReader()
movies.DataSource = dr
movies.DataBind()
End Sub
Protected Sub movies_ItemCommand(source As Object, e As RepeaterCommandEventArgs) Handles movies.ItemCommand
If e.CommandName = "Review" Then
Response.Redirect("testingreviews.aspx?id = '" & movie_title)
End If
End Sub
When I run page the page displays but when I click the review button I get the following error:
Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation="true"/>
in configuration or <%# Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or
callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.
RegisterForEventValidation method in order to register the postback or callback data for validation.
Anyone any ideas on what I am doing wrong? I am very new to asp.net.
If you want to access a button use the event ItemCreated or maybe its ItemDataBound.
Handles movies.ItemCreated
In that event you can then refeer to the button using FindControl,
Something like this
Sub Movies_ItemDataBound(Sender As Object, e As RepeaterItemEventArgs) Handles movies.ItemDataBound
Dim Btn As Button = CType(e.Item.FindControl("ButtonName"),Button)
End Sub

Find a repeater that is within another repeater

Ok so my issue is I have three repeaters. Within that repeater I have another repeater and a third one in the second. There is more in between but that's not relevant. Below the HTML is my VB code. My issue is that rptCrashPercentageAvg reutrns Nothing. How can rptCrashStatsDisplay access rptCrashPercentageAvg?
<asp:Repeater ID="rptCrashStatsDisplay" runat="server">
<ItemTemplate>
<asp:Repeater ID="rptCrashPercentage" runat="server">
<ItemTemplate>
<tr class="statsRowA">
<td class="emphasis" style="padding-left: 20px">
<%# DataBinder.Eval(Container.DataItem,"CRASH_TYPE_DESC") %>:
</td>
<td style="padding-left: 5px">
<%--background-color: <%# Iif(DataBinder.Eval(Container.DataItem,"CRASH_TYPE_PERCENT")>DataBinder.Eval(Container.DataItem,"COUNT(*)"), "red", "null") %>"--%>
<%#String.Format("{0:N1}", DataBinder.Eval(Container.DataItem, "CRASH_TYPE_PERCENT"))%>
%
</td>
<asp:Repeater ID="rptCrashPercentageAvg" runat="server">
<ItemTemplate>
<td style="padding-left: 5px">
<%#String.Format("{0:N1}", DataBinder.Eval(Container.DataItem, "AVG_VAL"))%>
%
</td>
</ItemTemplate>
</asp:Repeater>
</tr>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
Private Sub rptCrashStatsDisplay_ItemDataBound(ByVal sender As System.Object, _
ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptCrashStatsDisplay.ItemDataBound
Dim dv As DataRowView = CType(e.Item.DataItem, DataRowView)
If Not IsNothing(dv) Then
Dim rptCrashPercentage As Repeater = CType(e.Item.FindControl("rptCrashPercentage"), Repeater)
Dim view As DataView = dv.CreateChildView("statRel1")
If (view.Count > 0) Then
rptCrashPercentage.DataSource = view
rptCrashPercentage.DataBind()
End If
Dim rptCrashPercentageAvg As Repeater = CType(e.Item.FindControl("rptCrashPercentageAvg"), Repeater)
Dim viewAvg As DataView = dv.CreateChildView("statRel2")
If (viewAvg.Count > 0) Then
rptCrashPercentageAvg.DataSource = viewAvg
rptCrashPercentageAvg.DataBind()
End If
End If
End Sub
I would try making sure you're looking for it in the correct place. It'll look in your repeater's Header for the control and since it won't find it there, it'll be Nothing the first time you try and use it.
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
Dim rptCrashPercentageAvg As Repeater = CType(e.Item.FindControl("rptCrashPercentageAvg"), Repeater)
'Shouldn't be "nothing" here.
End If
Otherwise you could try a more inefficient method:
Dim rptCrashPercentageAvg As Repeater = CType(e.Item.FindControl("rptCrashPercentageAvg"), Repeater)
If rptCrashPercentageAvg IsNot Nothing Then
Dim viewAvg As DataView = dv.CreateChildView("statRel2")
If (viewAvg.Count > 0) Then
rptCrashPercentageAvg.DataSource = viewAvg
rptCrashPercentageAvg.DataBind()
End If
End If
Edit: Also, since it actually is a repeater, you shouldn't need the CType.

Event handlers for controls in an ASP Repeater

I need to be able to trigger events when a user clicks on a radio button that is generated within an control on my page.
I've added an OnSelectedIndexChanged handler to the RadioButtonList and created a function in my code behind that should handle the selection of the RadioButtonList's ListItems, but I don't know how to pass a value to that function.
Here's my code:
<asp:Repeater runat="server" ID="rptQuestions">
<HeaderTemplate><table width="100%"></HeaderTemplate>
<ItemTemplate>
<tr>
<td colspan="2"><%# Container.DataItem("QuestionText")%></td>
</tr>
<tr>
<td>
<asp:RadioButtonList runat="server" ID="rblAnswerSelection" RepeatDirection="Horizontal" AutoPostBack="true" OnSelectedIndexChanged="CheckAnswer">
<asp:ListItem Text="True" Value="1"></asp:ListItem>
<asp:ListItem Text="False" Value="0"></asp:ListItem>
</asp:RadioButtonList>
<asp:Label runat="server" ID="lblCorrectAnswer" Text="<%#Container.DataItem("CorrectAnswer") %>"></asp:Label>
</td>
<td><asp:Label runat="server" ID="lblResult"></asp:Label></td>
</tr>
</ItemTemplate>
<FooterTemplate></table></FooterTemplate>
</asp:Repeater>
Private Function CheckAnswer(ByVal SelectedAnswer As Integer) As Boolean
Select Case SelectedAnswer
Case 1 ' User answered True
If lblCorrectAnswer.Text = "True" Then
Return True
Else
Return False
End If
Case 0 ' User answered False
If lblCorrectAnswer.Text = "False" Then
Return True
Else
Return False
End If
End Select
End Function
The idea is that the user is to be informed whether or not their selected answer was correct. The value of the CheckAnswer function would determine a "CORRECT" or "INCORRECT" message displaying on lblResult. If there's a way to do this without a PostBack, then that would be ideal.
Any suggestions will be greatly appreciated.
Here's brief outline of client side solution (w/o post-back). Use html radio-buttons along with a hidden field to store the correct answer. Attach click event handlers on radio-buttons to match the value with the value from hidden field.
Repeater Mark-up:
<tr>
<td colspan="2"><%# Container.DataItem("QuestionText")%></td>
</tr>
<tr>
<td class="answerContainer">
<input type="radio" class="option" name='answer_<%# Container.ItemIndex %>' value="1">True
<input type="radio" class="option" name='answer_<%# Container.ItemIndex %>' value="0">False
<input type="hidden" id="correct_answer" value='<%#Container.DataItem("CorrectAnswer") %>' />
</td>
<td>
<span class="result" />
</td>
</tr>
Java-script (using jquery):
$(document).ready(function() {
$('td.answerContainer .option').click(function() {
var opt = $(this);
var correctAns = opt.next('#correct_answer');
var result = (opt.val() == correctAns.val()) ? "Correct" : "Incorrect";
opt.parent().next('td').find('.result').html(result);
});
});
Disclaimer: untested code
Note that radio button names are suffixed with the item index so that on the server side, you can read the user's answers by looking into the request (for example, value of Request["answer_1"] should tell user selected answer for second question -> "1" : True, "0": False and empty string: no selection).
The obvious disadvantage is that correct answer is stored in the html and so it will be simpler to cheat the system. Solution can be to make ajax call to the server to check if the answer is correct or not - this will need creating salted time-bound pseudo-random tokens to identify questions (otherwise user can make same ajax calls to get answers).
Cut your RadioButton code from repeater somewhere outside repeater, go to Design view and click on that RadioButton (now it's not included in repeater and you can assign event handler to it without typing any code manually).
When you select this RadioButton in DesignView, click events button in your proporties tab and click OnSelectedIndexChanged and this will auto generate eventhandler function. You have to enable autopostback on this radiobutton (arrow in top right corner of control - in Design view).
Now cut back this RadioButton and place it inside your repeater. Now every radiobutton change will cause calling generated handler function where you can cast sender object to RadioButton, and you can access its value with SelectedValue property.
I've tried this solution many times, but only in C# so I am sorry if something is different in VB.NET
You can't use Function as an event handler. It must be a sub which takes two argument.
Take a look at this sample.
Markup
<asp:Repeater runat="server" ID="rptQuestions">
<HeaderTemplate><table width="100%"></HeaderTemplate>
<ItemTemplate>
<tr>
<td colspan="2"><%# Eval("Name")%></td>
</tr>
<tr>
<td>
<asp:RadioButtonList runat="server"
ID="rblAnswerSelection"
RepeatDirection="Horizontal"
AutoPostBack="true"
OnSelectedIndexChanged="CheckAnswer">
<asp:ListItem Text="True" Value="1"></asp:ListItem>
<asp:ListItem Text="False" Value="0"></asp:ListItem>
</asp:RadioButtonList>
<asp:Label runat="server"
ID="lblCorrectAnswer"
Text='<%#Eval("CorrectAnswer") %>'>
</asp:Label>
</td>
<td><asp:Label runat="server" ID="lblResult"></asp:Label></td>
</tr>
</ItemTemplate>
<FooterTemplate></table></FooterTemplate>
</asp:Repeater>
Code-behind
Public Class Data
Public Property QuestionText As String
Public Property CorrectAnswer As String
End Class
Dim lst As List(Of Data)
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
lst = New List(Of Data)
lst.Add(New Data() With {.QuestionText = "A", .CorrectAnswer = "True"})
lst.Add(New Data() With {.QuestionText = "B", .CorrectAnswer = "False"})
lst.Add(New Data() With {.QuestionText = "C", .CorrectAnswer = "True"})
rptQuestions.DataSource = lst
rptQuestions.DataBind()
End If
End Sub
Protected Sub CheckAnswer(sender As Object, e As System.EventArgs)
Dim rad As RadioButtonList = DirectCast(sender, RadioButtonList)
Dim item As RepeaterItem = DirectCast(rad.Parent, RepeaterItem)
Dim correctAns As Label = DirectCast(item.FindControl("lblCorrectAnswer"), Label)
Dim result As Label = DirectCast(item.FindControl("lblResult"), Label)
Dim SelectedAnswer As String = rad.SelectedItem.Text
If correctAns.Text = SelectedAnswer Then
result.Text = "Correct"
Else
result.Text = "Incorrect"
End If
End Sub

How to add asyncPostBackTrigger to Template column, Item Template, Button in DataGrid

I need to add a trigger for two buttons in DataGrid Template columns. I have found a couple postings saying to put the code in the code-behind using the UniqueID.
Something isn't right with my logic (or maybe it isn't in the right place). I am getting "Object reference not set to an instance of an object" error when I run it.
I am getting this on my "gridSelectTrigger.ControlID = btnSessionSelect.UniqueID" statement.
Does this logic need to be in an "ItemDataBound" event? Or is my logic wrong?
<%# Page Title="Admin Session Folders" Language="VB" MasterPageFile="~/MasterPage.master" AutoEventWireup="false" CodeFile="AdminAddEditReleaseAndFiles.aspx.vb" Inherits="AdminAddEditReleaseAndFiles" Theme="Standard" %>
<asp:Panel ID="pnlEditTopic" runat="server" CssClass="modalPopupEditTopic" Style="display: none;" >
<table cellspacing="0" class="borderTable0" width="100%" style="">
<tr style="height:4px">
<td colspan="6" align="center">
<asp:ImageButton ID="btnAddTopic" runat="server" AlternateText="Add Topic"
ImageUrl="~/App_Themes/Common/images/BtnApply.jpg" Height="28px">
</asp:ImageButton>
<asp:ImageButton ID="btnUpdateTopic" runat="server" AlternateText="Update Topic"
ImageUrl="~/App_Themes/Common/images/BtnApply.jpg" Height="28px">
</asp:ImageButton>
<asp:ImageButton ID="btnDeleteTopic" runat="server" AlternateText="Delete Topic"
ImageUrl="~/App_Themes/Common/images/BtnDelete.jpg" Height="28px">
</asp:ImageButton>
<asp:ImageButton ID="btnEditTopicClose" runat="server" AlternateText="Close Edit Topic Popup"
ImageUrl="~/App_Themes/Common/images/BtnCancel.jpg" Height="28px">
</asp:ImageButton>
</td>
</tr>
</table>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
If Not (IsPostBack) Then
Dim MainContent As ContentPlaceHolder = TryCast(Page.Master.FindControl("ContentPlaceHolder1"), ContentPlaceHolder)
Dim UpdatePanelSessions As UpdatePanel = TryCast(MainContent.FindControl("UpdatePanelSessions"), UpdatePanel)
Dim btnSessionSelect As Button = TryCast(UpdatePanelSessions.FindControl("btnSessionSelect"), Button)
Dim btnSessionDetail As Button = TryCast(UpdatePanelSessions.FindControl("btnSessionDetail"), Button)
Dim gridSelectTrigger As AsyncPostBackTrigger = New AsyncPostBackTrigger
Dim gridDetailTrigger As AsyncPostBackTrigger = New AsyncPostBackTrigger
gridSelectTrigger.ControlID = btnSessionSelect.UniqueID
gridSelectTrigger.EventName = "Click"
UpdatePanelSessions.Triggers.Add(gridSelectTrigger)
gridDetailTrigger.ControlID = btnSessionDetail.UniqueID
gridDetailTrigger.EventName = "Click"
UpdatePanelSessions.Triggers.Add(gridDetailTrigger)
End If
End Sub
Thank you,
James
Got it. The update panel needed children as triggers set to true.

Resources