ASP.NET Timer results in an updatepanel gives full postback - c#

I have a quite strange situation where I have the following code:
<asp:Timer ID="GameClock" runat="server" Interval="5000" Enabled="true"
ontick="GameClock_Tick">
</asp:Timer>
<asp:UpdatePanel ID="ItemsUpdatePanel" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="false">
<Triggers>
NOTE THE TRIGGER IS COMMENTED OUT
<%--<asp:AsyncPostBackTrigger ControlID="GameClock" EventName="Tick" />--%>
</Triggers>
<ContentTemplate>
<asp:ListView ID="PlayerItems" runat="server" GroupItemCount="7"
onitemdatabound="PlayerItems_ItemDataBound">
<LayoutTemplate>
<table border="1" cellpadding="2" cellspacing="0" runat="server" id="tblProducts">
<tr runat="server" id="groupPlaceholder">
</tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<td id="Td1" runat="server" style="vertical-align:top; text-align:left; height:100%;">
<div>
<div id="category" runat="server">
<asp:Panel ID="ItemPanel" runat="server">
</asp:Panel>
</div>
</div>
</td>
</ItemTemplate>
<GroupTemplate>
<tr runat="server" id="productRow">
<td runat="server" id="itemPlaceholder"></td>
</tr>
</GroupTemplate>
</asp:ListView>
</ContentTemplate>
</asp:UpdatePanel>
This gives a quite strange result: Every 5s my whole page gives a full postback. When I comment in (activate) the asyncpostbacktrigger, the updatepanel does not give a full postback.
In the PlayerItems_ItemDataBound I have the following code (which, I do think, do not matter):
protected void PlayerItems_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
ListViewDataItem dataItem = e.Item as ListViewDataItem;
if (dataItem != null)
{
BaseItem myItem = dataItem.DataItem as BaseItem;
Panel itemPanel = new Panel();
Literal firstLiteral = new Literal();
firstLiteral.Text += "<div id='smoothmenu1' class='ddsmoothmenu'>";
firstLiteral.Text += "<ul>";
firstLiteral.Text += "<li><img src='Images/Game/Items/" + myItem.ItemImageUrl + "' />";
firstLiteral.Text += "<ul>";
// Add all events bound to item into contextmenu
itemPanel.Controls.Add(firstLiteral);
foreach (Delegate del in myItem.Actions.Items)
{
Literal firstItLit = new Literal();
firstItLit.Text += "<li>";
itemPanel.Controls.Add(firstItLit);
MethodInfo methodInfo = del.Method;
string commandName = myItem.ItemId + "|" + methodInfo.Name;
LinkButton btn = new LinkButton();
btn.Text = methodInfo.Name;
btn.Click += new EventHandler(btn_Click);
btn.CommandName = commandName;
itemPanel.Controls.Add(btn);
Literal secondItLit = new Literal();
secondItLit.Text += "</li>";
itemPanel.Controls.Add(secondItLit);
}
Literal btnLiteral = new Literal();
btnLiteral.Text += "</ul>";
btnLiteral.Text += "</li>";
btnLiteral.Text += "</ul>";
btnLiteral.Text += "</div>";
itemPanel.Controls.Add(btnLiteral);
Panel panel = (Panel)(e.Item.FindControl("ItemPanel"));
panel.Controls.Add(itemPanel);
}
}
}
When I create a NEW updatepanel, ItemsUpdatePanel1, it does not fire a full postback without the timer.
I can even start copying items from ItemsUpdatePanel to ItemsUpdatePanel1, and suddenly the full postbacks happen. I tried 2 seperate times, and they started happening at different times!!!
Could anyone please enlighten me? I simply want the UpdatePanel NOT to give a full postback, even without a timer.
Thanks!:)

I found the solution (or, I asked on ASP.NET and found it):
http://forums.asp.net/p/1644391/4262140.aspx#4262140
The wrapping solution worked really good.

Was this project upgraded from ASP.NET 1.1? If so, check your web.config file and remove the xhtmlConformance tag from it. I forget all the specifics, but having that tag in your web.config will cause that to happen, and is there by default in .NET 1.1 web applications.

Related

Dynamically create ASPxButtons

