I'm trying to get a column value of the first element on a repeater, and use it on the repeater's HeaderTemplate. After searching and trying many ways of achieving this through intellisense, I gave up and decided to post this question here.
My code is as follows:
Frontend
<asp:Repeater ID="states" runat="server">
<HeaderTemplate>
<h1>Stage: <asp:Literal ID="stageName" runat="server"></asp:Literal></h1>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# DataBinder.Eval(Container.DataItem, "StateName") %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
Backend
protected void BindStageStates()
{
List<StagesStatesModel> statesList = App.Services.Stages.StagesService.GetStatesByStage(Page.DefaultApp, 1, Page.DefaultCultureId).Where(p => p.StateActive == true).ToList();
states.ItemDataBound += new RepeaterItemEventHandler(rptStagesStatesDataBound);
states.DataSource = statesList;
states.DataBind();
}
void rptStagesStatesDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Header)
{
Literal stageName = (Literal)e.Item.FindControl("stageName");
stageName.Text = // Something to go here..
}
}
Thanks in advance!
Try OnItemCreated
protected void Repeater_OnItemCreated(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Footer)
{
e.Item.FindControl(ctrl);
}
if (e.Item.ItemType == ListItemType.Header)
{
e.Item.FindControl(ctrl);
}
}
By:
How to find controls in a repeater header or footer
Related
I need to create a data-bound control where each item renders <tbody><ItemTemplate></tbody>. Further, I'd also like to put the <HeaderTemplate> in a <thead> rather than a <tbody> row as the <asp:DataList> does. I need full control of the item template. It needs to be able to render an editable row, like the DataList does.
I believe I need to make a custom control for this (but if not, please let me know--it would save a lot of time). What's the best parent class to extend? My guess is that it's either DataList or DataBoundControl.
Looks like what I'm looking for is <asp:Repeater> with a little extra code for editing since it doesn't have an <EditItemTemplate>.
.ascx
<asp:Repeater id="rItems" runat="server" OnItemCommand="rItems_ItemCommand" OnItemDataBound="rItems_ItemDataBound">
<HeaderTemplate>
<table>
<thead>...</thead>
</HeaderTemplate>
<ItemTemplate>
<tbody id="itemRows" runat="server">
...
<asp:Button ... CommandName="Edit" />
...
</tbody>
<tbody id="editItemRows" runat="server" visible="false">...</tbody>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
.ascx.cs
private int m_editIndex = -1;
protected void rItems_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
switch (e.CommandName)
{
case "Edit":
m_editIndex = e.Item.ItemIndex;
break;
... // Cancel, Update, Delete, etc
case "Cancel":
m_editIndex = -1;
break;
}
BindItemsDataSource();
}
protected void rItems_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item | e.Item.ItemType == ListItemType.AlternatingItem)
{
bool edit = e.Item.ItemIndex == m_editIndex;
HtmlGenericControl tbody = e.Item.FindControl("itemRows") as HtmlGenericControl;
tbody.Visible = !edit;
tbody = e.Item.FindControl("editItemRows") as HtmlGenericControl;
tbody.Visible = edit;
if (edit)
{
PopulateEditableFieldValues(e.Item);
}
}
}
I have three repeaters with a parent child relationship (so we have a parent repeater, and child repeater, and a child-child repeater) with the inner-most repeater not being triggered. here is my aspx page for the layout:
<asp:Repeater ID="rptMission" runat="server">
<HeaderTemplate>
<ul id="acc1" class="ui-accordion-container">
</HeaderTemplate>
<ItemTemplate>
<li>
<div class="ui-accordion-left"></div>
<a class="ui-accordion-link acc1"><%# Eval("Name") %><span class="ui-accordion-right"></span></a>
<div>
<ul class="ui-accordion-container" id="acc2">
<asp:Repeater ID="rptActivity" runat="server">
<ItemTemplate>
<li>
<div class="ui-accordion-left"></div>
<a class="ui-accordion-link acc2"><%# Eval("Name") %>
<span class="ui-accordion-right"></span></a>
<div>
<asp:Repeater ID="rptProject" runat="server">
<ItemTemplate>
<%# Eval("Name") %><br/>
</ItemTemplate>
</asp:Repeater>
</div>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</div>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
The top two repeaters work great but the 'rptProject' repeater doesn't get triggered. Here is my code behind:
protected void Page_Load(object sender, EventArgs e)
{
_presenter = new TierTypesPresenter(this);
rptMission.ItemDataBound += new RepeaterItemEventHandler(rptMission_ItemDataBound);
RaiseStartUp();
}
void rptMission_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
Mission row = (Mission)item.DataItem;
if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
{
var rptActivity = (Repeater)item.FindControl("rptActivity");
var activity = _presenter.GetActivitiesByMission(row.Id);
rptActivity.DataSource = activity;
rptActivity.DataBind();
}
}
void rptActivity_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
Activity row = (Activity)item.DataItem;
if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
{
var rptProject = (Repeater)item.FindControl("rptProject");
var project = _presenter.GetProjectsByActivities(row.Id);
rptProject.DataSource = project;
rptProject.DataBind();
}
}
public void SetMissions(IEnumerable<Mission> missionList)
{
rptMission.DataSource = missionList;
rptMission.DataBind();
}
If I could trigger the second ItemDataBound event 'rptActivity_ItemDataBound' I think it would work fine but it gets skipped over. Thanks for any insight!
I solved my problem by putting the third repeater binding into the second repeaters ItemBoundEvent. Here is the updated code for any interested:
void rptMission_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
Mission row = (Mission)item.DataItem;
if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
{
var rptActivity = (Repeater)item.FindControl("rptActivity");
var activity = _presenter.GetActivitiesByMission(row.Id);
var i = 0;
foreach (Activity data in activity)
{
RepeaterItem activityItem = rptActivity.Items[i];
var rptProject = (Repeater)activityItem.FindControl("rptProject");
var project = _presenter.GetProjectsByActivities(data.Id);
rptProject.DataSource = project;
rptProject.DataBind();
i++;
}
rptActivity.DataSource = activity;
rptActivity.DataBind();
}
}
I guess you are missing this line of code:
rptActivity .ItemDataBound += new RepeaterItemEventHandler(rptActivity_ItemDataBound);
It is easier to set the events in the asp file by the way...
Lets say I have the following:
<asp:Repeater ID="repSubItems" runat="server" DataSource="<%# SubItems %>" >
<ItemTemplate>
<sc:FieldRenderer ID="FieldRenderer1"
FieldName="BlurbSpot_Content_SubHeading"
runat="server"
Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>" />
</ItemTemplate>
</asp:Repeater>
I want to in code behind be able to do:
FieldRenderer1.Style["Width"] = MyCoolWidth;
But within the Repeater I cannot access the FieldRenderer1 control.
You will need to handle the ItemDataBound event of the repSubItems repeater. Example:
protected void repSubItems_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var fieldRenderer1 = e.Item.FindControl("FieldRenderer1") as Sitecore.Web.UI.WebControls.FieldRenderer;
if (fieldRenderer1 != null)
{
fieldRenderer1.Style["Width"] = MyCoolWidth;
}
}
}
You need to find the row your are looking for specifically in the Repeater and then find the control. Here is an example that can do it for all items in your Repeater:
// repeater item
foreach (Control cr in repSubItems.Controls)
{
// assuming this is your templated control name and not the final output name
FieldRenderer founcControl = cr.FindControl("FieldRenderer1") as FieldRenderer;
founcControl .Style["Width"] = MyCoolWidth;
}
The better way to do this would be to implement the OnDataBinding for your control specifically because then you have no searching to do:
<sc:FieldRenderer ID="FieldRenderer1" FieldName="BlurbSpot_Content_SubHeading"
runat="server" Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>"
OnDataBinding="FieldRenderer1_DataBinding" />
protected void FieldRenderer1_DataBinding(object sender, System.EventArgs e)
{
FieldRenderer rend = (FieldRenderer)(sender);
// you can do whatever you want to rend at this point and it is scoped to ONLY
// the control so you never have to search for it.
rend.Style["Width"] = MyCoolWidth;
}
I have a repeater with a textbox inside. I am trying to edit the information inside the textbox, retrieve the new data, and write to the DB. With my code its giving me the original info that was in the box. Not the new information that I have added. Here is my code
html:
<asp:LinkButton id="saveReviewLinkButton" text="Save" runat="server" onCommand="saveReviewLinkButton_OnCommand" />
<table>
<asp:Repeater id="ReviewRepeater" runat="server" onItemDataBound="ReviewRepeater_ItemDataBound">
<itemtemplate>
<tr >
<td ><asp:TextBox id="titleLabel" runat="server" width="200px" textMode="MultiLine"/></td>
</tr>
</itemtemplate>
</table>
c#:
protected void ReviewRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
Review review = (Review)e.Item.DataItem;
TextBox titleLabel = (TextBox)e.Item.FindControl("titleLabel");
titleLabel.Text = review.Title;
}
}
protected void saveReviewLinkButton_OnCommand(object sender, EventArgs e)
{
TextBox titleLabel = new TextBox();
foreach (RepeaterItem dataItem in ReviewRepeater.Items)
{
titleLabel = (TextBox)dataItem.FindControl("titleLabel");
string newInfo = titleLabel.Text;
}
}
Please make sure, you are binding the data to the repeater by checking in page load
if(!IsPostBack)
BindData();
I know how to use a simple If statement wrapped in the <%# tags to hide something, but I don't know how to do it in a repeater when I need to access Container.DataItem, as in I need the dataItem currently being 'repeated'
eg
if (CurrentValidationMessage.Link != "")
{
show a hyperlink
}
Markup:
<asp:Repeater ID="repValidationResults" runat="server">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<a href='<%# ((MttImportValidationMessage)Container.DataItem).EditLink %>'> Link to erroneous Milestone </a>
<%# ((MttImportValidationMessage)Container.DataItem).Message %>
<br />
</ItemTemplate>
</asp:Repeater>
It might be more maintainable if you just tagged the controls in the repeater with id's and runat='server' and reference the DataItem in the ItemDataBound event by using e.Item.DataItem.
Then use e.Item.FindControl to reference your controls in the ItemTemplate and perform your logic.
protected void repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
Domain.Employee employee = (Domain.Employee)e.Item.DataItem;
Control myControl = (Control)e.Item.FindControl("controlID");
//Perform logic
}
}
use ItemDataBound Event with repeater, and make the "a" tag with a runat="server" property and ID
protected void repValidationResults_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
if (item.ItemType == ListItemType.AlternatingItem || item.ItemType == ListItemType.Item)
{
HyperLink link = (HyperLink) item.FindControl("link");
//Do all your logic here :)
}
}
MarkUp:
<asp:Repeater ID="repValidationResults" runat="server">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<a runat="server" ID="link"> Link to erroneous Milestone </a>
<%# ((MttImportValidationMessage)Container.DataItem).Message %>
<br />
</ItemTemplate>
</asp:Repeater>