I'm trying to find controls in a nested listview in a parent listview on postback.
if (Page.IsPostBack)
{
ListView ChildLV = (ListView)(LVParent.FindControl("ChildLV"));
foreach (ListViewItem item in ChildLV.Items)
{
item.FindControl("NestListViewChildControl");
}
}
You have to loop the items in the parent ListView and use FindControl in each of those to locate the nested ListView.
if (Page.IsPostBack)
{
foreach (ListViewItem item in LVParent.Items)
{
ListView ChildLV = item.FindControl("ChildLV") as ListView;
}
}
aspx
<asp:ListView ID="LVParent" runat="server">
<ItemTemplate>
<asp:ListView ID="ChildLV" runat="server">
<ItemTemplate>
</ItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>
I am trying to get a page to display information in a row layout using repeaters. I have one working that allows me to dynamically create hyperlinks, however i cant get my nested repeater to work to display the date the file was created. Is it possible to use repeaters to dynamically display multiple variables from lists as i'm trying to do below?
.aspx
<asp:Repeater id="repLinks" runat="server">
<ItemTemplate>
<tr><td>
<asp:HyperLink runat="server" NavigateUrl='<%# Container.DataItem.ToString() %>' Text="<%# Container.DataItem.ToString().Split('\\').Last() %>" />
<td>
<asp:Repeater ID="Repeater2" runat="server" OnItemDataBound="Repeater2_ItemDataBound" >
<ItemTemplate>
<%# Container.DataItem.ToString()%>
</ItemTemplate>
</asp:Repeater>
</td>
<td>
Submitted By <!--add repeater-->
</td>
<td>
Mark as Billed <!--add repeater-->
</td>
</td></tr>
</ItemTemplate>
</asp:Repeater>
.aspx.cs
public List<string> CD = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
//Welcomes User
string Uname = Environment.UserName;
UserName.Font.Size = 17;
UserName.Text = "Welcome: " + Uname;
//gives path and constructs lists for directory paths and file links
string root = "C:\\Users\\James\\Documents\\Visual Studio 2015\\WebSites";
List<string> lLinks = new List<string>();
//adds files to list
foreach (var path in Directory.GetDirectories(#root))
{
foreach (var path2 in Directory.GetFiles(path))
{
lLinks.Add(path2);
CD.Add(File.GetCreationTime(path2).Date.ToString("yyyy-mm-dd"));
}
}
//Define your list contents here
repLinks.DataSource = lLinks;
repLinks.DataBind();
}
protected void Repeater2_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater Repeater2 = (Repeater)(e.Item.FindControl("Repeater2"));
Repeater2.DataSource = CD;
Repeater2.DataBind();
}
}
The issue with your code is that you are binding the nested repeater control (Repeater2) in the ItemDataBound event of Repeater2 repeater itself which will never get fired because ItemDataBound event is fired for each item in collection when it is bounded to the repeater control.
You should write the logic in ItemDataBound event of your parent repeater like this:-
<asp:Repeater id="repLinks" runat="server" OnItemDataBound="Repeater1_ItemDataBound">
Then, write the logic in this event handler:-
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
Repeater Repeater2 = (Repeater)(e.Item.FindControl("Repeater2"));
Repeater2.DataSource = CD;
Repeater2.DataBind();
}
}
Also, In the Page_Load event you should bind the Parent Repeater Repeater1 on just the initial page load so wrap it inside !IsPostBack and populate your datasource lLinks & CD from a separate method intead of doing it in Page_Load event.
I have an edit button and a dropdownlist inside a formview. I am using Linq To Entities to get the data I need to work with and have no problem populating and viewing the formview itemtemplate.
However, the dropdownlist control (id="ddlEligibility") is only in theedititemtemplate (I use a textbox in the itemtemplate to display the current value) and I am having a problem getting the value initially shown in the itemtemplate to appear when the edititemtemplate is shown. All I get right now is the dropdownlist with the first value shown. I want the value from the itemtemplate to appear by default and the user can change it if they wish. Here is the code that populates the dropdownlist. Anyone have a suggestions?
protected void btnEdit_Click(object sender, EventArgs e)
{
fvSubscriber.ChangeMode(FormViewMode.Edit);
fvSubscriber.DataBind();
LifeLineDSEntities context = new LifeLineDSEntities():
var program = from p in context.EligibilityPrograms
select p;
DropDownList ddlEligibility = (DropDownList)(fvSubscriber.FindControl("ddlEligibility")));
if (ddlEligibility != null)
{
ddlEligibility.DataSource = program;
ddlEligibility.DataTextField = "ProgramName";
ddlEligibility.DataValueField = "eligibilityCode";
ddlEligibility.DataBind();
}
}
DropDownlist in FormView...
<form id="form1" runat="server">
<asp:FormView ID="fvSubscriber" runat="server" RenderOuterTable="false" DefaultMode="Readonly" OnModeChanging="fvSubscriberChanging">
<ItemTemplate>
<asp:TextBox ID="txtEligibility" runat="server" Text='<%# Eval("ProgramName") %>' />
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlEligibility" runat="server" />
</EditItemTemplate>
</asp:FormView>
</form>
You could try getting the value of the textbox before you change the formview mode.
TextBox txtEligibility= (TextBox)fvSubscriber.FindControl("txtEligibility");
fvSubscriber.ChangeMode(FormViewMode.Edit);
fvSubscriber.DataBind();
LifeLineDSEntities context = new LifeLineDSEntities():
var program = from p in context.EligibilityPrograms
select p;
DropDownList ddlEligibility = (DropDownList)(fvSubscriber.FindControl("ddlEligibility")));
if (ddlEligibility != null)
{
ddlEligibility.DataSource = program;
ddlEligibility.DataTextField = "ProgramName";
ddlEligibility.DataValueField = "eligibilityCode";
ddlEligibility.DataBind();
if (txtEligibility != null)
{
if(!string.IsNullOrWhiteSpace(txtEligibility.Text))
{
foreach (ListItem item in ddlEligibility.Items)
{
if (item.Text == txtEligibility.Text)
{
ddlEligibility.SelectedValue = txtEligibility.Text;
}
}
}
}
}
I need to know how to nest repeaters within a user control. The html side of things is fine, it's the binding and code behind I need help with. I've only been able to find examples using an sql data source, which doesn't really help.
My repeaters look like this:
<asp:Panel ID="pnlDiscipline" runat="server" CssClass="">
<asp:Repeater ID="rptDiscipline" runat="server">
<ItemTemplate>
<h4><%#Eval("Discipline")%></h4>
<ul>
<asp:Repeater ID="rptPrograms" runat="server">
<ItemTemplate>
<li><asp:HyperLink runat="server" Text='<%#Eval("Name") %>' NavigateUrl='<%#Eval("Link") %>'></asp:HyperLink> <%#Eval ("Notation") %></li>
</ItemTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
What I need to do is hopefully reasonably clear - the h4 discipline should appear once, all the entries that belong to the discipline are listed below, then the next h4, then the appropriate list, the next h4 and so on.
The datasource is a dataview created in the codebehind where each row has 'Name', "Link', 'NOtation' and 'Discipline'. I've bound the dataview to the outermost repeater, and it behaves as expected - lists the discipline name for each entry, but shows no data in the inner repeater.
How do I go about making this work?
EDIT: Just to clarify, I have one datatable in the codebehind. Each row in that table is an item, each item belongs to a discipline. I want to use the outer repeater to list the disciplines, the inner to list the items grouped under each discipline. Like so:
<h4>DISCIPLINE 1</h4>
<ul>
<li>Item</li>
<li>Item</li>
<li>Item</li>
</ul>
<h4>DISCIPLINE 2</h4>
<ul>
<li>Item</li>
<li>Item</li>
</ul>
<h4>DISCIPLINE 3</h4>
<ul>
<li>Item</li>
<li>Item</li>
</ul>
At present, binding the datatable to the outer repeater gives this (example uses the data above):
<h4>DISCIPLINE 1</h4>
<h4>DISCIPLINE 1</h4>
<h4>DISCIPLINE 1</h4>
<h4>DISCIPLINE 2</h4>
<h4>DISCIPLINE 2</h4>
<h4>DISCIPLINE 3</h4>
<h4>DISCIPLINE 3</h4>
I've used OnItemDataBound on the outer repeater as suggested, and as a test case am able to access the data:
protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
DataRowView drView = (DataRowView) e.Item.DataItem;
string name = drView["Name"] as string;
string link = drView["Link"] as string;
string notation = drView["Notation"] as string;
Response.Write(name + link + notation + "<br />")
}
So the data is there, it is exactly what I would expect to see, I just can't get it bound to the inner repeater. If there is a more performant way to achieve the same, I'm happy to rework my solution.
On the outer control, use the ItemDataBound event, like this:
<asp:Repeater ID="rptDiscipline" runat="server"
OnItemDataBound="rptDiscipline_ItemDataBound">
...
Then, in the code-behind, handle the rptDiscipline_ItemDataBound event and manually bind the inner repeater. The repeater's ItemDataBound event fires once for each item that is repeated. So you'll do something like this:
protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
// To get your data item, cast e.Item.DataItem to
// whatever you're using for the data object; for example a DataRow.
// Get the inner repeater:
Repeater rptPrograms = (Repeater) e.Item.FindControl("rptPrograms");
// Set the inner repeater's datasource to whatever it needs to be.
rptPrograms.DataSource = ...
rptPrograms.DataMember = ...
rptPrograms.DataBind();
}
EDIT: Updated to match your question's update.
You need to bind the outer repeater to a data source that has only one record per item you want the repeater to render. That means the data source needs to be a collection/list/datatable/etc that has only the disciplines in it. In your case, I would recommend getting a List<string> of disciplines from the DataTable for the inner collection, and bind the outer repeater to that. Then, the inner repeater binds to a subset of the data in the DataTable, using the ItemDataBound event. To get the subset, filter the DataTable through a DataView.
Here's code:
protected void Page_Load(object sender, EventItems e)
{
// get your data table
DataTable table = ...
if ( !IsPostBack )
{
// get a distinct list of disciplines
List<string> disciplines = new List<string>();
foreach ( DataRow row in table )
{
string discipline = (string) row["Discipline"];
if ( !disciplines.Contains( discipline ) )
disciplines.Add( discipline );
}
disciplines.Sort();
// Bind the outer repeater
rptDiscipline.DataSource = disciplines;
rptDiscipline.DataBind();
}
}
protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
// To get your data item, cast e.Item.DataItem to
// whatever you're using for the data object
string discipline = (string) e.Item.DataItem;
// Get the inner repeater:
Repeater rptPrograms = (Repeater) e.Item.FindControl("rptPrograms");
// Create a filtered view of the data that shows only
// the disciplines needed for this row
// table is the datatable that was originally bound to the outer repeater
DataView dv = new DataView( table );
dv.RowFilter = String.Format("Discipline = '{0}'", discipline);
// Set the inner repeater's datasource to whatever it needs to be.
rptPrograms.DataSource = dv;
rptPrograms.DataBind();
}
If you don't want to do it on the ItemDataBound event, you can also do it inline in your page by binding to a child property of the parent item if the child property is a collection like so:
<asp:Repeater runat="server" ID="OuterRepeater" >
<ItemTemplate>
Outer Content: <%# DataBinder.Eval(Container.DataItem, "ParentProperty")%>
<asp:Repeater runat="server" ID="InnerRepeater" DataSource='<%# DataBinder.Eval(Container.DataItem, "ChildCollection")%>' >
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "ChildProperty")%>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
First you need two lists, the list of disciplines, and then the list of all your data.
Data bind the list of disciplines to the outer repeater. If there are 6 disciplines, the repeater should repeat 6 times.
<asp:Repeater ID="rptDiscipline" runat="server" OnItemDataBound="rptDiscipline_ItemDataBound">
<ItemTemplate>
<h4><%# Eval("Discipline")%></h4>
<ul>
<asp:Repeater runat="server" ID="InnerRepeater" >
<ItemTemplate>
<li>
<asp:Label runat="server" ID="lbl" />
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
Repeater inner= (Repeater) e.Item.FindControl("InnerRepeater");
//You want to bind all the data related to this discipline
DataRowView drView = (DataRowView) e.Item.DataItem;
string discipline= drView["Discipline"] as string;
//filter your total data with ones that match the discipline
inner.DataSource = //data bind the filtered list here
inner.DataBind();
}
I have a dropdownlist inside of a TemplateField, within a GridView.
I would like to dynamically add list items to it and write code to handle when the index changes. How do I go about manipulating the list, since I can't directly reference the DropDownList when it's in a TemplateField.
Here is my code:
<asp:TemplateField HeaderText="Transfer Location" Visible="false">
<EditItemTemplate>
<asp:DropDownList ID="ddlTransferLocation" runat="server" ></asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
If I'm understanding what you want to do correctly, you can handle adding items to your drop down like this:
foreach (GridViewRow currentRow in gvMyGrid.Rows)
{
DropDownList myDropDown = (currentRow.FindControl("ddlTransferLocation") as DropDownList);
if (myDropDown != null)
{
myDropDown.Items.Add(new ListItem("some text", "a value"));
}
}
Then, if you mean handling the index change of the DropDownList you just need to add an event handler to your control:
<asp:DropDownList ID="ddlTransferLocation" runat="server" OnSelectedIndexChanged="ddlTransferLocation_SelectedIndexChanged" AutoPostBack="true"></asp:DropDownList>
Then in that event handler you can use (sender as DropDownList) to get whatever you need from it:
protected void ddlTransferLocation_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList myDropDown = (sender as DropDownList);
if (myDropDown != null) // do something
{
}
}