I want to create a download list where each available file has its own ASPxButton and I would like to dynamically create them rather than creating like 30 manually and dynamically setting them to visible.
Since I don't have a form within my .aspx.cs file but create my buttons within a table in my .aspx code, I can't use the form.AddButton method. Any ideas on how to do something like that?
Not sure if that helps but here is the code for the 2 buttons I already have:
<dx:TabPage Name="Downloads" Text="Downloads" Enabled="false">
<ContentCollection>
<dx:ContentControl runat="server">
<table class="grid_centered">
<tr>
<td>
<dx:ASPxButton ID="btnDownload0" runat="server" Text="Anschreiben" Theme="Metropolis" CssClass="button centered" OnClick="btn_Click" Width="300px"></dx:ASPxButton>
</td>
</tr>
<tr>
<td>
<dx:ASPxButton ID="btnDownload1" runat="server" Text="Serie 1" Theme="Metropolis" CssClass="button centered" OnClick="btn_Click" Width="300px" Visible="false" Enabled="false"></dx:ASPxButton>
</td>
</tr>
</table>
</dx:ContentControl>
</ContentCollection>
</dx:TabPage>
The solution to this is to use an asp:Repeater. This way, I only have to write the details for one and use the OnItemCommand event to handle button clicks. I had to switch to using asp:Button instead of dx:ASPxButton, though since I needed the CommandName field to pass the info which button was pressed along to my event handler.
<asp:Repeater
ID="MyRepeater"
runat="server"
DataSourceID="MyDataSource"
OnItemCommmand="MyClickedEventHandler">
<ItemTemplate>
<asp:Button
ID="MyButton"
runat="server"
Text="Download"
CommandName='<%# $"{Eval("keyField")}" %>' />
</ItemTemplate>
</asp:Repeater>
I am not too familiar with dx:ASPxButton but I am assuming it would be similar to an aspx:Button. To dynamically create controls you have to create the controls in the Page_Load() event.
protected void Page_Load()
{
//get your files
string targetDirectory = "your directory";
string [] fileEntries = Directory.GetFiles(targetDirectory);
int i = 0;
foreach(string fileName in fileEntries)
{
ASPxButton btn = new Button();
btn.Text = fileName;
btn.ID = "btnDownload" + i.ToString();
btn.CssClass = "button centered";
btn.Attributes.Add("Theme", "Metropolis");
//add any other properties you need
//add the event handler
btn.Click += new EvenHandler(btn_Clik);
form.AddButton(btn);
}
}

ASP.NET passing a function return value from a modalpopupextender to the main form

