I have a nested Repeater control in the ItemTemplate of another Repeater. I want to dynamically add a delete and update button to certain items in the nested Repeater depending on their data value, in this case whether they're associated with the current user. A click to either button should handled server-side based so the data source can be updated, the nested repeater re-bound and an Update Panel that contains both repeaters would be updated.
<asp:Repeater ID="rpProCom" runat="server">
<HeaderTemplate><div class="comment"></HeaderTemplate>
<ItemTemplate>
<div class="c-score"><%# Eval("Text") %></div>
<asp:UpdatePanel ID="upOut" runat="server" ChildrenAsTriggers="true" UpdateMode="Always" >
<ContentTemplate>
<asp:Repeater ID="rpVotes" runat="server" DataSource='<%# ((ScoreBoard.Score)Container.DataItem).Votes %>' OnItemDataBound="rpVotes_ItemDataBound">
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
<li>
<div class="c-ctrl"><asp:PlaceHolder ID="phD" runat="server" /></div>
<div class="c-box"><!-- placeholder for more tools --></div>
<div class="c-i"><div runat="server" ID="imgCom" class='<%# Eval("ImgClass") %>' /></div>
<div class="c-head">
<strong><%# Eval("UserName") %></strong>
<br /><%# Eval("Dt")%>
</div>
<div class="c-body"><%# Eval("Comment") %></div>
</li></ItemTemplate><FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</ContentTemplate></asp:UpdatePanel>
</ItemTemplate>
<FooterTemplate></div></FooterTemplate>
</asp:Repeater>
The outer repeater is bound in Page_Init
protected void rpVotes_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
if (((Vote)e.Item.DataItem).UserName == user.UserName){
LinkButton btn = new LinkButton();
btn.Text = "delete";
btn.CommandName = "delCom";
btn.CommandArgument = ((Vote)e.Item.DataItem).ID.ToString();
btn.Click += new EventHandler(DeleteComment);
btn.ID = "d" + ((Vote)e.Item.DataItem).ID.ToString();
//find contrl
e.Item.FindControl("phD").Controls.Add(btn);
}
}
}
Since the Button is created on item databound and is nested within another control, I can't think of a reasonable way to persist the button and the unique identifier of the Data Item in Viewstate so I can recreate the button(s) on PageInit postback in order to fire the button's Click event.
I tried using Command Arguments, but they are empty:
javascript:__doPostBack('ctl00$CPHRight$rpProCom$ctl02$rpVotes$ctl01$d21','')
I need a reference to the containing Repeater and a unique identifier for the item in the repeater so I can update the DB and rebind that Repeater (ideally in an UpdatePanel that encompasses just that Repeater). I know this is a classic problem, and I'm sure someone's solved it.
So basically, is there some way to force a command argument into a dynamically control created dynamically during ItemDataBound or otherwise identify which dynamically created button caused postback? Can I put and Update Panel in a Repeater? Also can I possibly use the word dynamically again in this post?
You can use dynamically as much as you want :-)
What I would recommend is declaring a static button, adding an itemdatabound event, and showing/hiding the button instead by setting the Visible property of it; that way, you won't have to concern yourself with the reloading issues, but the user won't be able to see the buttons they don't have permissions for.
HTH.
Related
I'm sure there's a really simple explanation for this but I've been tearing my hair out too long now so I appeal to SO for the sake of my sanity!
It's this simple: I have a ListView which is bound when the page first loads (and not again on postback). It's part of a form. On the first load I see the list of items but when I postback I see the EmptyDataTemplate. Is this correct behaviour? I'm sure that ListView as a data binding control should persist its list over postbacks. Here's the code, first front end:
<asp:ListView ID="boxes" runat="server" ItemType="Model.Generic.ILookupEntity<int>" EnableViewState="true">
<LayoutTemplate>
<div>
<ul class="contact-list checkbox-row">
<li id="itemPlaceholder" runat="server" />
</ul>
</div>
</LayoutTemplate>
<ItemTemplate>
<li>
<label>
<asp:CheckBox ID="cb" runat="server" />
<asp:HiddenField ID="value" runat="server" Value="<%# Item.Key %>" />
<span><%# Item.Value %></span>
</label>
</li>
</ItemTemplate>
<EmptyDataTemplate>
<p>No data</p>
</EmptyDataTemplate>
</asp:ListView>
<asp:CheckBoxList ID="boxtemp" runat="server" />
Then back end:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!IsPostBack)
{
var items = new List<Model.Generic.LookupEntity<int>>()
{
new Model.Generic.LookupEntity<int>(1, "One"),
new Model.Generic.LookupEntity<int>(2, "Two"),
new Model.Generic.LookupEntity<int>(3, "Three"),
new Model.Generic.LookupEntity<int>(4, "Four"),
};
boxes.DataSource = items;
boxes.DataBind();
boxtemp.DataSource = items;
boxtemp.DataTextField = "Value";
boxtemp.DataValueField = "Key";
boxtemp.DataBind();
}
}
I've added the boxtemp CheckBoxList as a test. This one retains its data on postback. But the ListView doesn't. What am I doing wrong here?
UPDATE 1
What's even weirder is that if I add the following code and debug, the variable test references the value 4 even on postback. But when the posted page is rendered I still see the EmptyItemTemplate.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
var test = boxes.Items.Count;
}
UPDATE 2
Having had it confirmed that this is not expected behaviour I have now found the cause I think. The ListView is inside a user control which is calling this.DataBind() on PreRender. I presume this is causing all data bound controls inside to re-bind on postback. The weird thing is that if I handle the ListView's OnDataBinding and OnDataBound events, on post back I can observe that the list still contains 4 items during both events. But is still rendered displaying the EmptyDataTemplate. Given this scenario, and assuming that the parent control's DataBind call is required, can anyone suggest the best resolution?
I have a control image in a user control. And I'm using a repeater to create several images list.
I have a button outside from the user control to delete image (per images).
I want to know, how can I make references to an specific row when I click in the button to delete the image.
This is the repetear:
<asp:Repeater ID="ImageRepeater" runat="server"
onitemcommand="ImageRepeater_ItemCommand">
<ItemTemplate>
<div>
<uc1:IVT_DisplayImage ID="IVT_DisplayImage1" runat="server" ImageURL="<%# Container.DataItem %>" />
<asp:Button ID="RemoveDiplayImage" Text="Remove" runat="server"
CommandName="delete"
/>
</div>
</ItemTemplate>
</asp:Repeater>
This is the event ItemCommand:
protected void ImageRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "delete")
{
//????
}
}
I want to know, how identify by code wich row (user control) I'm selecting.
You need to add CommandArgument to your button like CommandArgument="<%# Container.ItemIndex %>".
This way, in the code; e.CommandArgument gives you the item number, with which you can get the item that you want.
Note: In fact instead of specifying ItemIndex as CommandArgument, you can use any Primary Key (Unique Identifier) from the DataSource that you bind to the repeater from where you will be able to get hold of the record directly from the list object (DataSource).
In asp.net I have a table in database containing questions,date of submission and answers.On page load only questions appear.now i want to use any link which on clicking show answers and date specified in table data, either in textbox or label and clicking again on that link answer disappear again like expand and shrink on click.
So what coding should i use for this in C#?
I believe you could handle the ItemCommand event of the Repeater.
Place a LinkButton control for the link that you want the user to click in the Repeater's item template. Set the CommandName property of this to something meaningful, like "ShowAnswers". Also, add a Label or TextBox control into the Repeater's item template, but set their Visible property to false within the aspx markup.
In the code-behind, within the ItemCommand event handler check if the value of e.CommandName equals your command ("ShowAnswers"). If so, then find the Label or TextBox controls for the answers and date within that Repeater item (accessed via e.Item). When you find them, set their Visible property to true.
Note: you could take a different approach using AJAX to provide a more seamless experience for the user, but this way is probably simpler to implement initially.
I think the implementation would look something like this. Disclaimer: I haven't tested this code.
Code-Behind:
void Repeater_ItemCommand(Object Sender, RepeaterCommandEventArgs e)
{
if (e.CommandName == "ShowAnswers")
{
Control control;
control = e.Item.FindControl("Answers");
if (control != null)
control.Visible = true;
control = e.Item.FindControl("Date");
if (control != null)
control.Visible = true;
}
}
ASPX Markup:
<asp:Repeater id="Repeater" runat="server" OnItemCommand="Repeater_ItemCommand">
<ItemTemplate>
<asp:LinkButton id="ShowAnswers" runat="server" CommandName="ShowAnswers" />
<asp:Label id="Answers" runat="server" Text='<%# Eval("Answers") %>' Visible="false" />
<asp:Label id="Date" runat="server" Text='<%# Eval("Date") %>' Visible="false" />
</ItemTemplate>
</asp:Repeater>
<asp:Repeater ID="Cartridges" runat="server" onitemcommand="Cartridges_ItemCommand">
<ItemTemplate>
<p class="cartqty">QTY <asp:TextBox ID="cartQty" Text="0" runat="server"></asp:TextBox></p>
<div class="cartbuy2"><asp:LinkButton ID="buy" runat="server" CommandName="AddtoCart" CommandArgument='<%#Eval("cartID") %>' Text="Buy"></asp:LinkButton></div>
</ItemTemplate>
</asp:Repeater>
Why does the TextBox cartQty only return the default value of 0 rather than the value entered and submitted? If I change the value to 3 it submits 3 regardless of what's typed.
Here's the codebehind for cartQty
LinkButton lb = (LinkButton)e.CommandSource;
int varCartQty = Convert.ToInt32(((TextBox)lb.Parent.FindControl("cartQty")).Text);
Thank you ;-)
I can only guess:
You are binding the Repeater to it's DataSource on every postback but not only if(!Page.IsPostBack)
I doubt your repeater is rebinded. When you click the button your page_load event is called before your click handler, where your repeater is binded.
So you need to take care of that.
if(!IsPostBack)
{
//Put repeater binding code here
}
I need to display a control consistently across a set of pages. So I'm using a MasterPage to do that in ASP.NET/C#. However I also need to programmatically access this control, mostly provide options to view/hide depending on whether the controls checkbox is clicked.
Here is the Source for the MasterPage
<div id="verifyInitial" runat="server">
<asp:CheckBox ID="chkInitialVerify" runat="server"
oncheckedchanged="chkInitialVerify_CheckedChanged" />
I agree that my initial data is correct.
</div>
<div id="verifyContinuous" runat="server">
<asp:CheckBox ID="chkContinuousVerify" runat="server"
oncheckedchanged="chkContinuousVerify_CheckedChanged" />
I agree that my continuous data is correct
</div>
Now in the code behind I want to perform the following operations. Basically if a person clicks on the checkbox for the initial div box, then the initial box disappears and the continous box shows up. However it seems that the code behind for the MasterPage does not activate whenver I click on the checkbox. Is that just the way MasterPages are designed? I always thought you could do add some sort of control functionality beyond utilizing the Page Load on the Master Page.
protected void chkInitialVerify_CheckedChanged(object sender, EventArgs e)
{
verifyContinuous.Visible = true;
verifyInitial.Visible = false;
}
protected void chkContinuousVerify_CheckedChanged(object sender, EventArgs e)
{
verifyContinuous.Visible = false;
}
If you're expecting the two controls to trigger a change for that page immediately then you'll need to set the AutoPostBack property to true for both of them:
<div id="verifyInitial" runat="server">
<asp:CheckBox ID="chkInitialVerify" runat="server" oncheckedchanged="chkInitialVerify_CheckedChanged" AutoPostBack="true" />
I agree that my initial data is correct.
</div>
<div id="verifyContinuous" runat="server">
<asp:CheckBox ID="chkContinuousVerify" runat="server" oncheckedchanged="chkContinuousVerify_CheckedChanged" AutoPostBack="true" />
I agree that my continuous data is correct
</div>
Otherwise, you need an <asp:button /> or some other control on the page to trigger a postback and cause your event handlers to run. The button, or other control, can either be on your masterpage or on your content page, the choice is entirely yours.