Accessing asp controls within a datalist - asp.net

How do you access an asp control within a datalist. For example, I would like to, but currently cannot, access the HyperLink control or the ImageButton control by inline code, or in the code-behind file.
<asp:DataList ID="DataList1" runat="server" AlternatingItemStyle-CssClass="altArtStyle">
<HeaderTemplate>
<table>
<tr>
<td>
<asp:HyperLink ID="lnkTitle" runat="server" NavigateUrl="Default.aspx?order_by=title&direction=ASC" >
Title
</asp:HyperLink> <asp:ImageButton id="imgbtnTitle" src="/_images/hover-down.gif" runat="server"/>
</td>
</tr>
</table>
</HeaderTemplate>

Generally, you need to call FindControl on the DataListItem object, in order to find the control on the specific row. In your example, FindControl will only work on a header row, as in the following example:
Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) Handles DataList1.ItemDataBound
If e.Item.ItemType = ListItemType.Header Then
Dim btn As ImageButton = e.Item.FindControl("imgbtnTitle")
If btn IsNot Nothing Then
' Do stuff here.
End If
End If
End Sub

same you can do with labels and hyperlinks
private void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
ImageButton imgbutton = (ImageButton)e.Item.FindControl("imgbtnTitle");
imgbutton.ToolTip = "abc";
}
}

It depends. For example, if you wanted to change the header at runtime, in one of the object bind events, you'd do something like for this datalist header, do a findcontrol on the hyperlink and with that reference, do this...

Yes, you can access the asp controls inside the datalist by using the Datalist Item Data bound
protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
HyperLink TitleLink = (HyperLink)e.Item.FindControl("lnkTitle");
}
}

Related

How to fire a button event from inside a repeater?

I have done my research but can't find an efficient way to do the following in VB:
Each button should fire the same event.
The button event saves every repeater item and so each event is not unique.
I am aware I can use the ItemCommand option but have not been able to get it working as desired.
ASP.NET
Inside Repeater Item
<asp:Button ID="btnSave" RunAt="Server"/>
VB.NET
Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As System.EventArgs)
sqlConn.Open()
For Each Item As RepeaterItem In rpt.Items
...
Next
sqlConn.Close()
End Sub
Edit:
After some research here on SO, I found that others events than ItemCommand are not caught by Asp:Repeater, as FlySwat said on his answer. So you'll need to write your VB.NET code like this:
First, declare the ItemCommand event on your page with something like this:
Protected Sub rpt_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles rpt.ItemCommand
If e.CommandName = "Save" Then
'Save
End If
End Sub
Then, on Asp:Button markup inside the Asp:Repeater, you must set its CommandName property like this:
<Asp:Button ID="btnSave" runat="server" CommandName="Save" UseSubmitBehavior="false"/>
Take a look here to learn more about the UseSubmitBehavior.
Try it.
When the button is inside a Repeater template, you need to add OnClick event, you can add event on ItemDataBound event of the Repeater control.
Your .aspx code will look something like this:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:Button ID="btnSave" runat="server" Text="SomeText" />
</ItemTemplate>
</asp:Repeater>
code-behind
void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == Repeater1.AlternatingItem || e.Item.ItemType == Repeater1.Item)
{
var btn = e.Item.FindControl("btnSave") as Button;
if (btn != null)
{ // adding button event
btn.Click += new EventHandler(btn_Click);
}
}
}
void btn_Click(object sender, EventArgs e)
{
//write your code
}
in vb.net
Private Sub Repeater1_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
If e.Item.ItemType = Repeater1.AlternatingItem OrElse e.Item.ItemType = Repeater1.Item Then
Dim btn = TryCast(e.Item.FindControl("btnSave"), Button)
If btn IsNot Nothing Then
' adding button event
btn.Click += New EventHandler(btn_Click)
End If
End If
End Sub
Private Sub btn_Click(sender As Object, e As EventArgs)
'write your code
End Sub

Why is my ASP.NET Repeater data not available in load events via code behind?

