Why is FindControl not working with my repeater? - c#

I'm trying to change the visibility of a pair of server controls (specifically a LinkButton and Label) that are nested inside the ItemTemplate part of a repeater during the onclick event of the same LinkButton. I've actually already found a solution, but I don't understand why it works and not the way I was trying before. What I was trying originally is as follows:
Nested inside the ItemTemplate of a repeater
<asp:LinkButton ID="lnAdd" CommandArgument='<%#Eval("index") %>' runat="server" Text="Add" OnClick="lnAdd_Click"> </asp:LinkButton>
<asp:Label Visible="false" runat="server" ID="videoAdded" Text="Video Added"></asp:Label>
Then inside of that lnAdd_Click function I have:
Repeater1.FindControl("lnAdd").Visible = false;
Repeater1.FindControl("videoAdded").Visible = true;
where Repeater1 is the id of the repeater these controls are in. This appears to do nothing (though it compiles). I assume this is because for some unknown reason those controls are not found.
What does work is the last answer of the following question: Server controls in an asp.net repeater
The solution appears to be doing something very similar what I've tried to do. Its even using FindControl on a repeater. The only difference (that I can see) is that it obtains the repeater via the sender object. Hmmm, actually, now that I think about it the id of the elements are changed by .Net to some nonesense like ctl00_ContentPlaceHolder1_Repeater1_ctl02_lnAdd when this is actually run, so perhaps that's why its not finding it. But at the same time, in the working solution I just give the normal ID like "lnAdd". Is .Net automatically translating it? Why would it do it for this solution and not for how I was trying to do it originally?
Anyway, I feel like there's something fundamental here that I'm not quite grasping and would appreciate some enlightenment :D

