Here is my scenario:
I have several deals, each has a category, all are grouped by categories as such:
DealView: Name (the category), Deals (List of Deals objects)
the DealViews (List) is bound to the category list view, the listview on item databound generates the corresponding inner listviews and sets their corresponding data pagers paging size,it also decides whether to show the inner pagers or not. The OnLoad event of the categories listview is used for the postback of the any of the internal pagers. I can debug the code and i can see that the Load event is executed, the inner pagers SetPageProperties are also set correctly however nothing changes on the UI no matter how many times I click. If I remove the updatepanel, everything works as expected. Here is some, or alot of code :)
<div class="tabs-content">
<asp:UpdatePanel ID="upDeals" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:ListView ID="lvCategorisedDeals" runat="server" DataKeyNames="Deals" >
<LayoutTemplate>
<asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
<div class="clear"></div>
</LayoutTemplate>
<ItemTemplate>
<div class="tab-item">
<asp:ListView runat="server" ID="lvCategoryDeals">
<LayoutTemplate>
<div class="deals">
<asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
</div>
<div class="clear"></div>
</LayoutTemplate>
<ItemTemplate>
<div class="rc-item">
<h3><%# Eval("Title") %></h3>
<div class="deal-img">
<img src="<%# Eval("ImageUrl") %>" width="168" height="113">
</div>
<div class="deal-data">
<div class="info"><%# Eval("Caption") %></div>
<div class="price"><%# Eval("Currency") %> <%# Eval("DiscountedPrice") %></div>
<div class="deal-booking">Buy Now</div>
</div>
</div>
</ItemTemplate>
</asp:ListView>
<div class="dealsPager">
<asp:DataPager runat="server" ID="pgInner" PagedControlID="lvCategoryDeals" >
<Fields>
<asp:NumericPagerField />
</Fields>
</asp:DataPager>
</div>
</div>
</ItemTemplate>
</asp:ListView>
</ContentTemplate>
</asp:UpdatePanel>
</div>
And in the code behind:
void lvCategorisedDeals_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
foreach (var item in lvCategorisedDeals.Items)
{
if (item.ItemType == ListViewItemType.DataItem)
{
var lvInner = item.FindControl("lvCategoryDeals") as ListView;
if (lvInner == null)
throw new InvalidOperationException("The inner ListView was not found");
var pgInner = item.FindControl("pgInner") as DataPager;
if (pgInner == null)
throw new InvalidOperationException("The inner pager was not found");
if (lvCategorisedDeals.DataKeys == null && lvCategorisedDeals.DataKeys.Count == 0)
throw new InvalidOperationException("The outer ListViews Datakeys do not seem to be set");
var dataItem = lvCategorisedDeals.DataKeys[item.DisplayIndex].Value as List<GRCDeal>;
lvInner.PagePropertiesChanging += new EventHandler<PagePropertiesChangingEventArgs>(
(s, evt) =>
{
pgInner.SetPageProperties(evt.StartRowIndex, evt.MaximumRows, false);
// Get the data for the ListView lvInner
lvInner.DataSource = dataItem;
lvInner.DataBind();
}
);
}
}
}
}
void lvCategorisedDeals_ItemDataBound(object sender, ListViewItemEventArgs e)
{
var listViewDataItem = e.Item as ListViewDataItem;
if (listViewDataItem == null)
return;
if (listViewDataItem.ItemType == ListViewItemType.DataItem)
{
var lvInner = e.Item.FindControl("lvCategoryDeals") as ListView;
if (lvInner == null)
throw new InvalidOperationException("The inner ListView was not found");
var pgInner = e.Item.FindControl("pgInner") as DataPager;
if (pgInner == null)
throw new InvalidOperationException("The inner pager was not found");
var dataItem = listViewDataItem.DataItem as DealView;
pgInner.PageSize = this.PageSize;
pgInner.Visible = dataItem.Deals.Count > this.PageSize;
lvInner.DataSource = dataItem.Deals;
lvInner.DataBind();
}
Additional things to note is that I am passing that List of Deals as DataKeys and I am able to grab it fine. First binding happens on page load. The code is inside a user control part of Visual WebPart (SharePoint 2013).
Appreciate any help since this is killing me.
Related
I try to use a repeater in repeater in ASP.NET, but I want to change datasource from every repeat.
My aspx markup is:
<div class="container px-4 py-5" id="custom-cards">
<asp:Repeater ID="RepeaterKategori" runat="server" OnItemDataBound="ItemBound">
<ItemTemplate>
<h2 class="pb-2 border-bottom"><%#Eval("kategoriAd") %></h2>
<div class="row row-cols-1 row-cols-md-3 g-4">
<asp:Repeater ID="RepeaterAltKategori" runat="server">
<ItemTemplate>
<div class="col">
<div class="card h-100">
<img src="<%#Eval("altkategoriResim") %>" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title"><%#Eval("altkategoriBaslik") %></h5>
<p class="card-text"><%#Eval("altkategoriAciklama") %></p>
</div>
<div class="card-footer">
<small class="text-muted">Teşekkürler : <%#Eval("altkategoriDestekci") %></small>
</div>
</div>
</div>
</ItemTemplate>
</asp:Repeater>
</div>
<div class="d-grid gap-2 my-4">
Tümünü Görüntüle
</div>
</ItemTemplate>
</asp:Repeater>
</div>
My aspx.cs code behind is:
rehber kod = new rehber();
protected void Page_Load(object sender, EventArgs e)
{
RepeaterKategori.DataSource = kod.getDataTable("SELECT KategoriAd FROM kategoriler");
RepeaterKategori.DataBind();
}
protected void ItemBound(object sender, RepeaterItemEventArgs args)
{
if (args.Item.ItemType == ListItemType.Item || args.Item.ItemType == ListItemType.AlternatingItem)
{
DataTable katsay = kod.getDataTable("SELECT * FROM altkategoriler");
int kategoris = katsay.Rows.Count;
for (int i = 1; i == kategoris; i++)
{
Repeater RepeaterAltKategori = (Repeater)args.Item.FindControl("RepeaterAltKategori");
RepeaterAltKategori.DataSource = kod.getDataTable("SELECT TOP 3 * FROM altkategoriler WHERE kategoriId="+i+"");
RepeaterAltKategori.DataBind();
}
}
}
I want another id data like 1,2,3,4 for every repeat. How can I do this? Thanks..
You need to nest two repeaters then.
You have
top table - feed the main repeater - 1 record for each.
child table - feed the child repeater - child table - many records for each.
Also, make sure you ALWAYS use if (!isPostBack) to have a real first page load - if you don't do most (if not all) of your loading and databinding inside of the !IsPostback?
you cannot even really quite much build a working page that can survive post-backs.
Ok, so we have the master (top) repeater.
for the child repeater, you might have one record, maybe many. It don't matter. But WHAT DOES matter is you now have a whole new seperate data set and whole new set of Eval() and binding that belongs to that child table or child data set.
So, lets take a main repeater (our hotels), and for each instance, we drop in another repeater to display the child data (in this case people booked in the hotel).
So, we have this mark-up - note the nested 2nd repeater.
<asp:Repeater ID="repHotels" runat="server" OnItemDataBound="repHotels_ItemDataBound">
<ItemTemplate>
<asp:Label ID="txtHotel" runat="server" Width="240px"
Text='<%# Eval("HotelName") %>' Font-Size="X-Large" >
</asp:Label>
<asp:TextBox ID="txtDescription" runat="server"
Text='<%# Eval("Description") %>'
TextMode="MultiLine" Rows="5" Columns="40" Style="margin-left:20px" >
</asp:TextBox>
<br />
<h4>People Booked</h4>
<asp:Repeater ID="repPeopleBooked" runat="server">
<ItemTemplate>
<asp:Label ID="lFirst" runat="server" Text='<%# Eval("FirstName") %>'>
</asp:Label>
<asp:Label ID="lLast" runat="server" Text='<%# Eval("LastName") %>'
style="margin-left:10px">
</asp:Label>
<br />
</ItemTemplate>
</asp:Repeater>
<%-- our repeat separator --%>
<div style="height:20px">
<hr style="border:1px solid" />
</div>
</ItemTemplate>
</asp:Repeater>
And our code to load. We ONLY load the main repeater data source, and THAT will trigger the item data bound event, and in that event then we deal with EACH separate instance of the child repeater.
Code like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadData();
}
void LoadData()
{
SqlCommand cmdSQL = new SqlCommand("SELECT * from MyHotels ORDER BY HotelName");
repHotels.DataSource = MyRstP(cmdSQL);
repHotels.DataBind();
}
protected void repHotels_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ( (e.Item.ItemType == ListItemType.Item) ||
(e.Item.ItemType == ListItemType.AlternatingItem))
{
// get child nested repeater
Repeater rChild = e.Item.FindControl("repPeopleBooked") as Repeater;
DataRowView rRow = ((DataRowView)e.Item.DataItem);
string strSQL = "SELECT * FROM People WHERE Hotel_ID = #id";
SqlCommand cmdSQL = new SqlCommand(strSQL);
cmdSQL.Parameters.Add("#id", SqlDbType.Int).Value = rRow["ID"];
rChild.DataSource = MyRstP(cmdSQL);
rChild.DataBind();
}
}
public DataTable MyRstP(SqlCommand cmdSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (cmdSQL)
{
cmdSQL.Connection = conn;
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
and we now get this:
So, we see the 3 main records that drive the main repeater, and then we see the child records for the nested repeater.
Now, in your case, you might only ever have one child record - but it don't matter. What really matters is that you have the ability to deal with, and bind, and have separate Eval() and data for that child repeater.
I have two repeaters nested in my application which is working fine. I would love to display the footer if the child repeater is empty. Due to my code my long html, i will just drop a sample of what my html looks like and post my full code for better understanding. Everything works fine though unless when the child repeater is empty i want to display the footer message
<asp:Repeater ID="ProductRepeater" runat="server" OnItemDataBound="ProductRepeater_ItemDataBound">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<table>
<tr>
<td>
<%#Eval("Name")%>
</td>
<tr>
</table>
<pre>
<asp:Repeater ID="ChildRepeater" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<table>
<tr>
<td>
<%#Eval("Description")%>
<td>
</tr>
<table>
</itemTemplate>
<FooterTemplate>
<div>
<h5>
<asp:Label ID="lblDefaultMessage" runat="server" Text="This is empty. " Visible="false" ForeColor="Red" Font-Size="Large">
</asp:Label>
</h5>
</div>
</FooterTemplate>
</asp:Repeater>
</pre>
</ItemTemplate>
</asp:Repeater>
<protected void ProductRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
string category = "Value"
Repeater rptRelated = e.Item.FindControl("ChildRepeater") as Repeater;
rptRelated.DataSource = getChild(category);
rptRelated.DataBind();
if (rptRelated.Items.Count < 1)
{
if (e.Item.ItemType == ListItemType.Footer)
{
Label lblDefaultMessage = (Label)e.Item.FindControl("lblDefaultMessage");
lblDefaultMessage.Visible = true;
}
}
}
}
Repeater has no EmptyDataTemplate like GridView.
You should place your footer content next to Repeater and change your "databinding" code like this:
Repeater rptRelated = e.Item.FindControl("ChildRepeater") as Repeater;
Label lblDefaultMessage = (Label)e.Item.FindControl("lblDefaultMessage");
var ds = getChild(category);
lblDefaultMessage.Visible = ds != null && ds.Rows.Count != 0;
if (rptRelated != null)
{
rptRelated.DataSource = ds;
rptRelated.DataBind();
}
Find Repeater like:
// find Child Repeater
Control ctrl = (sender) as Control;
Repeater rptRelated = ctrl.Parent.NamingContainer as Repeater;
And Find control from Repeater's Footer like:
Label lblDefaultMessage =
(Label)rptRelated.Controls[rptRelated.Controls.Count-1].FindControl("lblDefaultMessage");
Add this into child Repeater's OnItemDataBound event instead of parent.
protected void ChildRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Control ctrl = (sender) as Control;
Repeater rptRelated = ctrl.Parent.NamingContainer as Repeater;
if (rptRelated.Items.Count < 1)
{
if (e.Item.ItemType == ListItemType.Footer)
{
Label lblDefaultMessage = (Label)rptRelated.Controls[rptRelated.Controls.Count-1].FindControl("lblDefaultMessage");
lblDefaultMessage.Visible = true;
}
}
}
Event is:
<asp:Repeater ID="ChildRepeater" runat="server"
OnItemDataBound="ChildRepeater_ItemDataBound">
I have create the user control and add the same in aspx code behind. I want to handle the selected index change event for dropdownlist in aspx page. Kindly help me to do this.
<div class="row">
<div class="col-lg-2">
<asp:Label ID="lbl_parent" runat="server" Text="Parent Node" CssClass="control-label"></asp:Label>
</div>
<div class="col-lg-6">
<asp:DropDownList ID="ddl_parent" runat="server" CssClass="form-control" AutoPostBack="true">
</asp:DropDownList>
</div>
</div>
phContactDetails.Controls.Add(LoadControl("~/UserControl/WUC_DisLabelControl.ascx"));
foreach (var control in phContactDetails.Controls)
{
var usercontrol = control as WUC_DisLabelControl;
DropDownList ddl_parenrt = ((DropDownList)usercontrol.FindControl("ddl_parent"));
ddl_parenrt.SelectedIndexChanged += new EventHandler(ddlparent_SelectedIndexChanged);
}
protected void ddlparent_SelectedIndexChanged(object sender, EventArgs e)
{
throw new NotImplementedException(); //Not Firing
}
You have not added SelectedIndexChanged event on dropdown.
Add SelectedIndexChanged="ddlparent_SelectedIndexChanged" on dropdown.
<asp:DropDownList ID="ddl_parent" runat="server" CssClass="form-control" AutoPostBack="true" OnSelectedIndexChanged="ddlparent_SelectedIndexChanged">
</asp:DropDownList>
I have a repeater inside another. Like so :
<asp:Repeater ID="CategoryRepeater" runat="server" OnItemDataBound="ItemBound">
<ItemTemplate>
<div class="groupbox">
<fieldset>
<legend><%# Container.DataItem %></legend>
<table>
<asp:Repeater ID="ItemRepeater" runat="server">
<ItemTemplate>
<tr>
<td>
<asp:CheckBox id="chkItem" runat="server" Text='<%# Eval("Text")%>' />
<asp:Button ID="btnXRefs" Text="x-refs" runat="server" CssClass="xRefButton" OnClick="btnSelectXRefs_Click" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
</fieldset>
</div>
</ItemTemplate>
</asp:Repeater>
CODE BEHIND :
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
using (var db = new DbContext())
{
CategoryRepeater.DataSource = db.Categories.OrderBy(x => x.Heading).Select(x => x.Heading).Distinct();
CategoryRepeater.DataBind();
}
}
}
protected void ItemBound(object sender, RepeaterItemEventArgs args)
{
if (args.Item.ItemType == ListItemType.Item)
{
Repeater childRepeater = (Repeater)args.Item.FindControl("ItemRepeater");
var item = args.Item as RepeaterItem;
using (var db = new DbContext())
{
childRepeater.DataSource = db.Categories.Where(x => x.Heading == item.DataItem).OrderBy(x => x.Text);
childRepeater.DataBind();
}
}
}
My goal is to first make many groupboxes using the top level, then bind items into each one. So I end up with many small stacked lists of checkboxes.
Problem is, all the top level boxes appear, yet only the first one contains checkbox items, ie. only the first one is bound internally, and the ItemBound method is only called once for the first one.
Any ideas why?
This line
if (args.Item.ItemType == ListItemType.Item)
Should be like this
if(args.Item.ItemType = ListItemType.Item ||
args.Item.ItemType == ListItemType.AlternatingItem)
Good day
I have a user control that contains a ListView which is being used to display tabs.
I am databinding the ListView and on the OnItemDataBound event adding the tab elements.
However the Items property never contains anything and is always empty (on PostBack and on ItemDataBound).
Markup:
<asp:ListView ID="SaleTabsListView" runat="server" OnItemDataBound="SaleTabsListView_OnItemDataBound" ItemPlaceholderID="SaleTabsPlaceHolder" EnableViewState="true">
<LayoutTemplate>
<div class="tabs">
<asp:PlaceHolder runat="server" ID="SaleTabsPlaceHolder" />
</div>
</LayoutTemplate>
<ItemTemplate>
<asp:PlaceHolder runat="server" ID="ItemPlaceHolder" />
</ItemTemplate>
</asp:ListView>
Code behind:
protected void SaleTabsListView_OnItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
var saleTab = ((ListViewDataItem)e.Item).DataItem as SalesTab;
if (saleTab != null)
{
var placeHolder = e.Item.FindControl("ItemPlaceHolder") as PlaceHolder;
var htmlAnchor = new HtmlAnchor();
htmlAnchor.Attributes.Add("id", saleTab.Id);
htmlAnchor.Attributes.Add("class", saleTab.IsCurrent ? currentTabClass : string.Empty);
var emptyLabel = new Label();
var label = new Label {Text = saleTab.Title};
label.Attributes.Add("id", saleTab.Id + "Label");
label.Attributes.Add("class", saleTab.IsComplete ? completeClass : incompleteClass);
emptyLabel.Controls.Add(label);
htmlAnchor.Controls.Add(emptyLabel);
placeHolder.Controls.Add(htmlAnchor);
}
}
}
So my question is: is the binding I'm doing somehow screwing with the Items property?
Thanks