I have an ASP.NET repeater that is being populated via a datasource. The data loads and presents perfectly on the screen, but all attempts to access any row of data in that repeater via code behind during the load phase are unsuccessful. I can access everything perfectly on a form submit, once the repeater has rendered on the screen, but in every load-related event I have tried (Load, Init, PreRender, DataBind, etc), it shows as empty. Is it necessary to populate the repeater programatically in code behind, rather than ASPX markup, in order to access this data during the load phase or am I just doing something wrong?
ASPX snippet:
<div runat="server" id="rpt3" style="display: block;">
<p class="approvalHeaderText">
Rejected Items</p>
<asp:Repeater ID="RptRejected" runat="server" DataSourceID="SQL_EmployeeGetRejectedEdits">
<ItemTemplate>
<tr class="gridToggleWhite gridVisible" id="<%# Eval("RecID") %>_cont">
<td>
<%# Eval("OrderID")%>
</td>
Code behind snippet - tried in several events (assume all variables have been declared):
For i = 0 To RptRejected.Items.Count - 1
'Obtain current week's Expenses
curExpVal = RptRejected.Items(i).FindControl("ExpensePay")
If Not IsNothing(curExpVal) Then
If curExpVal.Text = "" Then
insertExp = 0
Else
insertExp = CSng(curExpVal.Text)
End If
Else
insertExp = 0
End If
Next
You can use the ItemDataBound event (and you don't need the loop):
Sub rpt3_ItemDataBound(Sender As Object, e As RepeaterItemEventArgs)
If (e.Item.ItemType = ListItemType.Item) OrElse _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim curExpVal = e.Item.FindControl("ExpensePay")
If Not IsNothing(curExpVal) Then
If curExpVal.Text = "" Then
insertExp = 0
Else
insertExp = CSng(curExpVal.Text)
End If
Else
insertExp = 0
End If
End If
End Sub
R1_Load and R1_ItemDataBound should be used to populate your data and R1_ItemCommand should be used to handle the button actions.
aspx
<asp:Repeater runat="server" ID="R1" OnItemCommand="R1_ItemCommand" OnItemDataBound="R1_ItemDataBound"
OnLoad="R1_Load">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:TextBox runat="server" ID="txt"></asp:TextBox><asp:Button runat="server" ID="btn"
Text="Add" CommandName="AddOne" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table> </FooterTemplate>
</asp:Repeater>
aspx.cs
protected void R1_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var items = new List<int>();
for (int i = 0; i < 5; i++)
{
items.Add(i);
}
R1.DataSource = items;
R1.DataBind();
}
}
protected void R1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var txt = e.Item.FindControl("txt") as TextBox;
txt.Text = Convert.ToString(e.Item.DataItem);
}
}
protected void R1_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "AddOne")
{
var txt = e.Item.FindControl("txt") as TextBox;
txt.Text = (Convert.ToInt32(txt.Text) + 1).ToString();
}
}
My key mistake was using Eval() instead of the DataBinder.Eval() method. While the result is the same on the screen, Eval() does not trip the OnItemDataBound event. Once I switched my markup over to DataBinder.Eval(), everything fell into place. Thanks, everyone, for your ideas.

Change an ASP.NET control's properties in a Repeater control

My question is fairly simple. This is what I have for the aspx page:
<ul>
<asp:Repeater runat="server" ID="linksList" OnItemDataBound="linksList_OnItemDataBound" >
<ItemTemplate>
<li><asp:HyperLink runat="server" ID="link" /></li>
</ItemTemplate>
</asp:Repeater>
</ul>
I'm trying to get a list of hyperlinks from a SQL server into a list. This is what I have in the codebehind:
protected void Page_Load(object sender, EventArgs e)
{
DataSet ds = Utilities.RunSelectQuery("SELECT *");
DataTable dt = ds.Tables[0];
linksList.DataSource = dt;
linksList.DataBind();
}
How do I change the NavigateUrl and Text properties in the asp:HyperLink after data's been bound to the Repeater? I want to do this in the codebehind, I can get it to work if I do it using <%# Eval("URL") %> in the aspx page but that's sort of against what ASP.NET is all about.
Edit: this is the solution that worked for me thanks to womp:
protected void linksList_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
DataRowView row = (DataRowView)e.Item.DataItem;
HyperLink link = (HyperLink)e.Item.FindControl("link");
link.Text = row["description"].ToString();
link.NavigateUrl = row["URL"].ToString();
}
}
Actually, using the Databinder syntax in your templates is a great way to do it, I'm not sure what you mean that it's "against what ASP.Net is all about".
However, if you really want to do it in code, you can do it right in your OnItemDataBound handler (which it looks like you've created). Something like this (read: untested) should do the trick:
void linksList_OnItemDataBound(object Sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item
|| e.Item.ItemType == ListItemType.AlternatingItem) {
DataRow row = e.Item.DataItem as DataRow;
Hyperlink link = e.Item.FindControl("link"));
link.Text = row["URL"];
link.NavigateUrl = row["URL"];
}
}
}
The way to do it is just as you said. Doing it in the code behind adds unnecessary work if you only wish to display the URL. You also would want to put the tags in the HeaderTemplate and FooterTemplate.
<asp:Repeater runat="server" ID="linksList" OnItemDataBound="linksList_OnItemDataBound" >
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
<li><asp:HyperLink runat="server" ID="link" NavigateUrl='<%# Eval("url") %>' /></li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>

