Getting value in footer template from code behind-Repeater - asp.net

I have a repeater like this:
<asp:Repeater runat="server" ID="pde">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<asp:Literal runat="server" ID="literal1"></asp:Literal>
</ItemTemplate>
<FooterTemplate><asp:Literal runat="server" ID="literal2"></asp:Literal></FooterTemplate>
</asp:Repeater>
Now in literal2 I want to get the value from code behind.But I am not able to get the literal2 in code behind.Any idea how to get this?

You should be able to access it by accessing the last RepeaterItem in your repeater which will be your footer. Then do a search, using FindControl, on the RepeaterItem for any control you are looking for.
Using your example above do:
Literal controlYouWant = pde.Controls[pde.Controls.Count - 1].FindControl("literal2") as Literal;
You can break down the statements to:
// This will get you the footer
RepeaterItem item = pde.Controls[pde.Controls.Count - 1];
// From here you finds any control you want within the RepeaterItem.
Literal controlYouWant = item.FindControl("literal2") as Literal;

First search through items in repeater and only take the footer item type and discard the others. Take a look to the following code.
foreach(RepeaterItem item in repeterName.Controls)
{
if (item.ItemType != ListItemType.Footer) continue;
var lblMyLabel = ((Label)item.FindControl("lblMyLabel"));
lblMyLabel.Text = "I found it!!!";
}

Related

Hide / unhide Label, textbox depending on the db results in asp.net

I need to hide /unhide the labels and textbox depending on db results , I tried something like this but it doesnt works, the condition should be like if the db field is empty for that field , then the label associated with that field should hidden (not visible) , following is the code i tried :
<asp:Label ID="lblBirth" Text="DOB:" runat="server" ViewStateMode="Disabled" CssClass="lbl" />
<asp:Label ID="DOB" runat="server" CssClass="lblResult" Visible='<%# Eval("Berth") == DBNull.Value %>'></asp:Label>
Code behind:
protected void showDetails(int makeID)
{// get all the details of the selected caravan and populate the empty fields
DataTable dt = new DataTable();
DataTableReader dtr = caravans.GetCaravanDetailsByMakeID(makeID);
while (dtr.Read())
{
//spec
string value = dtr["Price"].ToString();
lblModel.Text = dtr["model"].ToString();
birthResult.Text = dtr["Berth"].ToString(); }}
To make your aspx version work your control should be data bound to data source that contains "Berth" property. As I can see from code behind, you prefer to use c# to populate controls. In this case you may just do the following:
DOB.Visible = dtr["Berth"] == DBNull.Value;
I think that using data binding is more preferable solution.

How to place a hyperlink field in a web page at runtime?

I am trying to display contents of a folder in a hyperlink. I am using masterpage also. The hyperlinks are not shown into the content page. what to do for that?
I know in windows forms we can use like
TextBox.Location=new Point(100,100);
But how to do in web page...please anybody suggest me..
my coding in page_load is
protected void Page_Load(object sender, EventArgs e)
{
DirectoryInfo di = new DirectoryInfo(Server.MapPath("~/ProjectsUpload"));
int i = 0;
foreach (FileInfo fi in di.GetFiles())
{
HyperLink HL = new HyperLink();
HL.ID = "HyperLink" + i++;
HL.Text = fi.Name;
HL.NavigateUrl = "downloading.aspx?file=" + fi.Name;
Page.Controls.Add(HL);
Page.Controls.Add(new LiteralControl("<br/>"));
}
}
You can't add it directly to Page.Controls. You have to add it to the ContentPlaceHolder on the page.
Instead of dynamically creating controls, which is rather messy and error-prone, have you considered using an asp:Repeater control and binding the files directly to it? Something like:
<asp:Repeater ID="RepeaterFiles" runat="server">
<ItemTemplate>
<asp:HyperLink runat="server" Text='<%# Container.DataItem %>'
NavigateUrl='<%# String.Format("downloading.aspx?file={0}", Container.DataItem)%>' />
<br />
</ItemTemplate>
</asp:Repeater>
and in code behind:
DirectoryInfo di = new DirectoryInfo(Server.MapPath("~/ProjectsUpload"));
RepeaterFiles.DataSource = di.GetFiles();
RepeaterFiles.DataBind();
That way you can use declarative mark-up to control layout and keep the logic in your code-behind.
Put a PlaceHolder control on your page:
<asp:PlaceHolder runat="server" ID="ph" />
In your code behind write like:
HyperLink HL = new HyperLink();
HL.ID = "HyperLink" + i++;
HL.Text = fi.Name;
HL.NavigateUrl = "downloading.aspx?file=" + fi.Name;
ph.Controls.Add(HL);
ph.Controls.Add(new Literal { Text = "<br/>"});
I'm making use of the newly C# 3 feature on that last line to set the Text property.
Have you used the debugger to step through the loop to verify that it processes at least one file?
Instead of adding the links to Page.Controls, you could put a list control on the page, and then add each link within a list item. Then you'd know precisely where on the page they should appear.
Create a Panel or a Label in the Page's Content area, and add your HyperLinks into the Controls collection of the Panel.
(Stepping through the code to check whether the IIS App actually enumerates any files in the directory would help too.)