I have looked at a number of solutions to my basic issue, but have not found any solution that I either understand or that would work.
I have a page that takes in two items of information, filename and a store. The user then clicks on a button to execute a function that will update a database and send back a resulting string that I want to display on a textbox on the main form.
However, when they press the button I call a modalpopupextender using an UpdatePanel panel. That gets a value into the modalpopup. If the user validates that the correct store is selected they click an 'okay' button which then call the dbprocessing function that returns a result. The page is small so I'll give the complete aspx and c# code.
The function doProcess() returns a List of values which I convert to String for display. I left the session variables in for that was my last attempt at trying to get this to work.
Where I am confused is that when the first button on the main form (Process) is clicked, there is a postback which obviously hits the page load before the button click. That is when I display the popup. Then when the user clicks on the button Okay, another postback is perform hitting page load before the button click and in that second button I originally tried to set the textbox on the main page because there is no other action after the second click, but no data displayed.
What is strange, if I repeat the process, when I click to display the popup, my data displays. This is not making sense.
This is the aspx page
<%# Page Title="Product Rank Loader" Language="C#" MasterPageFile="~/OMnested.master" AutoEventWireup="true" CodeBehind="ProductRankLoader.aspx.cs" Inherits="OrderManager.ProductRankLoader" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajax" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<script type="text/javascript" src="Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="Scripts/local.js"></script>
<script type="text/javascript">
function callme(thisone)
{
$("#ddlStores").prop('disabled', false);
}
</script>
<div>
<table style="width: 500px">
<tr>
<td>
<asp:Label ID="lblMessage" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td>
<asp:FileUpload ID="fulRanks" runat="server" Width="315px" />
</td>
</tr>
<tr>
<td>
<asp:DropDownList ID="ddlStores" runat="server" Height="16px" Width="155px">
<asp:ListItem Value="0">Select Store</asp:ListItem>
<asp:ListItem Value="10101">Parkseed</asp:ListItem>
<asp:ListItem Value="10151">Wayside</asp:ListItem>
<asp:ListItem Value="10201">Jackson (JP)</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td style="height: 20px; padding-top: 15px; padding-bottom: 15px; padding-left: 20px;">
<asp:Button ID="btnProcess" runat="server" Text="Process" Width="89px" OnClick="btnProcess_Click" />
</td>
</tr>
<tr>
<td>
**<asp:TextBox ID="txtResults" runat="server" Height="200px" ReadOnly="True" TextMode="MultiLine"></asp:TextBox>**
</td>
</tr>
</table>
<asp:HiddenField ID="hdnFilename" runat="server" />
</div>
<asp:UpdatePanel id="updVerifyChoice" runat="server">
<ContentTemplate>
<div style="display: none;">
<asp:Button ID="btnDummy" UseSubmitBehavior="true" OnClientClick="ShowModalPopup" OnClick="btnDummy_Click" runat="server" />
<%--Dummy Button added to assign the target controlid of PopupExtender--%>
<asp:Button ID="btnDummyButton" UseSubmitBehavior="true" runat="server" Text="DummyButton" Style="display: none;" />
</div>
<asp:Panel ID="pnlVerifyRequestPopup" runat="server">
<div style="background: #fff; padding-left: 3px; border: 1px solid #989898; border-top: 1px solid #989898 !important;">
<table style="background-color: #F7F5F4; width: 300px;">
<tr>
<td><label>Verify Process Request</label></td>
<td style="text-align: right;">
<label class="lbl_3">
<asp:LinkButton ID="lBtnVerifyRequestClose" CssClass="lnkCloseheaderedit" Text="Cancel"
runat="server" OnClick="lBtnBillUpdPopClose_Click" /></label>
</td>
</tr>
<tr>
<td style="width: 150px;" colspan="2">
<asp:Label ID="lblWarn" runat="server" Text="" Font-Size="Medium" ForeColor="#CC3300"></asp:Label>
</td>
</tr>
<tr>
<td colspan="2" class="align_right">
<asp:Button ID="btnPopVerify" runat="server" CssClass="order_searchbtn" Text="Okay"
OnClick="btnPopVerify_Click" />
</td>
</tr>
</table>
<asp:HiddenField ID="hdnReturnData" runat="server" />
</div>
</asp:Panel>
<ajax:ModalPopupExtender ID="extVerifyProcess" runat="server" BehaviorID="extndPopBillUpdBehId"
TargetControlID="btnDummyButton" PopupControlID="pnlVerifyRequestPopup" CancelControlID="lBtnVerifyRequestClose">
</ajax:ModalPopupExtender>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Content>
The field in question that should get the returned values from the function is called txtResults.
Here is the c# code (I cut out unneeded code)
namespace OrderManager
{
public partial class ProductRankLoader : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var currentUser = Request.LogonUserIdentity.Name.Split('\\')[1];
// Session.Add("returnText", "");
var header = Master.FindControl("lblpageheading") as Label;
header.Text = "Product Rank Loader";
if (IsPostBack)
{
try
{
//if (Session["Verified"].ToString() != "")
//{
Session["returnText"] = doProcess();
if (Session["returnText"].ToString() != "")
{
txtResults.Text = Session["returnText"].ToString();
lblMessage.Text = "";
}
//}
}
catch { }
} else
{
Session.Add("returnText", "");
Session.Add("Verified", "");
}
}
protected void btnProcess_Click(object sender, EventArgs e)
{
Boolean fileOK = false;
string filename = Path.GetFileName(fulRanks.FileName);
hdnFilename.Value = filename;
if (fulRanks.HasFile)
{
ddlStores.Enabled = true;
String fileExtension =
System.IO.Path.GetExtension(fulRanks.FileName).ToLower();
String[] allowedExtensions = { ".txt", ".log" };
for (int i = 0; i < allowedExtensions.Length; i++)
{
if (fileExtension == allowedExtensions[i])
{
fileOK = true;
fulRanks.SaveAs(#"c:\temp\" + filename);
}
}
}
if (!fileOK || ddlStores.SelectedIndex <= 0)
{
lblMessage.Text = "Either the file name is incorrect or a store has not been selected.";
return;
} else { }
lblWarn.Text = "You are going to update item Ranks for store <br />" + ddlStores.SelectedItem + ".<br /><br />Press 'Okay' to process";
Session.Add("Verified", "true");
extVerifyProcess.Show();
}
protected void lBtnBillUpdPopClose_Click(object sender, EventArgs e)
{
Session["Verified"] = "";
Session["returnText"] = "";
Response.Redirect("ProductRankLoader.aspx");
}
protected void btnPopVerify_Click(object sender, EventArgs e)
{
//Session["returnText"] = doProcess();
Session.Remove("returnText");
Session.Remove("Verified");
}
private string doProcess()
{
string tmpResults = "";
Int32 store = 0;
if (ddlStores.SelectedIndex > 0)
{
Int32.TryParse(ddlStores.SelectedValue.ToString(), out store);
string filename = hdnFilename.Value;
ProductRankLoaderDLL.ProductRankLoaderDLL newRanks = new ProductRankLoaderDLL.ProductRankLoaderDLL(xxx);
List<string> results = newRanks.ProcessRanks();
foreach (string result in results)
{
tmpResults += result + '\r';
}
// txtResults.Text = tmpResults;
lblMessage.Text = "";
}
else
{
lblMessage.Text = "";
}
return tmpResults;
}
protected void btnDummy_Click(object sender, EventArgs e)
{
}
}
}
If I don't misunderstand your request your problem is caused by the postbacks. I think you can handle better your logic with jquery. For example you can use jquery to close the popup without performing postback:
$('#lBtnVerifyRequestClose').click(function (event) {
event.preventDefault();
$('#pnlVerifyRequestPopup').dialog('close');
});
the event.preventDefault() ensure that postback are not executed.
If you need server logic to put data on your popup you can bind a jquery function to the dialog on open event and retrieve there data / perform your logic. In this way your form will be submitted to the server only once at the end of the process.

