Reputation: 53991
Within a repeater control, is there a way of de-binding certain items before the page is rendered?
Currently we have a collection of items being bound to a repeater and if the item is not part of the current language, we hide the item.
I'm wanting to be able to do a count on the repeater and get a valid number back. A count that doesn't also include the hidden items.
Is it possible to de-bind specific items perhaps in the ItemDataBound
event?
Update
For each item in the collection we're binding, we check the database during the ItemDataBound
for further information about the item, such as language etc. This is currently stopping us from filtering the bound data before binding it.
Upvotes: 7
Views: 6897
Reputation: 21
The answer is very easy you just set the Visible
property to false
on the item and it won't be rendered. In this example I'm removing items from a product list that are only available to new customers if the current user has a purchase history:
void rpt_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (!userHasPurchaseHistory) { return; }
// filter out products only allowed for new members
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
System.Data.Common.DbDataRecord rec = (System.Data.Common.DbDataRecord)e.Item.DataItem;
if (rec != null)
{
bool newMemberOnly = Convert.ToBoolean(rec["NewMemberOnly"]);
if (newMemberOnly) { e.Item.Visible = false; }
}
}
}
Note that the above is databound to an IDataReader
, you may need to cast the e.Item.DataItem
to a different object depending on what you are binding to.
Note also that I definitely would not ever do another database lookup while binding, you should never access the database in a loop but as long as the data you are binding to has something you can check to decide if you want to show it there is nothing wrong with filtering in ItemDataBound
. It could be problematic if you are doing any kind of paging since that would make inconsistent page sizes rendered.
Upvotes: 2
Reputation: 48583
I agree with the others answers - the best solution (for both performance and code clarity) is to redesign the page so that you can filter invalid entries out before databinding.
Most data sources don't allow us to remove their items while ASP.NET is iterating them. For example, if you bind to a simple generic List<T>
, and you remove an item while iterating it, the list will throw an InvalidOperationException
.
In other cases, ASP.NET actually iterates a a copy of the data source. If you bind to a DataTable
, ASP.NET uses a copy of the contents (the default DataView) rather than iterating the source rows themselves - you can remove items from the underlying data source while iterating, but it doesn't affect the databinding operation.
If filtering the items in advance really isn't an option, your current solution is fine: just hide the items! If you need to get the correct count on top of that, track the number of invalid items in your ItemDataBound handler and expose it as a page-level property:
if (IsInvalid(args.Item.DataItem)) {
this.invalidItemCount++;
// code to hide the current item
}
Upvotes: 2
Reputation: 67068
Why not filter the datasource before binding. So assuming you are using some custom objects:
myRepeater.DataSource=repository.getItems().Where(item=>item.Language==CurrentLanguage);
If you don't need them don't bind them in the first place.
Update
If it's at all possible you should probally pull that info from the DB upfront. Are these lists large? If so hitting the db once for each item in the list will show up as a performance problem.
Upvotes: 2
Reputation: 1511
A more appropriate solution could be to filter the bound collection if there is no specific need in those hidden items. Something like
items.Where(i => i.IsInLanguage(currentLanguage));
Update:
As for me I'd use this approach:
var items = db.
Where(i => i.IsInLanguage(currentLanguage)).
Where(i => i.SomeField == anotherFilterParameter);
repeater.DataSource = items;
repeater.DataBind();
So all filtering is applied beforehand
This will reduce the number of round-trips to the database as well, which plays for better performance
Upvotes: 3