Updating placeholder during runtime

here is the problem I am having with placeholder:
I have a repeater and within that repeater, I have an item template. Now this template is formatted with a couple of tables, but for this question I have removed them to make things easier to read:
<asp:Repeater ID="Repeater1" OnItemDataBound="R1_ItemDataBound" runat="server">
<ItemTemplate>
<asp:PlaceHolder ID="phAnswers" runat="server"></asp:PlaceHolder>
</ItemTemplate>
</asp:Repeater>
Then, on the event OnItemDataBound, I create a new placeholder, bind it to the existing on (phAnswers), however the placeholder is not updated with the radiobuttons/textboxs that are created:
Dim rdList As New RadioButtonList
Dim newRadio As New RadioButton
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim tempPH As PlaceHolder
tempPH = e.Item.FindControl("phAnswers")
For x As Integer = 0 To (t_MC.Count - 1)
newRadio = New RadioButton
newRadio.ID = "Answer" + x.ToString
newRadio.Text = t_MC(x).Value
rdList.Controls.Add(newRadio)
Next
tempPH.Controls.Add(rdList)
Any ideas why phAnswers is not updated with the new tempPH placeholder?
Cheers
OnItemDataBound may be too late to add controls. Try it in OnItemCreated and see if that helps. It's a quick test - just change your repeater event declaration like this:
OnItemCreated="R1_ItemDataBound"
If this idea doesn't help, you can easily switch it back.
Edit - I just noticed something. To populate a RadioButtonList, you should use ListItems, like this:
ListItem item - new ListItem("your text", "your value");
rdList.Items.Add(item);
This is probably why your RadioButtonList did not appear, but lone radio buttons worked.
Try using a Panel instead of a PlaceHolder

AutoCompleteExtender control in a repeater