Target accordion pane content template after databind so that I can load data on demand?

I have an accordion that has another accordion inside one of its panes. This inner accordion is created using a datasource so each of its panes are loaded from a list of objects. In this particular case, this datasource is also loaded on demand. Now, where I'm stuck is that I want to be able to load the pane headers only and then load the contents when the pane is clicked; similar to what I have in the outer pane. The reason I'm confused here, is because the lazy load happens when the pane is clicked, but since this happens AFTER the databind, I don't know how to reference the content of the pane that invokes the ItemCommand. Not sure if that makes sense. Here is the inner accordion:
<ajaxToolkit:Accordion runat="server" ID="accReviewers" OnItemDataBound="accOuterAccordion_ItemDataBound" ContentCssClass="ReviewerContent" RequireOpenedPane="False" SelectedIndex="-1" OnItemCommand="accReviewers_ItemCommand">
<HeaderTemplate>
<div>
<asp:LinkButton Text='<%#Eval("Header") %>' CssClass="InReviewHeader" runat="server"
CommandName="LoadReviewers" CommandArgument='<%#Eval("MocRequestId") %>'/>
</div>
</HeaderTemplate>
<ContentTemplate>
<div>
<asp:ListView runat="server" ID="lvReviewers" ItemPlaceholderID="phReviewer" OnItemDataBound="lvReviewers_ItemDataBound">
<LayoutTemplate>
<div>
<asp:HyperLink runat="server" ID="lnkGotoRequest" Text="View this request"/>
</div>
<asp:PlaceHolder runat="server" ID="phReviewer"/>
<div style="margin-top: 5px;">
<asp:Button runat="server" ID="btnResubmit" Text="Resubmit" CssClass="ResubmitInitial"/>
</div>
</LayoutTemplate>
<ItemTemplate>
<div class="ReviewerItem">
<%#Eval("Assignee.Name") %><br />
<img src="" alt="Reviewer" runat="server" ID="imgReviewer" width="75" style="border: 1px solid gray; border-radius: 6px;"/><br />
<asp:Label runat="server" ID="lblStatus" Text='<%#Eval("ReviewStatus") %>' />
<asp:HyperLink runat="server" ID="lnkRejectComment" CssClass="InitialRejectComment">(details)</asp:HyperLink>
</div>
</ItemTemplate>
</asp:ListView>
</div>
</ContentTemplate>
</ajaxToolkit:Accordion>
</Content>
</ajaxToolkit:AccordionPane>
As you can see, the accordion accReviewers is generated via a DataSource. The listview contained in the LayoutTemplate will not have its datasource bound until the LinkButton has been clicked, which will fire the item command. Also worth noting that this entire accordion is wrapped in an UpdatePanel.
This is the code behind I was starting to work with, but it doesn't appear to get the correct instance of the listview and while the list is not empty, it will not display anything:
protected void accReviewers_ItemCommand(object sender, CommandEventArgs e)
{
var mocId = int.Parse(e.CommandArgument.ToString());
var list = (sender as AjaxControlToolkit.Accordion).FindControl("lvReviewers") as ListView; //APPARENTLY WRONG
var reviewers = MocApi.GetReviews(mocId);
list.DataSource = reviewers;
list.DataBind();
}
So to recap, when the LinkButton within the HeaderTemplate is clicked, I need to somehow gain reference to the correct instance of the ListView so that I can bind its datasource. As always, any help or insight is appreciated. This is similar to a previous question of mine but is specific to gaining this reference after databind which seems a bit more complicated. TIA
UPDATE:
I found that I can bind the item datasource if I can somehow capture its index. I'm exploring trying to set that as a command argument during the databinding of the inner accordion.
I managed to solve this with some minor shenannigans:
Here is the markup:
<ItemTemplate>
<div class="ReviewerItem">
<%#Eval("Assignee.Name") %><br />
<div style="display: inline-block; position: relative;">
<img src="" alt="Reviewer" runat="server" ID="imgReviewer" width="75" style="border: 1px solid lightgray; border-radius: 6px; overflow: hidden;"/><br />
<div runat="server" ID="divYes" Visible="False">
<img src="../Images/Yes.png" alt="Approved" class="ApprovalIcon" />
</div>
<div runat="server" ID="divNo" Visible="False">
<img src="../Images/No.png" alt="Rejected" class="ApprovalIcon" id="imgNo" />
</div>
</div>
<asp:Label runat="server" ID="lblStatus" Text='<%#Eval("ReviewStatus") %>' />
<asp:HyperLink runat="server" ID="lnkRejectComment" CssClass="InitialRejectComment">(details)</asp:HyperLink>
<asp:Panel runat="server" ID="pnlDemoApproval" Visible="False" CssClass="DemoButtons">
<asp:Button runat="server" ID="btnApprove" Text="Approve" CommandArgument='<%#Eval("Assignee.Guid") + "|" + Eval("Ticketid") %>' CommandName="ApproveReview"/>
<asp:Button runat="server" ID="btnDeny" Text="Deny" CommandArgument='<%#Eval("Assignee.Guid") + "|" + Eval("Ticketid") %>' CommandName="DenyReview"/>
</asp:Panel>
<ajaxToolkit:BalloonPopupExtender runat="server" ID="balloon" BalloonPopupControlID="pnlPopup"
TargetControlID="lnkRejectComment" Position="TopRight" BalloonStyle="Cloud" BalloonSize="Medium" DisplayOnMouseOver="True"/>
<asp:Panel runat="server" ID="pnlPopup">Rejection Reason</asp:Panel>
</div>
</ItemTemplate>
On databind, I catch the item so that I can grab the index and set it to the CommandName for later use:
AjaxControlToolkit.AccordionItemEventArgs e)
{
if (e.ItemType != AjaxControlToolkit.AccordionItemType.Content) return;
var index = e.ItemIndex;
var button = e.AccordionItem.Parent.FindControl("lnkbHeader") as LinkButton;
if (button != null) button.CommandName = index.ToString();
}
Now that control contains the index, i can use that to target the correct pane and bind its datasource:
protected void accReviewers_ItemCommand(object sender, CommandEventArgs e)
{
//This seems stupid to put here, but for some reason the item command bypasses the listview catch and passes it to the accordion
if (e.CommandName == "ApproveReview")
{
var assigneeGuid = new Guid(e.CommandArgument.ToString().Split('|')[0]);
var ticketId = int.Parse(e.CommandArgument.ToString().Split('|')[1]);
var ticket = new MocApproval(ticketId);
DoDemoApproval(ticketId, assigneeGuid, true);
var approvalIndex = (sender as AjaxControlToolkit.Accordion).SelectedIndex;
var lv =
(sender as AjaxControlToolkit.Accordion).Panes[approvalIndex].FindControl("lvReviewers") as ListView;
lv.DataSource = MocApi.GetReviews(ticket.MocRequest);
lv.DataBind();
return;
}
if (e.CommandName == "DenyReview")
{
var assigneeGuid = new Guid(e.CommandArgument.ToString().Split('|')[0]);
var ticketId = int.Parse(e.CommandArgument.ToString().Split('|')[1]);
var ticket = new MocApproval(ticketId);
DoDemoApproval(ticketId, assigneeGuid, false);
var approvalIndex = (sender as AjaxControlToolkit.Accordion).SelectedIndex;
var lv =
(sender as AjaxControlToolkit.Accordion).Panes[approvalIndex].FindControl("lvReviewers") as ListView;
lv.DataSource = MocApi.GetReviews(ticket.MocRequest);
lv.DataBind();
return;
}
...

ASP.NET Repeater: Button in item template to redirect to another page

I have a repeater and each item contains a button which should redirect to another page and also pass a value in the query string.
I am not getting any errors, but when I click the button, the page just refreshes (so I am assuming a postback does occur) and does not redirect. I think that for some reason, it isn't recognizing the CommandName of the button.
Repeater code:
<asp:Repeater ID="MySponsoredChildrenList" runat="server" OnItemDataBound="MySponsoredChildrenList_ItemDataBound" OnItemCommand="MySponsoredChildrenList_ItemCommand">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<br />
<div id="OuterDiv">
<div id="InnerLeft">
<asp:Image ID="ProfilePic" runat="server" ImageUrl='<%#"~/Resources/Children Images/" + String.Format("{0}", Eval("Primary_Image")) %>'
Width='300px' Style="max-height: 500px" /></div>
<div id="InnerRight">
<asp:HiddenField ID="ChildID" runat="server" Value='<%# DataBinder.Eval(Container.DataItem, "Child_ID") %>'/>
<span style="font-size: 20px; font-weight:bold;"><%# DataBinder.Eval(Container.DataItem, "Name") %>
<%# DataBinder.Eval(Container.DataItem, "Surname") %></span>
<br /><br /><br />
What have you been up to?
<br /><br />
<span style="font-style:italic">"<%# DataBinder.Eval(Container.DataItem, "MostRecentUpdate")%>"</span>
<span style="font-weight:bold"> -<%# DataBinder.Eval(Container.DataItem, "Update_Date", "{0:dd/MM/yyyy}")%></span><br /><br /><br />Sponsored till:
<%# DataBinder.Eval(Container.DataItem, "End_Date", "{0:dd/MM/yyyy}")%>
<br /><br />
<asp:Button ID="ChildProfileButton" runat="server" Text="View Profile" CommandName="ViewProfile" />
</div>
</div>
<br />
</ItemTemplate>
<SeparatorTemplate>
<div id="SeparatorDiv">
</div>
</SeparatorTemplate>
</asp:Repeater>
C# Code behind:
protected void MySponsoredChildrenList_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
// Stuff to databind
Button myButton = (Button)e.Item.FindControl("ChildProfileButton");
myButton.CommandName = "ViewProfile"; }
}
protected void MySponsoredChildrenList_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "ViewProfile")
{
int ChildIDQuery = Convert.ToInt32(e.Item.FindControl("ChildID"));
Response.Redirect("~/ChildDescription.aspx?ID=" + ChildIDQuery);
}
}
I am new to using repeaters so it's probably just a rookie mistake. On a side note: is there a better way of obtaining the ChildID without using a hidden field?
EDIT: Using breakpoints; the ItemDatabound event handler is being hit, but the ItemCommand is not being entered at all
You need to set MySponsoredChildrenList_ItemDataBound as protected. Right now, you have just 'void' which by default is private, and is not accessible to the front aspx page.
Another way is to use the add event handler syntax from a function in your code behind, using the += operator.
Either way, the breakpoint will now be hit and our code should mwork.
EDIT: So the above solved the compilation error but the breakpoints are not being hit; I've ran some tests and am able to hit breakpoints like this:
Since I do not know how you are databinding, I just added this code to my code-behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
MySponsoredChildrenList.DataSource = new List<object>() { null };
MySponsoredChildrenList.DataBind();
}
}
Note: If you DataBind() and ItemDataBound() is called on every postback, it will wipe out the command argument, which is potentially what you are seeeing; so if you always see [object]_ItemDataBound() breakpoint hit, but never [object]_ItemCommand(), it is because you need to databind only on the initial page load, or after any major changes are made.
Note also the method MySponsoredChildrenList_ItemCommand doesn't work:
protected void MySponsoredChildrenList_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "ViewProfile")
{
int ChildIDQuery = Convert.ToInt32(e.Item.FindControl("ChildID"));
Response.Redirect("~/ChildDescription.aspx?ID=" + ChildIDQuery);
}
}
When you do FindControl, you need to cast to the correct control type, and also make sure to check for empty and null values before converting, or else you will possibly have errors:
protected void MySponsoredChildrenList_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "ViewProfile")
{
int childId = 0;
var hiddenField = e.Item.FindControl("ChildID") as HiddenField;
if (null != hiddenField)
{
if (!string.IsNullOrEmpty(hiddenField.Value))
{
childId = Convert.ToInt32(hiddenField.Value);
}
}
if (childId > 0)
{
Response.Redirect("~/ChildDescription.aspx?ID=" + childId);
}
}
}
Hope this helps - if not, please post additional code for the "full picture" of what is happening, so we can see where else you might have a problem.
I think on the repeater you need to add
OnItemDataBound="MySponsoredChildrenList_ItemDataBound"
Not 100% sure, but could be the same for the ItemCommand.
--
In regards to obtaining the ChildID. Add a CommandArgument to the button in the repeater, and set it in the same way, <% Eval("ChildID") %>. This can the be obtained using e.CommandArgument.
Try this.. Add an attribute to item row
row.Attributes["onclick"] = string.Format("window.location = '{0}';", ResolveClientUrl(string.Format("~/YourPage.aspx?userId={0}", e.Item.DataItem)) );
or You can do like this also
<ItemTemplate> <tr onmouseover="window.document.title = '<%# Eval("userId", "Click to navigate onto user {0} details page.") %>'" onclick='window.location = "<%# ResolveClientUrl( "~/YourPage.aspx?userId=" + Eval("userid") ) %>"'> <td> <%# Eval("UserId") %> </td> </tr> </ItemTemplate>

