Creating ASP.Net DataBound control that renders table with multiple tbodies - c#

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);
}
}
}

Related

C# Get first repeater item column value to use on HeaderTemplate

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

Change repeater row value?

im trying to change a value inside my repeater : (via itemdatabound event)
if the year is empty - set value blabla
my repeater :
<ItemTemplate>
<tr >
<td >
<%#Eval("year") %>
</td>
my c# code :
void RPT_Bordereaux_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
if (string.IsNullOrEmpty(((DataRowView)e.Item.DataItem)["year"].ToString()))
{
(((DataRowView)e.Item.DataItem)["year"]) = "blabla"; // ???????
}
}
it does change but not displayed in repeater ( the old value is displayed).
one solution is to add a server control or literal ( runat server) in the itemTemplate - and to "findControl" in server - and change its value.
other solution is by jQuery - to search the empty last TD.
but - my question :
is there any other server side solution ( ) ?
you can try something like this :
Repeater in .aspx:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<table>
<tr>
<td> <%# GetText(Container.DataItem) %></td>
</tr>
</table>
</ItemTemplate>
</asp:Repeater>
.cs :
protected static string GetText(object dataItem)
{
string year = Convert.ToString(DataBinder.Eval(dataItem, "year"));
if (!string.IsNullOrEmpty(year))
{
return year;
}
else
{
return "blahblah";
}
}
IN GetText Method you can able to check by string that Empty or not than return string.
You could try to use the itemcreated event which occurs before the control is bound and not after the control is bound. Example in first link:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.repeater.itemcreated.aspx
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.repeater_events.aspx
ItemDataBound Occurs after an item in the Repeater control is data-bound but before it is rendered on the page.
HTML FILE
<asp:Repeater ID="RPT_Bordereaux" runat="server">
<ItemTemplate>
<table>
<tr>
<td> <%# GetValue(Container.DataItem) %></td>
</tr>
</table>
</ItemTemplate>
</asp:Repeater>
.CS CODE
protected void RPT_Bordereaux_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
}
}
protected static string GetValue(object dataItem)
{
string year = Convert.ToString(DataBinder.Eval(dataItem, "year"));
if (!string.IsNullOrEmpty(year))
{
return Convert.ToString(year);
}
else
{
return "blahbla";
}
}
This should work

catching SelectedIndexChanged of a dropdown list inside a repeater