I have an AutoCompleteExtender AjaxControlToolkit control inside a repeater and need to get a name and a value from the web service. The auto complete field needs to store the name and there is a hidden field that needs to store the value. When trying to do this outside of a repeater I normally have the event OnClientItemSelected call a javascript function similiar to
function GetItemId(source, eventArgs)
{
document.getElementById('<%= ddItemId.ClientID %>').value = eventArgs.get_value();
}
However since the value needs to be stored in a control in a repeater I need some other way for the javascript function to "get at" the component to store the value.
I've got some JavaScript that might help you. My ASP.Net AutoComplete extender is not in a repeater, but I've modified that code to detect the ID of the TextBox you are going to write the erturned ID to, it should work (but I haven't tested it all the way through to post back).
Use the value from 'source' parameter in the client side ItemSelected method. That is the ID of the calling AutoComplete extender. Just make sure that you assign an ID the hidden TextBox in the Repeater Item that is similar to the ID of the extender.
Something like this:
<asp:Repeater ID="RepeaterCompareItems" runat="server">
<ItemTemplate>
<ajaxToolkit:AutoCompleteExtender runat="server"
ID="ACE_Item"
TargetControlID="ACE_Item_Input"
...other properties...
OnClientItemSelected="ACEUpdate_RepeaterItems" />
<asp:TextBox ID="ACE_Item_Input" runat="server" />
<asp:TextBox ID="ACE_Item_IDValue" runat="server" style="display: none;" />
</ItemTemplate>
</asp:Repeater>
Then the JS method would look like this:
function ACEUpdate_CustomerEmail(source, eventArgs) {
UpdateTextBox = document.getElementById(source.get_id() + '_IDValue');
//alert('debug = ' + UserIDTextBox);
UpdateTextBox.value = eventArgs.get_value();
//alert('customer id = ' + UpdateTextBox.value);
}
There are extra alert method calls that you can uncomment for testing and remove for production. In a simple and incomplete test page, I got IDs that looked like this: RepeaterCompareItems_ctl06_ACE_Item_IDValue (for the text box to store the value) and RepeaterCompareItems_ctl07_ACE_Item (for the AC Extender) - yours may be a little different, but it looks practical.
Good Luck.
If I understand the problem correctly, you should be able to do what you normally do, but instead of embeding the ClientId, use the 'source' argument. That should allow you to get access to the control you want to update.
Since you are using a Repeater I suggest wiring the OnItemDataBound function...
<asp:Repeater id="rptResults" OnItemDataBound="FormatResults" runat="server">
<ItemTemplate>
<asp:PlaceHolder id="phResults" runat="server" />
</ItemTemplate>
</asp:Repeater>
Then in the code behind use something like
`Private Sub FormatResults(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)
Dim dr As DataRow = CType(CType(e.Item.DataItem, DataRowView).Row, DataRow) 'gives you access to all the data being bound to the row ex. dr("ID").ToString
Dim ph As PlaceHolder = CType(e.Item.FindControl("phResults"), PlaceHolder)
' programmatically create AutoCompleteExtender && set properties
' programmatically create button that fires desired JavaScript
' use "ph.Controls.Add(ctrl) to add controls to PlaceHolder
End Sub`
Voila

asp:repeater - headers at section change

is there any way to bring up a subheader row at changes in a field in an databound asp:repeater control e.g.
Instead of
country | colour | number
uk | red | 3
uk | green | 3
france | red 3
Do this:
==UK==
colour | number
red | 3
green 3
==FRANCE==
colour | number
red | 3
Many thanks for any help.
There's no built-in support, but that doesn't mean it's impossible.
You'll need to over-ride the OnItemDataBound event, and have something like this in markup:
<asp:Repeater OnItemDataBound="NextItem" ... >
<ItemTemplate><asp:Literal Id="Header" Visible="False" Text="{0}<strong>{1}</strong><br/><table>" ... />
<tr>
<td><asp:Label id="Color" Text="<%# Eval("Color")" ... /></td>
<td><asp:Label id="Number" Text="<%# Eval("Number")" ... /></td>
</tr>
</ItemTemplate>
</asp:Repeater></table>
Then in the code-behind:
private string CurCountry = string.Empty;
private void NextItem(object sender, RepeaterItemEventARgs e)
{
if ( e.Item.ItemType != ListItemType.Item
&& e.Item.ItemType != ListItemType.AlternatingItem) return;
DbDataRecord row = (DbDataRecord)e.Item.DataItem;
if (CurCountry != row["country"].ToString() )
{
string prev = (CurCounter == string.Empty)?"":"</table>";
CurCountry = row["country"].ToString();
Literal header = (Literal)e.Item.FindControl("Header");
Literal footer = (Literal)e.Item.FindControl("Footer");
header.Text = string.Format(header.Text, prev, CurCountry);
header.Visible = true;
}
}
Another solution is to simply use two repeaters, one nested within the other. You can pass your groups with the child records to the first repeater, and on the ItemDataBound of the groups repeater, pass the child records to the child repeater and call DataBind() there.
This is more code but does actually give you more control over the layout without having HTML creation code in your code-behind.
As you can see here, we have a parent repeater and in the item template we can customise each group as we see fit. In the ChildRepeater, we have our item template in which we can customise each item inside the grouping. Very clean and all with declarative UI.
<asp:Repeater runat="server" id="GroupRepeater">
<ItemTemplate>
<asp:Literal runat="server" id="HeaderText" />
<asp:Repeater runat="server id="ChildRepeater">
<ItemTemplate>
<asp:Literal runat="server" id="InfoGoesHere" />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
In the code behind we can have something like this:
private void GroupRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
//Get the child records, this can be any data structure you want
SomeChildCollection children = ((SomeGroupCollection)e.Item.DataItem).Children;
//Find the child repeater
Repeater childRepeater = e.Item.FindControl("ChildRepeater") as Repeater;
childRepeater.ItemDataBound += SomeMethod;
childRepeater.DataSource = children;
childRepeater.DataBind();
}
After binding each child you can subscribe to the ItemDataBound event and do the child binding to controls as you see fit.
To joel Solution, I may advice following - change this line:
header.Text = string.Format("<strong> {0} </strong><br/><table>", CurCountry);
to
header.Text = string.Format(header.Text, CurCountry);
And than you can customize look & feel from .as?x file.
Ah - you're after a grouping repeater. The solution that I've adapted in the past seems to have disappeared. Maybe you can find it. But anyway, a search for grouping repeaters should help.
There seem to be a few bugs in the dotnetjunkies code but I've found a much simpler solution here http://www.west-wind.com/weblog/posts/140753.aspx
Now repeaters don't support grouping, so you have to do this on your own, but it's pretty easy to do. In the repeater above the following data expression is responsible for the grouping:
<%# this.RenderGroup(Eval("Group") as
string) %>
The expression calls a method on the form to render an extra div tag. The code for this simple method looks like this:
string LastGroup = "###~";
protected string RenderGroup(string Group) {
if (Group == this.LastGroup)
return ""; // *** Group has changed
this.LastGroup = Group;
return "<div class='groupheader'>" +Group + "</div>";
}
This code gets called for every item and it simply checks to see if the group has changed. If it hasn't nothing is returned otherwise a simple div tag is returned as a string to embed into the markup. I chose to send back the HTML but I suppose you could also return true or false and conditionally render a control in the Repeater which would make the CSS Nazis happier .

Resources