Page cycle question asp.net

I am using nested repeaters. I render several groups and every group has members that I need to render out different properties to.
I am using ItemDataBound on the nested repeater to find out which member the nested repeater is rendering out at the moment. I have <% %> tags in the .aspx which checks if the current user has a certain property, and if it has, I render the divs and other HTML elements that need to go there.
All the data is correct. When I debug I collect the correct data and I get the right info about who the user is and what properties the user has. I save the current evaluated user in a protected string currentRenderedUser that I use to find out who the user is in the aspx file.
The problem is that by the time the <% %> on the aspx gets evaluated the repeater has already gone through all the sets or something, because the currentRenderedUser is the same during every evalutaion in the aspx file.
I don't know the correct terminology for "<% %>" code in the aspx file, sorry.
This is the relevant parts of the aspx (I think):
<ItemTemplate>
<!-- nested repeater data -->
<tr>
<td width="50%"><div class="memberName"><%# DataBinder.Eval(Container.DataItem, "userEmail" )%></div></td>
<div style="display: none;"></div>
<% if (CheckIfUserIsAdmin(email, currentRenderedGroup))
{ %>
<%if (CheckIfUserIsAdmin(currentRenderedUser, currentRenderedGroup))
{ //Checks so that the user being rendered isn't already admin%>
<td><div style="margin-right:30px;" class="makeAdminButton"></div></td>
<% }
else
{%>
<td><div style="margin-right:30px;" class="makeAdminButton"><asp:ImageButton ID="ImageButtonMakeUserAdmin" CommandName="MakeAdmin" BorderWidth="0" ImageUrl="~/gfx/doAdmin.png" CommandArgument='<%#Convert.ToString(DataBinder.Eval(Container.DataItem, "userEmail" )) + " " + Convert.ToString(DataBinder.Eval(((RepeaterItem)Container.Parent.Parent).DataItem, "groupId"))%>' runat="server" AlternateText="Make admin" /></div></td>
<td><div class="removeUserButton"><asp:ImageButton ID="ImageButtonRemoveUserFromGroup" CommandName="RemoveUserFromGroup" BorderWidth="0" ImageUrl="~/gfx/can.png" CommandArgument='<%# Convert.ToString(DataBinder.Eval(Container.DataItem, "userEmail" )) + " " + Convert.ToString(DataBinder.Eval(((RepeaterItem)Container.Parent.Parent).DataItem, "groupId"))%>' runat="server" AlternateText="Delete" /></div></td>
<% } %>
<%}%>
</tr>
</ItemTemplate>
And this is the part of the back-end that evaluates the current user:
protected void NesterRepeater_ItemDataBound(object sender,
System.Web.UI.WebControls.RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem
|| e.Item.ItemType == ListItemType.Item)
{
DataRowView dataRowView = (DataRowView)e.Item.DataItem;
string memberInGroup = Convert.ToString(dataRowView["userEmail"]);
currentRenderedUser = memberInGroup;
}
}
How can I solve this in a better (or atleast, working) way?
Thanks
The problem is that the event ItemDataBound is executed first so you probably always get the value of the last record from the Repeater's DataSource if I'm not mistaken.
It is better to do it this way:
<ItemTemplate>
<tr>
<td width="50%"><div class="memberName"><%# DataBinder.Eval(Container.DataItem, "userEmail" )%></div></td>
<div style="display: none;"></div>
<asp:PlaceHolder ID="phNoAdmin" runat="server" Visible="false">
<td><div style="margin-right:30px;" class="makeAdminButton"></div></td>
</asp:PlaceHolder>
<asp:PlaceHolder ID="phAdmin" runat="server" Visible="false">
<td><div style="margin-right:30px;" class="makeAdminButton"><asp:ImageButton ID="ImageButtonMakeUserAdmin" CommandName="MakeAdmin" BorderWidth="0" ImageUrl="~/gfx/doAdmin.png" CommandArgument='<%#Convert.ToString(DataBinder.Eval(Container.DataItem, "userEmail" )) + " " + Convert.ToString(DataBinder.Eval(((RepeaterItem)Container.Parent.Parent).DataItem, "groupId"))%>' runat="server" AlternateText="Make admin" /></div></td>
<td><div class="removeUserButton"><asp:ImageButton ID="ImageButtonRemoveUserFromGroup" CommandName="RemoveUserFromGroup" BorderWidth="0" ImageUrl="~/gfx/can.png" CommandArgument='<%# Convert.ToString(DataBinder.Eval(Container.DataItem, "userEmail" )) + " " + Convert.ToString(DataBinder.Eval(((RepeaterItem)Container.Parent.Parent).DataItem, "groupId"))%>' runat="server" AlternateText="Delete" /></div></td>
</asp:PlaceHolder>
</tr>
</ItemTemplate>
And the code behind:
protected void NesterRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
DataRowView dataRowView = (DataRowView)e.Item.DataItem;
PlaceHolder phNoAdmin = e.Item.FindControl("phNoAdmin") as PlaceHolder;
PlaceHolder phAdmin = e.Item.FindControl("phAdmin") as PlaceHolder;
string memberInGroup = Convert.ToString(dataRowView["userEmail"]);
currentRenderedUser = memberInGroup;
if (CheckIfUserIsAdmin(email, currentRenderedGroup))
{
if (CheckIfUserIsAdmin(currentRenderedUser, currentRenderedGroup))
{
phNoAdmin.Visible = true;
phAdmin.Visible = false;
}
else
{
phNoAdmin.Visible = false;
phAdmin.Visible = true;
}
}
}
}
It would be better if you bind the data inside the 2 PlaceHolder control I wrote also in code behind for maintainability reason.
HTH

Categories