I am trying to catch the SelectedIndexChanged of a DropDownList inside a Repeater. I have searched the internet but could not find a specific answer any help would be great. This is my code.
page.aspx
<asp:Repeater id="CategoryMyC" OnItemCommand="SomeEvent_ItemCommand" runat="server">
<HeaderTemplate>
<table><tr>
</HeaderTemplate>
<ItemTemplate>
<td>
<table width="100%">
<tr>
<th>Edit Carousel Item</th>
</tr>
<tr>
<td>Choose a product:</td>
</tr>
<tr>
<td>
<asp:DropDownList ID="ddlMcProducts"
DataTextField="Name"
onselectedindexchanged="MyListIndexChanged"
AutoPostBack="true"
DataSource='<%# ProductsManager.GetMerchantProductRepeater(Convert.ToInt32(Eval("MID"))) %>'
runat="server">
</asp:DropDownList>
</td>
</tr>
</table>
</td>
</ItemTemplate>
<FooterTemplate>
</tr>
</table>
</FooterTemplate>
</asp:Repeater>
page.aspx.cs
In the Page_Load:
List<CarouselProducts> CP = CarouselProductsManager.GetCarouselItems(Convert.ToInt32(Session["Mid"]));
CategoryMyC.DataSource = CP;
CategoryMyC.ItemDataBound += new RepeaterItemEventHandler(RepeaterItemDataBound);
CategoryMyC.DataBind();
Other events:
protected void ddlMcProducts_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList d = (DropDownList)sender;
// Use d here
System.Windows.Forms.MessageBox.Show("I am changing");
}
protected virtual void PageInit(object sender, EventArgs e)
{
//get all the Carousel item of the merchant
List<CarouselProducts> CP = CarouselProductsManager.GetCarouselItems(Convert.ToInt32(Session["Mid"]));
//MerchantCategoryMyCarousel.DataSource = CP;
//MerchantCategoryMyCarousel.DataBind();
MerchantCategoryMyCarousel.DataSource = CP;
MerchantCategoryMyCarousel.ItemDataBound += new RepeaterItemEventHandler(RepeaterItemDataBound);
MerchantCategoryMyCarousel.DataBind();
}
protected virtual void RepeaterItemDataBound(object sender, RepeaterItemEventArgs e)
{
DropDownList theDropDown = sender as DropDownList;
if (e.Item.ItemType == ListItemType.EditItem)
{
DropDownList MyList = (DropDownList)e.Item.FindControl("ddlMcProducts");
if (MyList == null)
{
System.Windows.Forms.MessageBox.Show("Did not find the controle");
}
else
MyList.SelectedIndexChanged += new EventHandler(MyListIndexChanged);
}
}
protected virtual void MyListIndexChanged(object sender, EventArgs e)
{
System.Windows.Forms.MessageBox.Show("I am changing");
}
protected void SomeEvent_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
if (e.CommandSource.GetType() == typeof(DropDownList))
{
DropDownList ddlSomething = (DropDownList)e.Item.FindControl("ddlSomething");
System.Windows.Forms.MessageBox.Show("I am changing");
//Now you can access your list that fired the event
//SomeStaticClass.Update(ddlSomething.SelectedIndex);
}
}
I need to catch the SelectedIndexChanged of the populated DropDownList for each one generated.
You've got quite a mismatch of code going on here - using System.Windows.Forms in an ASP.NET application is just one of the issues. You appear to be assigning event handlers in the code-behind and in the markup (nothing necessarily bad about that, but there's seems to be no rhyme or reason to how you're doing it).
You're Repeater's ItemCommand event is bound to a method that is looking for a DropDownList that has a different ID than the one in your markup.
If you're using the System.Windows.Forms.MessageBox to debug (ala old school JavaScript and other language "debugging" methods), save yourself a world-class headache (not to mention a lot of unnecessary code cleanup when you're done with development) and step through your code in the debugger.
I'm not sure how the page will render, but I don't think you're using the HeaderTemplate and FooterTemplate quite the way they're intended.
All that said, try something like this:
Markup (ASPX page):
<asp:Repeater id="CategoryMyC" OnItemCommand="CategoryMvC_ItemCommand" OnItemDataBound="CategoryMvC_ItemDataBound" runat="server">
<HeaderTemplate>
<table>
<tr>
<th>Edit Carousel Item</th>
</tr>
</table>
</HeaderTemplate>
<ItemTemplate>
<table width="100%">
<tr>
<td>Choose a product:</td>
</tr>
<tr>
<td>
<asp:DropDownList ID="ddlMcProducts"
DataTextField="Name"
OnSelectedIndexChanged="ddlMcProducts_SelectedIndexChanged"
AutoPostBack="true"
DataSource='<%# ProductsManager.GetMerchantProductRepeater(Convert.ToInt32(Eval("MID"))) %>'
runat="server">
</asp:DropDownList>
</td>
</tr>
</table>
</ItemTemplate>
</asp:Repeater>
Code Behind (APSX.CS)
protected void Page_Load(object sender, EventArgs e)
{
List<CarouselProducts> CP = CarouselProductsManager.GetCarouselItems(Convert.ToInt32(Session["Mid"]));
CategoryMyC.DataSource = CP;
//This can be assigned in the markup
//CategoryMyC.ItemDataBound += new RepeaterItemEventHandler(RepeaterItemDataBound);
CategoryMyC.DataBind();
}
protected void ddlMcProducts_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList d = (DropDownList)sender;
// Use d here
}
protected void CategoryMyC_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
DropDownList theDropDown = sender as DropDownList;
if (e.Item.ItemType == ListItemType.EditItem)
{
DropDownList MyList = (DropDownList)e.Item.FindControl("ddlMcProducts");
// This section is not needed for what you are doing with it:
// If the control is null, handle it as an error
// There's no need to give it an event handler if it does exist, because
// you already did so in the markup
//if (MyList == null)
//{
//System.Windows.Forms.MessageBox.Show("Did not find the controle");
//}
//else
//MyList.SelectedIndexChanged += new EventHandler(MyListIndexChanged);
//}
}
}
protected void CategoryMyC_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
if (e.CommandSource.GetType() == typeof(DropDownList))
{
// Note the correct control name is being passed to FindControl
DropDownList ddlSomething = (DropDownList)e.Item.FindControl("ddlMcProducts");
//System.Windows.Forms.MessageBox.Show("I am changing");
//Now you can access your list that fired the event
//SomeStaticClass.Update(ddlMcProducts.SelectedIndex);
}
There may be more issues at hand as well - but this will hopefully streamline it enough for you to make some progress.
protected void drpOrganization_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList ddl = (DropDownList)sender;
RepeaterItem item = (RepeaterItem)ddl.NamingContainer;
if (item != null)
{
CheckBoxList list = (CheckBoxList)item.FindControl("chkSite");
if (list != null)
{
}
}
}

