Set IDs of controls of a repeater - asp.net

I have a repeater that contains a few controls and I want to set their ID's based on the IDs from database.
The datasource of the repeater is a list so basicly I want to do something like this in code behind, in repeater_ItemDataBound():
var myControl = e.Item.FindControl("controlID");
myControl.ClientIDMode = ClientIDMode.Static;
myControl.ID = e.Item.DataItem("ID"); //but I can't access the ID property, so here's my problem.
considering that I declared my repeater something like:
<asp:Repeater ID="repeater" runat="server">
<ItemTemplate>
<div class="someClass">
<asp:Label ID="controlID" runat="server"><%# Eval("Name")%></asp:Label>
<!-- list of other controls -->
</div>
</ItemTemplate>
</asp:Repeater>

Don't change ID's of controls that were already created with a different ID. That could cause nasty errors. Instead use the right ID in the first place. Or use whatever ID you use and assign the identifier to a different property like CommandArgument if it's a Button, Value if it's a HiddenField or Text if it's an (invisible) TextBox or Label.
So in this case you could use another control to store the ID:
<asp:HiddenField ID="hiddenID" runat="server" Value='<%# Eval("ID")%>' />
<asp:Label ID="lblName" runat="server"><%# Eval("Name")%></asp:Label>
Now, if you need the ID of the current item and you have the reference of the label or another control in that repeater-item:
var item = (RepeaterItem) lblName.NamingContainer;
HiddenField hiddenID = (HiddenField) item.FindControl("hiddenID");
string id = hiddenID.Value;

Related

Findcontrol in listview itemtemplate