The problem with using Repeater1.FindControl(..)... is that you can't tell which particular Label or LinkButton is being targeted. It's a repeater, so each such item gets assigned a unique identifier as part of the RepeaterItemCollection. In the markup you name it "lnAdd" but that's not what it will be once generated etc.
For reference, here's the code you said worked from the other post:
protected void btnUpdate_OnClick(object sender, EventArgs e)
{
Button b = sender as Button;
if (b != null)
{
RepeaterItem ri = b.Parent as RepeaterItem;
if (ri != null)
{
string name = null;
//Fetch data
TextBox txtName = ri.FindControl("txtName") as TextBox;
I'll explain the reason the above works. First, the button that was clicked is cast from the sender object. We know it's a button since it's the Update button's click handler. Next, we also know that the button appears in a repeater, so it's parent is a RepeaterItem. That's how the ri variable is initialized and cast. With ri available to us, using FindControl on it will now find the given control in that particular RepeaterItem.

You need to call the FindControl on the RepeaterItem that contains the button that was clicked, you do this in the OnItemCommand handler of the repeater, so you get the instance of the RepeaterItem that caused the command.
You have to add a OnItemCommand="ProcessCommands" in the repeater header and then add a ProcessCommand member:
protected void ProcessCommands(object source, RepeaterCommandEventArgs e)
{
LinkButton button = (LinkButton)e.Item.FindControl("lbAdd");
button.Visible = false;
...
}
Hope this helps

Related

linkButton Click Event in Grid View is not working

I am using linkbutton to insert data in the asp.net grid view through textbox. But in spite of correct code my button is not performing action.
Here is my ASPX code
<FooterTemplate>
<asp:LinkButton ID="Insertkey" OnClick="Insertkey_Click" runat="server">INSERT</asp:LinkButton>
</FooterTemplate>
Here is my C# code
protected void Insertkey_Click(object sender, EventArgs e)
{
SqlDataSource1.InsertParameters["Title"].DefaultValue = ((TextBox)GridView1.FooterRow.FindControl("Tbox")).Text;
SqlDataSource1.InsertParameters["Pic"].DefaultValue = ((TextBox)GridView1.FooterRow.FindControl("Pbox")).Text;
SqlDataSource1.InsertParameters["Content"].DefaultValue = ((TextBox)GridView1.FooterRow.FindControl("Cbox")).Text;
}
Please help me to solve my problem.
Try using the command event instead of click, then handle the grid's RowCommand event and see what the command name is.
Controls that postback, such as the link button, behave differently when in templated controls such as the gridview, primarily since they can't really be declared in the same way since they're in a template.

ASP.NET C# Issue Adding event handler to ImageButton CodeBehind

I'm having problems adding an event to an ImageButton. I have to create a set of buttons depending on a selected option from a DropDownList. The buttons are created successfully with Database data, but I'm can't attach the OnClick functionality.
The created buttons must share the same Handler.
protected void cmbServ_SelectedIndexChanged(object sender, EventArgs e) {
ServiceID = cmbServ.SelectedValue.ToString();
ServiceName = cmbServ.SelectedItem.ToString();
DataTable dtFirstTab = new DataTable();
dtFirstTab = mySQLConn.getTable(qryCarry); // LOAD DATA FROM DB
foreach (DataRow row in dtFirstTab.Rows) {
FTabBtn = "btn"+(Convert.ToInt32(row["SKU_Credito"])).ToString();
FTabIconURL = row["SKU_Icon"].ToString();
Panel dvFirstTab = new Panel();
dvFirstTab.CssClass = "col-xs-2";
ImageButton IB = new ImageButton();
IB.ID = FTabBtn;
IB.ImageUrl = FTabIconURL;
IB.Click += new ImageClickEventHandler(btnX_click); // <-- PROBLEM
dvFirstTab.Controls.Add(IB);
pnlIcons.Controls.Add(dvFirstTab); // pnlIcons exists in HTML
}
protected void btnX_click(object sender, ImageClickEventArgs e) {
string Obj = ((ImageButton)sender).ClientID;
Cantidad = Convert.ToInt32(Obj.Substring(3, (Obj.Length) - 3));
txtMonto.Text = "$" + Cantidad.ToString();
}
All the buttons appear correctly, but when I click on them they just fire a "submit" action, acting like there's no OnClick assigned.
No CodeBehid example:
If I add this line in HTML (I removed asp tags)
ImageButton ID="btn10" runat="server" ImageUrl="MontoLogo_10ST.png" OnClick="btnX_click"
It does work as intended.
Any ideas? Thanks a lot!
Creating controls dynamically in ASP.NET webforms usually seems easy at the beginning, but problems are very common when it comes to handling events. Even if you assign your event handler correctly, the event handler is not run in a postback until you re-create all the dynamic controls early in page lifecycle. This explains why the sample with the ImageButton on the ASPX works whereas the dynamically created buttons don't.
See this page for details on creating controls dynamically. The most important part is the warning that basically says: if you need to add dynamic controls, better don't.
Usually you can find a way to create all the necessary controls in markup, for instance using a Repeater control. The big advantage of the repeater is that you have control about the markup that is created.
The following sample outlines the necessary steps:
Place a repeater on your aspx-page. If pnlIcons serves no other purpose than being the container for the dynamically created buttons, substitute it by the repeater. Use the Header- and FooterTemplate properties to add the markup that surrounds the ImageButtons (e.g. the div for dvFirstTab).
Think about which data you need to assign to the image button. In your case, the fields "SKU_Credito" and "SKU_Icon" seem to be required.
Place the Image button in the ItemTemplate of the repeater and bind the properties "Id" and "ImageUrl" to the corresponding fields.
Add a Command event handler and bind the CommandArgument property to a value that helps you discern between the image buttons.
In the command event handler, you can use the CommandArgument to discover which button has been clicked. Add the appropriate code that handles the command.
In the SelectedIndexChanged event handler, read the data from the database and bind the repeater to the result. This creates the rows in the repeater with the ImageButtons.
Ok, I've found the reason. The event handling must be assigned in Page_Load event, so I moved everything inside a method and called it from Page_Load, calling it from "SelectedIndexChanged" doesn't work . It's working now.
Thanks!

Dynamic LinkButton Click event never appears on the resulting anchor

So I'm currently trying to add to each day of a .net calendar control one dynamic linkbutton (on the dayRender event). The problem I have is that the linkbutton href does not appear. It's not a problem of the linkbutton event not firing, the href= doesn't even appear, so it doesn't fire any postback. This means that the button looks like this in the html part:
<a class="delete79" ID="Delete_2014-09-01"> Delete </a>
My code looks like this:
protected void MyCalendar79_DayRender(object sender, DayRenderEventArgs e)
{
List<MenuDia> dayList = new List<MenuDia>();
foreach (var itemMenu in ListMenuDays)
{
if (itemMenu.Dia.CompareTo(e.Day.Date) == 0)
{
dayList.Add(itemMenu);
}
}
LinkButton deleteButton = new LinkButton();
deleteButton.CssClass = "delete79";
deleteButton.Text = "Delete";
deleteButton.ID = "Delete79_" + dayList[0].Dia.ToString("yyyy-MM-dd");
deleteButton.Click += delegate(object o, System.EventArgs a)
{
//simple stuff here, tried putting simple generic response.redirect
//and stuff like that but it wasn't the problem
};
}
I don't wanna sound rude but don't tell me that it's because I'm using a delegate instead of an eventhandler. First of all I tried changing that already (same thing happened) and second I usually do it like this when it's super simple so I don't have to create a separate method.
Also, I've tried changing the ID to something more predictable (Delete_+a simple index), that's not the problem unfortunately =(.
Any other ideas? Maybe it's because I'm doing it on dayrender and you can't do it there? How can I achieve the same thing then?
So yeah I found the problem. MSDN page says:
Because the DayRender event is raised while the Calendar control is
being rendered, you cannot add a control that can also raise an event,
such as LinkButton. You can only add static controls, such as
System.Web.UI.LiteralControl, Label, Image, and HyperLink.
That's the problem. I will do a hack manually that generates the same postback of a hidden linkbutton. Thanks everyone!

LinkButton postback but click event not fired

Hi everyoneThis is my first post on stackoverflow (which btw is by far my favourite site for finding answers). After finally admitting defeat, I'm hoping someone can help me with this problem...
The question has already been asked several times, but none of the suggested solutions I found has helped. Apologies in advance for a lengthy post, but I want to avoid anyone wasting their time on suggesting things I tried already.
The code below worked until recently, and its structure has not been touched since (although unrelated changes were made to the child page). In any event, it suddenly stopped working. Now even the most simplified button won’t fire.
Setup
VS 2008 C#, IIS 7 (no changes in setup since way before it stopped working)
nested masterpage (main + 1 child)
dynamically loaded ucl with datalist in child page
(i.e. MP => nested MP => child page => ucl => datalist => linkbutton)
linkbutton click event also resides in ucl
Problem
On LB click, the postback occurs ok, but the server-side click event never gets hit.
Code
page:
var ctrlX = base.LoadControl("~/somedir/someucl.ascx");
=> loads fine
ascx file (datalist stripped of all but the button):
<asp:DataList ID="dlX" RepeatLayout="Table" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:LinkButton ID="btnX" OnClick="btnX_Click" CausesValidation="false" runat="server" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate></FooterTemplate>
codebehind:
protected void btnX_Click(object sender, EventArgs e)
{
// do something
}
things tried
cleaning the solution
digging out a working backup and checking for code changes
(found none affecting the structure or user control)
setting LinkButton CausesValidation true/false
stripping datalist and LinkButton down to bare essentials
adding AddressOf="btnX.click" to LinkButton
wrapping UpdatePanel one at a time with varying settings around usercontrol datalist linkbutton
reattaching eventhandler in usercontrol init / load event:
IEnumerable<Control> controls = Utils.FlattenChildren(dlX);
foreach (var button in controls.OfType(LinkButton)())
{
if (button.ID.Contains("btnX"))
button.Click += new EventHandler(btnX_Click);
}
Wherever I add above code, all buttons are found and the event is attached, but click event doesn't fire ((LinkButton) = LinkButton inside <>; couldn't get it to display right, still struggling a bit with the editor)
.
adding PostBackUrl manually in page load event
comparing the client ids between load/postback events
=> they always match
That's it. Right now, I can't think of what else to try or check (maybe something in the breakpoint context menu on postback?).
Because the ucl loads fine, and the postback is working ok, I suspect the problem is somewhere in the ucl, rather than the child page loading it. But maybe not.
If at all possible, I want to avoid workarounds (I need the button command argument, not shown above, and am not keen on solutions such as jquery with hidden field or query string).
Apart from anything, I would really like to understand what causes this.
Obviously, I'm missing something... Thanks to anyone taking their time reading/helping with this!
======== as requested additional codebehind =======
I've simplified the parent page code to a minimum, dropping all method calls, and as per Eoins suggestion moved the ucl load in the page's init event. The ucl code remains as shown above. The DL and LB show up fine, and on click the postback is triggered, ucl page load event is hit, but as before, the server click event is not hit.
protected override void OnInit(EventArgs e)
{
var ctrlX = base.LoadControl("~/someucl.ascx");
if (ctrlX == null)
return;
DataList dlX = (DataList)ctrlX.FindControl("dlX");
if (dlX == null)
return;
DummyCollection x = new DummyCollection();
x.Add(null); // ok since the test LB does not draw on the datasource
dlX.DataSource = x;
dlX.DataBind();
pnlX.Controls.Add(ctrlX);
base.OnInit(e);
}
var ctrlX = base.LoadControl("~/somedir/someucl.ascx");
Where exactly does this code live on your page?
You'll need to make sure you're creating it and adding it to the control collection early enough in the page lifecycle so that on subsequent postbacks its created & wired up in time. I.e. in the oninit event.
protected override OnInit(...)
{
base.OnInit(...);
var ctrlX = base.LoadControl("~/somedir/someucl.ascx");
this.Controls.Add(ctrlX);
}

Accessing RepeaterItem Controls in an EventHandler

I have a page with a repeater in it. I'm writing an event handler so that when the user clicks my WebControl button, the event handler for said button iterates through the items in the repeater using FindControl, then uses some of the controls' values. It seems though, that after the page is loaded, the repeater items populate, but when the button is clicked to post this back, as I iterate through the repeater items, I'm seeing that they're all empty. I don't completely understand the sequencing, but I'm assuming it's because my iteration code is trying to access RepeaterItems that haven't been set yet.
The repeater code is in my OnLoad method. Outside of that, I have my event handler trying to iterate through those items after being clicked. This is essentially what I was trying to do:
protected void MyButton_Click(object sender, EventArgs e)
{
foreach(RepeaterItem item in MyRepeater.Items)
{
MyLabel = (Label)item.FindControl("MyLabel");
}
}
The button is located in the FooterTemplate of the repeater.
<asp:Button runat="server" OnClick="SubmitChecklist_Click" cssclass="BlueSubmit" id="SubmitChecklist" text="Submit" />
Thanks in advance.
Edit: To clarify, the exact error I'm getting is NullReferenceException, when I try to do something, for instance, Response.Write(MyLabel.Text)
Edit: After looking into it more today, this is what I understand to be happening: The repeater is databound on postback. When I then make selections from the generated dropdownlists and hit my button, it posts back again. At this point, the repeater is databound again to it's initial values. So, if I must postback in order to get the users' selections, how can I go about this in the button's eventhandler so that I can get the selected values before that repeater gets databound again?
THe problem, it sounds like, is that you may be binding the data to your repeater on load, but not first checking to make sure it isnt a post back.
example:
You request the page. On Load Fires. You bind the data to the repeater.
You maniupulate the data in the reapter then click your button
The page refreshes with the postback, firing the onload event. The data is rebound to your repeater and all previous data entered has been nullified.
the onclick event is triggered and your code tries to retrieve values that no longer exist.
Make sure your databinding code in your onLoad event is nested within an postback check
if (!Page.IsPostBack)
{
Repeater.DataSource = Datatable;
Repeater.DataBind();
}
I've seen the same thing. I don't understand why, but the data doesn't actually get bound until after all events have fired. I ended up making my data source available at the class level and then indexing.
private DataTable myTable;
protected void Page_Load(object sender, EventArgs e)
{
//populate dataTable
if (!IsPostBack)
{
//databind to repeater
}
}
protected void Submit_Click(object sender, EventArgs e)
{
foreach (RepeaterItem item in repeater1.Items)
{
DataRow row = myTable.Rows[item.ItemIndex];
}
}
Ideal? Certainly not but it works.
Instead of relying on the IsPostBack in my OnLoad, I just seperated all of the different states by putting the databinding of the repeater inside of an event handler after the user selects the first option, rather than relying on the IsPostBack of OnLoad. It was a bit convoluted, but I think I'm doing it the right way this time.

Categories

Resources