Iterate through repeater

There's this repeater...
<asp:Repeater ID="myRepeater" OnItemCommand="rpt1_ItemCommand" runat="server" OnItemDataBound="rpt1_OnItemDataBound">
<HeaderTemplate>
<table width="99%" border="0" cellpadding="0" cellspacing="0">
<tr class="lgrey">
<td>Default</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<table>
<tr>
<td>
<asp:LinkButton ID="lnk1" Text="Make Default" CommandName="SetDefault" runat="server" Visible="True" CommandArgument='<%#Eval("UserID") %>' CausesValidation="false"></asp:LinkButton>
<asp:Label ID="label1" Text="Yes" runat="server" Visible="False"></asp:Label>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
What I want is that when user clicks on any of the "lnk1" link button in the lsit that repeater renders,
the link should be replaced with the label "label1"..ie when the user clicks on "Make Default" link, it should be replaced
with "Yes" label
Now when I click 2 link buttons, both get their label "Yes" displayed where as I want only one link button to display Yes
ie the one which has been clciked and rest of the items should display "Make Default" link button only.
ie Only ONE item should be displaying "Yes" label...now how do I iterate through the repeater items to set only ONE item
as default and not multiple ??
You can iterate the repeater items collection,
protected void myRepeater_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
int selectedIndex = e.Item.ItemIndex;
foreach(RepeaterItem item in myRepeater.Items)
{
((LinkButton)item.FindControl("lnk1")).Visible = (item.ItemIndex != selectedIndex);
((Label)item.FindControl("label1")).Visible = (item.ItemIndex == selectedIndex);
}
}
The pros of this option are: 1. no second hit on the database.
Or I would put my logic in the ItemDataBound event instead, store the clicked link button index in a member variable and call DataBind in the command event handler.
private int selectedIndex = -1;
//...
protected void myRepeater_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
selectedIndex = e.Item.ItemIndex;
myRepeater.DataSource = MyGetDataMethod();
myRepeater.DataBind();
}
In the ItemDataBound handler compare the current index with the stored index and if they match show the label.
protected void myRepeater_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
if(e.Item.ItemIndex == selectedIndex)
{
((LinkButton)e.Item.FindControl("lnk1")).Visible = false;
((Label)e.Item.FindControl("label1")).Visible = true;
}
}
}
The cons of this second option are: 1. A second hit on the database. 2. If the user clicks say row two, and some other user inserts a new address record, row 2 may now be something different when you re-bind. Also if you're not using an order by that could change between database calls and your stored selectedIndex could be invalidated thatway too.
So in conclusion I'd go with option one now I've thought it all the way through.

Hide an element in ASP.net based on an if inside a Repeater

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>

Categories

Resources