I have the next code in itemtemplate:
<asp:ListView ID="ListView1" runat="server">
<ItemTemplate>
<asp:HiddenField Value='<%# checkCatName(Eval("CatName")) %>' runat="server" />
........
<asp:Label runat="server" id="lblBla" Visible="false"> ... </asp:Label>
</ItemTemplate>
</asp:ListView>
Code Behind (C#):
public void checkCatName(object CatName)
{
Label bla = (Label)ListView1.FindControl("lblBla");
if (CatName.ToString() == "test1")
bla.Visible = true;
return CatName.ToString();
}
I get null - like the page dont find the "bla" label.
Where i'm wrong ?
to get item which is in the listview or a repeater, you will need to go through items in this view and then find control (hidden field).
Page will not be able to find that control directly.
Hope that helps.
If the listview has an itemdatabound event you can use it to find the control and do what ever you need with it. The following code is assuming you have a hidden field in your listview item template with the id="myhiddenfield"
//this goes inside your listview's itemdatabound event
HiddenField myhiddenfield = new HiddenField();
myhiddenfield = (HiddenField)e.Item.FindControl("myhiddenfield");
//get or set hidden field value here.
int myID = Convert.ToInt32(myhiddenfield.Value);

GridView Template - How to Grab Data from Selected Row

<asp:TemplateField>
<ItemTemplate>
<table width="540" cellpadding="5">
<tr>
<td align="left" style="width:60%;">
<img src='PurchaseHandler.ashx?ProductID=<%# Eval("ProductID")%>'
alt="<%# Eval("ProductName") %>" />
</td>
<td align="left">
<h3 style="text-align:left;">
<asp:Label ID="nameLabel" runat="server"
Text='<%# Eval("ProductName") %>' />
</h3>
<asp:Label ID="priceLabel" runat="server" Text='<%# Eval("Price") %>' />
<br />
<asp:LinkButton ID="cartLink" runat="server" Text="<b>Add to Cart</b>"
CommandName="Add" CommandArgument='<%# Eval("ProductID") %>' />
</td>
</tr>
</table>
</ItemTemplate>
</asp:TemplateField>
I'm using a shopping cart business object which contains fields not used for display in the GridView. What I'm attempting to do next in the RowCommand event handler is to retrieve the rest of the data fields from the selected row. This gives me the correct product ID from the selected row:
if (e.CommandName == "Add")
{
int productID = 0;
int.TryParse(e.CommandArgument as string, out productID);
// Big blank!
}
How can I grab the rest of the data fields from the selected row to populate my cart? By way of explanation, I can probably use the productID to dig into the DataSet pulled from Session state, and get the data that way. However, what I'm trying to determine is if there is a syntax similar to this that can be used in this situation?
DataRow[] rows = ds.Tables[0].Select("ProductID=" +
gridProducts.SelectedDataKey.Values["ProductID"].ToString());
DataRow row = rows[0];
One way to do this would be to use the command argument to store the row index (perhaps setting it in the on row created event).
You could then use code as below to access your row (code snipped from MSDN):
// Convert the row index stored in the CommandArgument
// property to an Integer.
int index = Convert.ToInt32(e.CommandArgument);
// Retrieve the row that contains the button clicked
// by the user from the Rows collection. Use the
// CommandSource property to access the GridView control.
GridView customersGridView = (GridView)e.CommandSource;
GridViewRow row = customersGridView.Rows[index];
If you need to keep your command argument as the product id then you can use the code below to access the row:
GridViewRow row = (GridViewRow)(((LinkButton)e.CommandSource).NamingContainer);
You can then use the FindControl() method of the GridViewRow to select the controls that you need.
Label priceLabel = row.FindControl("priceLabel") as Label;
Edit after comments from OP
So if I'm correct, you want to access the DataItem of your row?
I don't think this is possible within a RowCommand event handler - I did a little bit of digging on other forums and apparently this property is only not null during DataBind - MSDN has this to say:
The DataItem property is available only during and after the RowDataBound event of a GridView control.
Looks like your method or something similar is the only way of linking back to the original objects in the RowCommand (hopefully someone proves me wrong)

Setting a asp repeater data source

I have a asp.net repeater control in a aspx page, with runat="server" and an id set, however for some reason i can't access its ID from code behind (I can access the id of the asp:detaislview control it sits in though). So instead in the page_load method I am doing the following:
Repeater repeater = (Repeater)PromotionSitesDetailsView.FindControl("estateRepeater");
repeater.DataSource = estateList;
However when run, an error comes up saying the repeater is null! All I want to do is set the datasource of this repeater to a List object. Any ideas?
You said the Repeater sits inside a DataList. The DataList is, itself, a kind of repeater - the controls inside of it don't exist until the DataList is bound to a datasource, and the controls in the template are created once per item in the source. So if you bind the DataList to a source with 3 items, you will get 3 repeaters.
So it looks kind of like this:
Page
MyDataList
Item0
MyRepeater
Item1
MyRepeater
Item2
MyRepeater
So obviously MyDataList.FindControl("MyRepeater") can't work - which "MyRepeater" are we talking about? Since multiple controls cannot have the same ID, ASP.NET solves this by making the ID unique to something called a NamingContainer. Since the DataList repeats the same set of controls many times (once per item in the data source), each item in the DataList is a NamingContainer.
We need to find the NamingContainer we know holds the instance of MyRepeater that we want:
MyDataList.Items[0].FindControl("MyRepeater");
You can iterate over the items in the DataList after it has been bound (of course, before it has been bound it has no items). You can also operate on a given item in the DataList as that item is being created:
<asp:DataList OnItemDataBound="MyDataList_HandleItemDataBound" ... />
//this will get called once per item as it is created
void MyDataList_HandleItemDataBound(object sender, DataListItemEventArgs e)
{
//e.Item is the current item being databound
Repeater myRepeater = e.Item.FindControl("MyRepeater") as Repeater;
myRepeater.DataSource = //ds
myRepeater.DataBind();
}
You can do it without code-behind, simply by assigning the Repeater DataSource. Here is an example of a two level hierarchical menu:
<ul>
<asp:Repeater ID="ctlMenu" runat="server">
<ItemTemplate>
<li>
<asp:HyperLink runat="server"
NavigateUrl='<%#(Container.DataItem as MyPage).GetUrl()%>'
Text="<%# (Container.DataItem as MyPage).GetName() %>"></asp:HyperLink>
<ul>
<asp:Repeater runat="server" DataSource="<%# (Container.DataItem as MyPage).GetChildren() %>">
<ItemTemplate>
<li>
<asp:HyperLink runat="server"
NavigateUrl='<%#(Container.DataItem as MyPage).GetUrl()%>'
Text="<%# (Container.DataItem as MyPage).GetName() %>"></asp:HyperLink>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
</ul>

Changing WebControl ID Inside of a Repeater

<ItemTemplate>
<asp:Label runat="server"><%#DataBinder.Eval(Container.DataItem, "Question")%></asp:Label>
<asp:DropDownList runat="server" id="<%#DataBinder.Eval(Container.DataItem, "QuestionID")%>">>
<asp:ListItem value="1" text="Yes" />
<asp:ListItem value="0" text="No" />
</asp:DropDownList>
<ItemTemplate>
This is roughly what I'm trying to do. Obviously, the implementation is faulty, but I can't find any information on how I'd go about this in practice. Any help is appreciated.
Edit: What I'm trying to do exactly is add a DropDownList for each item in this Repeater, and upon submission of the form, use the ID's of each Yes/No answer to input into a database. The SqlDataReader that I'm using has two fields: The question content and the questionID.
I think you'd be better off using the built in support for IDs inside a Repeater. If the goal is to assign it an ID to make it easy to find the proper control after the data has been bound you might try something like this:
<asp:Repeater ID="Repeater1" runat="server>
<ItemTemplate>
<asp:Label ID="QuestionID" Visible="False" Runat="server"><%#DataBinder.Eval(Container.DataItem, "FieldContent")%></asp:Label>
<asp:DropDownList ID="MyDropDownList" Runat="server"></asp:DropDownList>
</ItemTemplate>
</asp:Repeater>
Then, in your code you can loop through the items in the Repeater until you find the label you're looking for:
foreach (RepeaterItem curItem in Repeater1.Items)
{
// Due to the way a Repeater works, these two controls are linked together. The questionID
// label that is found is in the same RepeaterItem as the DropDownList (and any other controls
// you might find using curRow.FindControl)
var questionID = curRow.FindControl("QuestionID") as Label;
var myDropDownList = curRow.FindControl("MyDropDownList") as DropDownList;
}
A Repeater basically consists of a collection of RepeaterItems. The RepeaterItems are specified using the ItemTemplate tag. Each RepeaterItem has its own set of controls that are, by the very nature of a Repeater, associated with each other.
Say you're pulling the Repeater data from a database. Each Repeater item represents data from an individual row in the query results. So if you assign the QuestionID to a label and the QuestionName to a DropDownList, the ID in the label would match up with the name in drop down.
Could you remove the control from the markup file, and hook the repeater's onItemDataBound event. In that event, you should be able to create the dropdown control "manually", assigning whatever ID you want.

How to find checked RadioButton inside Repeater Item?

I have a Repeater control on ASPX-page defined like this:
<asp:Repeater ID="answerVariantRepeater" runat="server"
onitemdatabound="answerVariantRepeater_ItemDataBound">
<ItemTemplate>
<asp:RadioButton ID="answerVariantRadioButton" runat="server"
GroupName="answerVariants"
Text='<%# DataBinder.Eval(Container.DataItem, "Text")%>'"/>
</ItemTemplate>
</asp:Repeater>
To allow select only one radio button in time I have used a trick form this article.
But now when form is submitted I want to determine which radio button is checked.
I could do this:
RadioButton checkedButton = null;
foreach (RepeaterItem item in answerVariantRepeater.Items)
{
RadioButton control=(RadioButton)item.FindControl("answerVariantRadioButton");
if (control.Checked)
{
checkedButton = control;
break;
}
}
but hope it could be done somehow simplier (maybe via LINQ to objects).
You could always use Request.Form to get the submitted radio button:
var value = Request.Form["answerVariants"];
I think the submitted value defaults to the id of the <asp:RadioButton /> that was selected, but you can always add a value attribute - even though it's not officially an <asp:RadioButton /> property - and this will then be the submitted value:
<asp:RadioButton ID="answerVariantRadioButton" runat="server"
GroupName="answerVariants"
Text='<%# DataBinder.Eval(Container.DataItem, "Text")%>'"
value='<%# DataBinder.Eval(Container.DataItem, "SomethingToUseAsTheValue")%>' />
Since You are using javascript already to handle the radio button click event on the client, you could update a hidden field with the selected value at the same time.
Your server code would then just access the selected value from the hidden field.
I'm pretty sure that the only thing you could use LINQ to Objects for here would be to take the conditions from within the foreach loop and move them to a where clause.
RadioButton checked =
(from item in answerVariantRepeater.Items
let radioButton = (RadioButton)item.FindControl("answerVariantRadioButton")
where radioButton.Checked
select radioButton).FirstOrDefault();

Resources