Using event of control under datalist

I have a datalist control which some controls(ex: button) are in it. I want to write some code into click event of button which is in the datalist control. But in the code behind page I can't see the name of controls into datalist. How can I solve this problem?
Attach your event to the controls in the OnItemCreated event of the datalist.
EDITED TO ADD SAMPLE
private void DataList_ItemCreated(object sender,
System.Web.UI.WebControls.DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Button btn = (Button)e.Item.FindControl("btnWhatever");
if (btn != null) btn.Click += new EventHandler(SomHandler);
}
}
If you don't want to add a handler to all the child events, you could instead add your code to the OnItemCommand.
<asp:DataList id="DataList1" runat="server">
<ItemTemplate>
<asp:Button ID="btnDoSomething" Runat=server CommandName="DoSomething"
CommandArgument="<%# DataBinder.Eval(Container.DataItem, "SomeID")
%>"></asp:LinkButton>
</ItemTemplate>
</asp:DataList>
protected void DataList1_ItemCommand(
object source, DataListCommandEventArgs e)
{
if (e.CommandName == "DoSomething")
{
//Do stuff
}
}

ASP.Net: why is my button's click/command events not binding/firing in a repeater?

Here's the code from the ascx that has the repeater:
<asp:Repeater ID="ListOfEmails" runat="server" >
<HeaderTemplate><h3>A sub-header:</h3></HeaderTemplate>
<ItemTemplate>
[Some other stuff is here]
<asp:Button ID="removeEmail" runat="server" Text="X" ToolTip="remove" />
</ItemTemplate>
</asp:Repeater>
And in the codebehind for the repeater's databound and events:
Protected Sub ListOfEmails_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles ListOfEmails.ItemDataBound
If (e.Item.ItemType = ListItemType.Item) Or (e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim removeEmail As Button = CType(e.Item.FindControl("removeEmail"), Button)
removeEmail.CommandArgument = e.Item.ItemIndex.ToString()
AddHandler removeEmail.Click, AddressOf removeEmail_Click
AddHandler removeEmail.Command, AddressOf removeEmail_Command
End If
End Sub
Sub removeEmail_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Response.Write("<h1>click</h1>")
End Sub
Sub removeEmail_Command(ByVal sender As Object, ByVal e As CommandEventArgs)
Response.Write("<h1>command</h1>")
End Sub
Neither the click or command is getting called, what am I doing wrong?
Controls nested inside of Repeaters do not intercept events. Instead you need to bind to the Repeater.ItemCommand Event.
ItemCommand contains RepeaterCommandEventArgs which has two important fields:
CommandName
CommandArgument
So, a trivial example:
void rptr_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("myButton");
myButton.CommandName = "Add";
myButton.CommandArgument = "Some Identifying Argument";
}
}
void rptr_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "Add")
{
// Do your event
}
}
You need to handle the ItemCommand event on your Repeater. Here's an example.
Then, your button clicks will be handled by the ListOfEmails_ItemCommand method. I don't think wiring up the Click or Command event (of the button) in ItemDataBound will work.
If you're planning to use ItemCommand event, make sure you register to ItemCommand event in Page_Init not in Page_Load.
protected void Page_Init(object sender, EventArgs e)
{
// rptr is your repeater's name
rptr.ItemCommand += new RepeaterCommandEventHandler(rptr_ItemCommand);
}
I am not sure why it wasn't working for me with this event registered in Page_Load but moving it to Page_Init helped.
Here's an experiment for you to try:
Set a breakpoint on ListOfEmails_ItemDataBound and see if it's being called for postbacks.
You know what's frustrating about this?
If you specify an OnClick in that asp:Button tag, the build will verify that the named method exists in the codebehind class, and report an error if it doesn't... even though that method will never get called.

Resources